django ORM模型-单表操作

 一、ORM简介

ORM ,全称Object Relational Mapping,中文叫做对象关系映射,通过ORM我们可以通过类的方式去操作数据库,而不用再写原生的SQL语句。通过把表映射成类,把行作为实例,把字段作为属性,ORM在执行对象操作的时候最终还是会把对应的操作转换为数据库原生语句。

ORM 模型一般都是放在app的models.py文件中。每个app都可以拥有自己的模型,并且如果这个模型想要映射到数据库中,那么这个 app 必须要放在项目的settings.py文件的INSTALLED_APP 中进行安装。

二、ORM创建示例

1.创建一个项目base_orm_operation,再在这个项目中创建一个book的app,并将book放在项目的settings.py文件的INSTALLED_APP 中。

2.编写book app的models.py文件,字段类型先不用过多关注,后续再学习。

from django.db import models
class Book(models.Model):#以下四行,相当于定义了一个包含4个字段的表,字段名称分别为id、name、author和price
    id=models.AutoField(primary_key=True)#int类型,主键,自增长,即使不写系统也会自动生成这样一个字段
    name=models.CharField(max_length=100,null=False)#图书名称,varchar(100),不为空
    author=models.CharField(max_length=100,null=False)#图书作者,varchar(100),不为空
    price=models.FloatField(null=False,default=0)#图书价格,float,默认为为0
    def __str__(self):#自定义返回结果样式
        return '%s,%s,%s'%(self.name,self.author,self.price)
class Publisher(models.Model):
    name=models.CharField(max_length=100,null=False)
    address=models.CharField(max_length=100,null=False)
创建Book和Publisher模型

如果要自定义表名,需要在模型定义的时候添加。 

class Book(models.Model)
    ……
    class Meta:
        db_table='book'   #定义数据库存放的表名
        verbose_name_plural = '书籍表'   #定义django admin显示的表名

3.通过cmd窗口进入项目所在路径,使用makemigrations生成迁移脚本文件,python manage.py makemigrations。注意此时settings.py的中间件没有注释'django.middleware.csrf.CsrfViewMiddleware',否则会报加密需要csrf错误。

执行后会在app的migrations目录下生成一个0001_initial.py文件,文件内容如下,这个可以不用关注,这个是django内部处理的

# Generated by Django 2.1.4 on 2018-12-20 06:38
from django.db import migrations, models
class Migration(migrations.Migration):
    initial = True
    dependencies = []
    operations = [
        migrations.CreateModel(
            name='Book',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('name', models.CharField(max_length=100)),
                ('author', models.CharField(max_length=100)),
                ('price', models.FloatField(default=0)),
            ],
        ),
        migrations.CreateModel(
            name='Publisher',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=100)),
                ('address', models.CharField(max_length=100)),
            ],
        ),
    ]
migrations目录下0001_initial.py文件

4.使用migrate将新生成的迁移脚本文件映射到数据库中,python manage.py migrate

由于是第一次执行migrate,django会将settings.py中已经安装的app模型映射到数据库中。

5.查看生成结果,在navicat的orm_intro数据库的表上右键-刷新,可看到生成了很多表。

由于在创建模型的时候没有指定表的名称,系统默认以app名称_类名称的小写  命名表,即新生成的表名为book_book,表结构如下

       

三、通过ORM操作数据库

在urls.py文件中添加映射路径

from book import views
urlpatterns = [path('', views.index),]

1.增加记录:save方法和create()方法

from .models import Book
from django.http import HttpResponse
def index(request):
    book = Book(name='西游记',author='吴承恩',price=100)
    book.save()
    #book.objects.create(name='红楼梦',author='曹雪芹',price=56) 通过模型的objects的create方法生成记录,这种方法不需要再save
    return HttpResponse("图书添加成功!")

在浏览器中输入http://127.0.0.1:8000/,显示“图书添加成功”,返回navicat刷新book_book表,可看到已经成功添加上一条数据。

可按照这个方法将四大名著的记录都添加进去,添加后如下

 

2.查询记录:所有的查询都是通过模型上的objects属性来完成的,也可以自定义查询对象。

①如果查询结果只有一条记录(即通过主键或者unique索引查询),可使用objects.get(attr=value),返回结果是一个model对象<class 'app01.models.book'>,并且只支持严格匹配。

book = Book.objects.get(pk=2)
print(book)
return HttpResponse('主键查询图书成功')

在浏览器中输入http://127.0.0.1:8000/,显示“主键查询图书成功”,并且pycharm工具显示如下

②返回一条或多条记录可使用objects.filter(attr=value),结果是一个queryset集合<class 'django.db.models.query.QuerySet'>,集合中的每一个对象为model对象,可支持关键字例如in、like查询。

book1=Book.objects.filter(author='曹雪芹')
book2=Book.objects.filter(name='西游记').first()
print(book1)
print(book2)
return HttpResponse('条件查询图书成功')

 在浏览器中输入http://127.0.0.1:8000/,显示“主键查询图书成功”,并且pycharm工具显示如下

filter查询得到的结果是一个查询集合,即使匹配到的只有一个结果也会以集合形式显示,而first()得到的只是集合中的一个结果

 ③其他常用查询套件

book3=Book.objects.all() 查询所有记录

book4=Book.objects.first() 查询第一条记录

book5=Book.objects.last() 查询最后一套记录

book6=Book.objects.all()[1:3] 查询索引下标为1至2的记录

book7=Book.objects.all().values('name','price')  取values指定的列,结果显示为字典,<QuerySet [{'name': '三国演义', 'price': 52}, {'name': '水浒传', 'price': 38}···]>

book8=Book.objects.all().values_list('name','price')  取values指定的列,结果显示为列表,<QuerySet [('三国演义', 52), ('水浒传', 38)···]>

通过filter和all取出来的结果可通过for进行循环迭代

查询记录总结:

①通过objects.filter()和objects.all() 得到的结果为QuerySet,QuerySet中的每一个值为模型对象

②通过objects.get()、Book.objects.first()、objects.last() 得到的结果为模型对象

③通过①取出再进行values()或values_list(),得到的结果为QuerySet,但QuerySet中的每一个值为字典或元组

3.修改记录

①通过对象.属性修改再调用对象.save()方法、或者QuerySet的update方法进行修改

#使用get查询的结果为模型对象,必须通过对象.属性来更新,不能使用update方法,否则会报错AttributeError: 'book' object has no attribute 'update'
book = Book.objects.get(pk=2)
book.price=45
book.save()
print(book)
return HttpResponse('图书修改成功')

#使用filter查询的结果为QuerySet,必须通过update来更新,不能使用对象.属性,否则无法更新成功,并且QuerySet没有save()方法
#update语句的返回值为受影响的行数
Book.objects.filter(name='西游记').update(price=100)

在浏览器中输入http://127.0.0.1:8000/,显示“图书修改成功”,并且pycharm工具显示如下

②两种修改方法的区别

通过对象.属性修改再调用对象.save()方法,会对查询记录的每一个字段重新赋值,而使用update方法只会修改指定的列

如果需要查看通过ORM操作模型对象的语句转换成的数据库sql,可在项目的settings文件中添加如下部分

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}
将模型操作转化为数据库sql

添加上述部分后,可在pycharm的下方输出查看到如下内容,上面一条为使用对象.save()方法进行的修改,下面一条为使用update方法进行的修改

#UPDATE `app_book` SET `name` = '红楼梦', `price` = 1, `publishdate` = '2011-12-05', `author` = '曹雪芹' WHERE `app_book`.`id` = 7; args=('红楼梦', 1, '2011-12-05', '曹雪芹', 7)
#UPDATE `app_book` SET `price` = 100 WHERE `app_book`.`id` = 7; args=(100, 7)

4.删除记录delete,删除之前也需要先查询,再删除

book=Book.objects.get(pk=2)#或者book=Book.objects.filter(pk=2)
book.delete() 
return HttpResponse('删除图书成功,请检查表中是否还有该记录')

在浏览器中输入http://127.0.0.1:8000/,显示“删除图书成功,请检查表中是否还有该记录”,到navicat中刷新表,可看到上述记录已经删除。

四、ORM常用字段类型

AutoField(Field)
        - int自增列,必须填入参数 primary_key=True

BigAutoField(AutoField)
        - bigint自增列,必须填入参数 primary_key=True

注:如果model中没有自增列,模型会自动创建一个列名为id的自增列;也可以自定义自增列。

SmallIntegerField(IntegerField):
        - 小整数 -32768 ~ 32767

PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正小整数 0 ~ 32767

IntegerField(Field)
        - 整数列(有符号的) -2147483648 ~ 2147483647

PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正整数 0 ~ 2147483647

BigIntegerField(IntegerField):
        - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807

BooleanField(Field)
        - 布尔值类型

NullBooleanField(Field):
        - 可以为空的布尔值

CharField(Field)
        - 字符类型
        - 必须提供max_length参数, max_length表示字符长度

TextField(Field)
        - 文本类型

EmailField(CharField):
        - 字符串类型,Django Admin以及ModelForm中提供验证机制

IPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
GenericIPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
        - 参数:
            protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
            unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"

URLField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证 URL

SlugField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)

CommaSeparatedIntegerField(CharField)
        - 字符串类型,格式必须为逗号分割的数字

UUIDField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

FilePathField(Field)
        - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
        - 参数:
                path,                      文件夹路径
                match=None,                正则匹配
                recursive=False,           递归下面的文件夹
                allow_files=True,          允许文件
                allow_folders=False,       允许文件夹

FileField(Field)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

ImageField(FileField)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
            width_field=None,   上传图片的高度保存的数据库字段名(字符串)
            height_field=None   上传图片的宽度保存的数据库字段名(字符串)

DateTimeField(DateField)
        - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

DateField(DateTimeCheckMixin, Field)
        - 日期格式      YYYY-MM-DD

TimeField(DateTimeCheckMixin, Field)
        - 时间格式      HH:MM[:ss[.uuuuuu]]

DurationField(Field)
        - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

FloatField(Field)
        - 浮点型

DecimalField(Field)
        - 10进制小数
        - 参数:
            max_digits,小数总长度
            decimal_places,小数位长度

BinaryField(Field)
        - 二进制类型
ORM字段
null                数据库中字段是否可以为空
db_column           数据库中字段的列名
default             数据库中字段的默认值
primary_key         数据库中字段是否为主键。加速查找,列值唯一,且不为空
unique              数据库中字段是否可以建立唯一索引。加速查找,列值唯一
db_index            数据库中字段是否可以建立索引。加速查找
unique_for_date     数据库中字段【日期】部分是否可以建立唯一索引
unique_for_month    数据库中字段【月】部分是否可以建立唯一索引
unique_for_year     数据库中字段【年】部分是否可以建立唯一索引

verbose_name        Admin中显示的字段名称
blank               Admin中是否允许用户输入为空
editable            Admin中是否可以编辑
help_text           Admin中该字段的提示信息
choices             Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
                        如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)

error_messages      自定义错误信息(字典类型),从而定制想要显示的错误信息;
                        字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
                        如:{'null': "不能为空.", 'invalid': '格式错误'}

validators          自定义错误验证(列表类型),从而定制想要的验证规则
                        from django.core.validators import RegexValidator
                        from django.core.validators import EmailValidator,URLValidator,DecimalValidator,
                        MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
                        如:
                            test = models.CharField(
                                max_length=32,
                                error_messages={
                                    'c1': '优先错信息1',
                                    'c2': '优先错信息2',
                                    'c3': '优先错信息3',
                                },
                                validators=[
                                    RegexValidator(regex='root_d+', message='错误了', code='c1'),
                                    RegexValidator(regex='root_112233d+', message='又错误了', code='c2'),
                                    EmailValidator(message='又错误了', code='c3'), ]
                            )
ORM字段的参数

在定义字段类型时,如果没有设置null=True,默认为null=False,即默认字段不为空

AutoField:必须输入参数primary_key=True,数据库层面为int 类型,自增长,如果不指定主键,模型会自动生成一个叫做 id 的自增长的主键。如果需要指定一个其他名字并且自增长的主键,也可以使用AutoField。

BigAutoField:类似AutoField,数据范围更大

BooleanField字段:模型层面值为True或False(数据库层面值为1或0,类型tinyint),并且不接受null=True,即该字段不能为空

NullBooleanField字段:值为True或False,但可以为空

CharField:模型层面为字符串,数据库层面为varchar,使用时必须指定max_length=n,如果n超过254不建议使用,以TextField代替

TextField:文本类型,数据库层面是longtext

EmailField:数据库层面为varchar,默认最大长度为254个字节,在数据库层面并不会限制字符串一定要满足邮箱格式,只是以后在使用ModelForm等表单相关操作的时候会验证邮箱格式

IntegerField:整型,值的区间是 -2147483648—2147483647 。

FloatField:浮点类型

BigIntegerField:大整型,值的区间是 -9223372036854775808—9223372036854775807

PositiveIntegerField:正整型,值的区间是 0——2147483647 。

SmallIntegerField:小整型,值的区间是 -32768——32767 。

正小整型,值的区间是 0——32767

UUIDField:只能存储 uuid 格式的字符串。 uuid 是一个32位的全球唯一的字符串,一般用来作为主键,使用ModelForm等表单相关操作的时候会验证

URLField:类似于 CharField ,只不过只能用来存储 url 格式的字符串。并且默认的 max_length 是200,使用ModelForm等表单相关操作的时候会验证是否是URL格式

更多字段及ORM操作参见http://www.cnblogs.com/wupeiqi/articles/6216618.html

status_choices = ( (1,'未处理'),(2,'处理中'),(3,'已处理') )
status = models.IntegerField(choices=status_choices,default=1),对于一条记录来说,这个字段存储的值是1、2或3

在模板页面,Model.status显示的是数据库中的数字,可通过Model.get_status_display来显示数字对应的文字。

原文地址:https://www.cnblogs.com/Forever77/p/10145782.html