DjangoORM中常见字段和参数及查询方法
Django ORM常见字段和参数
常见字段
AutoField
int自增列,必须填入参数primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。
IntegerField
一个整数类型,范围在 -2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存,)
CharField(对应的MySQL数据库中的varchar类型)
字符类型,必须提供max_length参数, max_length表示字符长度。
Django中没有设置对应的char类型的字段,但Django允许我们自定义新的字段
DateField
日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例。
DecimalField
models.DecimalField(max_digits=8,decimal_places=2),总共八位,小数点后面占两位。
DateTimeField
日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。
字段合集(争取记忆)
AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 primary_key=True 注:当model中如果没有自增列,则自动会创建一个列名为id的列 from django.db import models class UserInfo(models.Model): # 自动创建一个列名为id的且为自增的整数列 username = models.CharField(max_length=32) class Group(models.Model): # 自定义自增列 nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) 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) - 二进制类型
对应关系: 'AutoField': 'integer AUTO_INCREMENT', 'BigAutoField': 'bigint AUTO_INCREMENT', 'BinaryField': 'longblob', 'BooleanField': 'bool', 'CharField': 'varchar(%(max_length)s)', 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 'DateField': 'date', 'DateTimeField': 'datetime', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 'DurationField': 'bigint', 'FileField': 'varchar(%(max_length)s)', 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'double precision', 'IntegerField': 'integer', 'BigIntegerField': 'bigint', 'IPAddressField': 'char(15)', 'GenericIPAddressField': 'char(39)', 'NullBooleanField': 'bool', 'OneToOneField': 'integer', 'PositiveIntegerField': 'integer UNSIGNED', 'PositiveSmallIntegerField': 'smallint UNSIGNED', 'SlugField': 'varchar(%(max_length)s)', 'SmallIntegerField': 'smallint', 'TextField': 'longtext', 'TimeField': 'time', 'UUIDField': 'char(32)',
字段参数
null
用于表示某个字段可以为空
unique
如果设置为unique=True,则该字段在此表中必须是唯一的。
db_index
如果db_index=True,则代表该为该字段设置索引。
default
为该字段设置默认值
DateField和DateTimeField
auto_now_add
配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
auto_now
配置auto_now=True,每次更行数据记录的时候会更新该字段。
关系字段
ForeignKey
外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方。
ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。
to
设置要关联的表
to_field
设置要关联的表的字段
on_delete
当删除关联表中的数据时,当前表与其关联的行的行为。
models.CASCADE
删除关联数据,与之关联也删除
1、models.CASCADE 级联操作,当主表中被连接的一条数据删除时,从表中所有与之关联的数据同时被删除 2、models.SET_NULL 当主表中的一行数据删除时,从表中所有与之关联的数据的相关字段设置为null,此时注意定义外键时,这个字段必须可以允许为空 3、models.PROTECT 当主表中的一行数据删除时,由于从表中相关字段是受保护的外键,所以都不允许删除 4、models.SET_DEFAULT 当主表中的一行数据删除时,从表中所有相关的数据的关联字段设置为默认值,此时注意定义外键时,这个外键字段应该有一个默认值 5、models.SET() 当主表中的一条数据删除时,从表中所有的关联数据字段设置为SET()中设置的值,与models.SET_DEFAULT相似,只不过此时从表中的相关字段不需要设置default参数 6、models.DO_NOTHING 什么都不做,一切都看数据库级别的约束,注数据库级别的默认约束为RESTRICT,这个约束与django中的models.PROTECT相似 外键详细配置
def func(): return 10 class MyModel(models.Model): user = models.ForeignKey( to="User", to_field="id", on_delete=models.SET(func) )
OneToOneField
一对一字段。
通常一对一字段用来扩展已有字段。(通俗的说就是一个人的所有信息不是放在一张表里面的,简单的信息一张表,隐私的信息另一张表,之间通过一对一外键关联)
to
设置要关联的表。
to_field
设置要关联的字段。
on_delete
当删除关联表中的数据时,当前表与其关联的行的行为。(参考上面的例子)
在Python脚本中调用Django环境
必知必会13条
操作下面的操作之前,我们实现创建好了数据表
<1> all(): 查询所有结果
<2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
<3> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
<4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
<5> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
<6> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
<7> order_by(*field): 对查询结果排序
<8> reverse(): 对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。
<9> distinct(): 从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)
<10> count(): 返回数据库中匹配查询(QuerySet)的对象数量。
<11> first(): 返回第一条记录
<12> last(): 返回最后一条记录
<13> exists(): 如果QuerySet包含数据,就返回True,否则返回False
13个必会操作总结
返回Query Set对象的方法有
all()
filter()
exclude()
order_by()
reverse()
distinct()
特殊的QuerySet
values() 返回一个可迭代的字典序列
values_list() 返回一个可迭代的元祖序列
返回具体对象的
get()
first()
last()
返回布尔值的方法有:
exists()
返回数字的方法有
count()
Django终端打印SQL语句
如果你想知道你对数据库进行操作时,Django内部到底是怎么执行它的sql语句时可以加下面的配置来查看
在Django项目的settings.py文件中,在最后复制粘贴如下代码:
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
配置好之后,再执行任何对数据库进行操作的语句时,会自动将Django执行的sql语句打印到pycharm终端上
补充:
除了配置外,还可以通过一点.query即可查看查询语句,具体操作如下:
queryset对象才能够点击query查看内部的sql语句
基于单表的双下划线查询
# 1、年龄大于23岁的数据(大于等于,age_gte=23) # res = models.User.objects.filter(age__gt=23) # 2、年龄小于23岁的数据(小于等于,age_lte=23) # res = models.User.objects.filter(age__lt=23) # 3、年龄是18或者20或者35 # res = models.User.objects.filter(age__in=[18,20,35]) # 4、年龄在18到24岁之间的 首尾都要 # res = models.User.objects.filter(age__range=[18,24]) # 5、查询出名字里面含有 y 的数据 模糊查询(区分大小写) # res = models.User.objects.filter(name__contains='y') # 6、查询出名字里面含有 G 的数据 忽略大小写 # res = models.User.objects.filter(name__icontains='G') # 7、查询出名字以 j 开头的数据 # res = models.User.objects.filter(name__startswith='j') # 8、查询出名字以 g 结尾的数据 # res = models.User.objects.filter(name__endswith='g') # 9、查询出时间为2004年1月份的数据 # res = models.User.objects.filter(chinatime__year='2004',chinatime__month='1')
多表查询
正反向的概念
# 正向 # 反向 外键字段在我手上那么,我查你就是正向 外键字段如果不在手上,我查你就是反向 book >>>外键字段在书那儿(正向)>>> publish publish >>>外键字段在书那儿(反向)>>>book 一对一和多对多正反向的判断也是如此 """ 正向查询按字段 反向查询按表名小写 字段_set """
子查询(基于对象的跨表查询)
# 当查看的是属于多的一方的时候需要.属性.all()的返回结果是一个列表套对象的数据(<QuerySet [<Author: Author object (2)>]>),需要.first()拿到对象之后在.属性
models.Book.objects.filter(pk=1).first().author.all().first().name
# 当查看的是属于一的一方的时候则不需要.first(),直接可以.属性
models.Book.objects.filter(pk=1).first().publish.name
# 1.查询书籍主键为1的出版社 # book_obj = models.Book.objects.filter(pk=1).first() # # 书查出版社 正向 # res = book_obj.publish # print(res) # print(res.name) # print(res.addr) # 2.查询书籍主键为2的作者 # book_obj = models.Book.objects.filter(pk=2).first() # # 书查作者 正向 # # res = book_obj.authors # app01.Author.None # res = book_obj.authors.all() # <QuerySet [<Author: Author object>, <Author: Author object>]> # print(res) # 3.查询作者jiang的电话号码 # author_obj = models.Author.objects.filter(name='jiang').first() # res = author_obj.author_detail # print(res) # print(res.phone) # print(res.addr) """ 在书写orm语句的时候跟写sql语句一样的 不要企图一次性将orm语句写完 如果比较复杂 就写一点看一点 正向什么时候需要加.all() 当你的结果可能有多个的时候就需要加.all() 如果是一个则直接拿到数据对象 book_obj.publish book_obj.authors.all() author_obj.author_detail """ # 4.查询出版社是北方出版社出版的书 # publish_obj = models.Publish.objects.filter(name='北方出版社').first() # 出版社查书 反向 # res = publish_obj.book_set # app01.Book.None # res = publish_obj.book_set.all() # print(res) # 5.查询作者是jiang写过的书 # author_obj = models.Author.objects.filter(name='jiang').first() # 作者查书 反向 # res = author_obj.book_set # app01.Book.None # res = author_obj.book_set.all() # print(res) # 6.查询手机号是123的作者姓名 # author_detail_obj = models.AuthorDetail.objects.filter(phone=123).first() # res = author_detail_obj.author # print(res.name) """ 基于对象 反向查询的时候 当你的查询结果可以有多个的时候 就必须加_set.all() 当你的结果只有一个的时候 不需要加_set.all() 自己总结出 自己方便记忆的即可 每个人都可以不一样 """
连表查询(基于双下划线的跨表查询)
# 1.查询jiang的手机号和作者姓名 # res = models.Author.objects.filter(name='jiang').values('author_detail__phone','name') # print(res) # 反向 # res = models.AuthorDetail.objects.filter(author__name='jiang') # 拿作者姓名是jason的作者详情 # res = models.AuthorDetail.objects.filter(author__name='jiang').values('phone','author__name') # print(res) # 2.查询书籍主键为1的出版社名称和书的名称 # res = models.Book.objects.filter(pk=1).values('title','publish__name') # print(res) # 反向 # res = models.Publish.objects.filter(book__id=1).values('name','book__title') # print(res) # 3.查询书籍主键为1的作者姓名 # res = models.Book.objects.filter(pk=1).values('authors__name') # print(res) # 反向 # res = models.Author.objects.filter(book__id=1).values('name') # print(res) # 4.查询书籍主键是1的作者的手机号 # book author authordetail # res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone') # print(res) """ 你只要掌握了正反向的概念 以及双下划线 那么你就可以无限制的跨表 """
聚合查询
# 聚合查询 aggregate """ 聚合查询通常情况下都是配合分组一起使用的 只要是跟数据库相关的模块 基本上都在django.db.models里面 如果上述没有那么应该在django.db里面 """ from app01 import models from django.db.models import Max,Min,Sum,Count,Avg # 1 所有书的平均价格 # res = models.Book.objects.aggregate(Avg('price')) # print(res) # 2.上述方法一次性使用 res = models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Count('pk'),Avg('price')) print(res)
分组查询
# 分组查询 annotate """ MySQL分组查询都有哪些特点 分组之后默认只能获取到分组的依据 组内其他字段都无法直接获取了 严格模式 ONLY_FULL_GROUP_BY """ from django.db.models import Max, Min, Sum, Count, Avg # 1.统计每一本书的作者个数 # res = models.Book.objects.annotate() # models后面点什么 就是按什么分组 # res = models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num') """ author_num是我们自己定义的字段 用来存储统计出来的每本书对应的作者个数 """ # res1 = models.Book.objects.annotate(author_num=Count('authors__id')).values('title','author_num') # print(res,res1) """ 代码没有补全 不要怕 正常写 补全给你是pycharm给你的 到后面在服务器上直接书写代码 什么补全都没有 颜色提示也没有 """ # 2.统计每个出版社卖的最便宜的书的价格(作业:复习原生SQL语句 写出来) # res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price') # print(res) # 3.统计不止一个作者的图书 # 1.先按照图书分组 求每一本书对应的作者个数 # 2.过滤出不止一个作者的图书 # res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title','author_num') # """ # 只要你的orm语句得出的结果还是一个queryset对象 # 那么它就可以继续无限制的点queryset对象封装的方法 # # """ # print(res) # 4.查询每个作者出的书的总价格 # res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price') # print(res) """ 如果我想按照指定的字段分组该如何处理呢? models.Book.objects.values('price').annotate() 后续BBS作业会使用 你们的机器上如果出现分组查询报错的情况 你需要修改数据库严格模式 """
F与Q查询
# F查询 # 1.查询卖出数大于库存数的书籍 # F查询 """ 能够帮助你直接获取到表中某个字段对应的数据 """ from django.db.models import F # res = models.Book.objects.filter(maichu__gt=F('kucun')) # print(res) # 2.将所有书籍的价格提升500块 # models.Book.objects.update(price=F('price') + 500) # 3.将所有书的名称后面加上爆款两个字 """ 在操作字符类型的数据的时候 F不能够直接做到字符串的拼接 """ from django.db.models.functions import Concat from django.db.models import Value models.Book.objects.update(title=Concat(F('title'), Value('爆款'))) # models.Book.objects.update(title=F('title') + '爆款') # 所有的名称会全部变成空白
# Q查询 # 1.查询卖出数大于100或者价格小于600的书籍 # res = models.Book.objects.filter(maichu__gt=100,price__lt=600) """filter括号内多个参数是and关系""" from django.db.models import Q # res = models.Book.objects.filter(Q(maichu__gt=100),Q(price__lt=600)) # Q包裹逗号分割 还是and关系 # res = models.Book.objects.filter(Q(maichu__gt=100)|Q(price__lt=600)) # | or关系 # res = models.Book.objects.filter(~Q(maichu__gt=100)|Q(price__lt=600)) # ~ not关系 # print(res) # <QuerySet []> # Q的高阶用法 能够将查询条件的左边也变成字符串的形式 q = Q() q.connector = 'or' q.children.append(('maichu__gt',100)) q.children.append(('price__lt',600)) res = models.Book.objects.filter(q) # 默认还是and关系 print(res)
图书管理系统