【ORM】django项目中orm的一些使用

阅读: 评论:0

【ORM】django项目中orm的一些使用

【ORM】django项目中orm的一些使用

常用字段类型

CharField(Field)

字符类型. 必须指定max_length参数,max_length表示字符长度

AutoField(Field)

必须指定参数primary_key=True指定主键. 如果没有设置主键, 默认创建并以id名作为主键

IntegerField(Field)

整数类型(有符号) -2147483648 ~ 2147483647

DecimalField(Field)

十进制小数

参数:
max_digits:数据总长度
decimal_places:小数位长度

EmailField(CharField)

带邮箱正则验证,自动判断邮箱的格式

DateField(DateTimeCheckMixin, Field)

日期字段. 格式: YYYY-MM-DD. 一般指定参数auto_now=Ture更新记录的时间, 或者auto_now_add=True插入记录的时间

DateTimeField(DateField)

日期字段. 格式: YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] 一般指定参数auto_now=Ture更新记录的时间, 或者auto_now_add=True插入记录的时间|

TextField(Field)

大量文本类型,超过254字符时替代CharField

BooleanField(Field)

布尔型、判断状态时使用,True/False,比如是否删除

FloatField(Field)

浮点数

SmallIntegerField(IntegerField)

小整型 -32768 ~ 32767

URLField(CharField)

字符串类型,为Django Admin以及ModelForm中提供验证URL

SlugField(CharField)

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

UUIDField(Field)

字符串类型,为Django Admin以及ModelForm中提供对UUID格式的验证

ImageField(FileField)

字符串,路径保存在数据库,文件上传到指定目录

参数:
upload_to=" ":上传文件的保存路径
storage=None:存储组件,默认files.storage.FileSystemStorage
width_field=None:上传图片的高度保存的数据库字段名(字符串)
height_field=None:上传图片的宽度保存的数据库字段名(字符串)

FileField(Field)

字符串类型,路径保存在数据库,文件上传到指定目录

参数:
upload_to=" ":上传文件的保存路径
storage=None:储存组件,默认files.storage.FileSystemStorage

FilePathField(Field)

字符串类型,为Django Admin以及ModelForm中提供读取文件夹下文件的功能

参数:
path:文件夹路径
match=None:正则匹配
recursive=False:递归下面的文件夹
allow_files=True:允许文件
allow_folders=False:允许文件夹

Field的常用参数

  • id:默认会自动创建一个 id 主键(自增、非空)
  • primary_key = True:是否为主键,与AutoField/BigAutoField连用,一个数据库模型只允许设置一个,一旦某个字段设置了,那么 orm 框架就不会自动创建 id 主键。
  • verbose_name:指定中文的描述,在 admin 后台站点以及在接口文档平台中会使用到
  • help_text:指定中文的描述,在 admin 后台站点以及在接口文档平台中会使用到
  • unique = True:设置唯一性约束,在数据库中就是唯一约束
  • null = True:数据库中可以为null
  • blank = True:前端可以不填,标识这个字段在表单验证的时候是否可以为空,默认是False。这个和null是有区别的,null是一个纯数据库级别的。而blank是表单验证级别的。
  • default = ‘’:设置默认值
  • choices = ‘’:在一个范围内选择出一项,它是一个可迭代对象,即列表或者元组,其中每一个元素都是一个二元组(a,b)的形式,a 是用来选择的对象,b 是对 a 的描述信息。
 sex = models.IntegerField(choices=[(0, '女'), (1, '男'), ], default=1)
  • error_messages: 自定义错误信息(字典类型),从而定制想要显示的错误信息,字典的键是参数名,如:unique,invalid,invalid_choice等,字典的值是如果违反了相对应的规则而提示的错误信息,如:
error_messages={'unique': '输入内容已存在','invalid': '输入格式错误',
}
  • blank=True, null=True:定义该字段的时候,允许为空
  • SET(): 自定义一个值,该值当然只能是对应的实体了
  • ordering:指定表的默认排序规则
  • related_name:指定父表获取子表信息时的字段名称
  • db_index:是否为该字段建立索引,这种索引只是单纯的加快查找速度,并无其他作用
  • db_column:这个字段在数据库中的名字。如果没有设置这个参数,那么将会使用模型中属性的名字。
  • auto_now_add = True:自动添加创建时间,创建这条记录时的时间
  • auto_now = True:自动添加更新时间,对这条记录内容更新时的时间
  • validators:自定义验证规则(列表类型),如:
validators import validators import EmailValidator,URLValidator,DecimalValidator,MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidatorname = models.CharField(max_length=32,validators=[RegexValidator(r'root_d+', message='错了',  code="c1"),RegexValidator(r'root_11111d+', message="又错了", code='c2'),EmailValidator(message='还是错了', code='c3'), ],error_messages={'c1': '错误信息1','c2': '错误信息2','c3': '错误信息3',}
)

blank和null的区别

  • blank
    设置为True时,字段可以为空。设置为False时,字段是必须填写的。字符型字段CharField和TextField是用空字符串来存储空值的。

  • null
    设置为True时,django用Null来存储空值。日期型、时间型和数字型字段不接受空字符串。所以设置IntegerField,DateTimeField型字段可以为空时,需要将blank,null均设为True。如果为True,空值将会被存储为NULL,默认为False。

如果想设置BooleanField为空时可以选用NullBooleanField型字段。

一句话概括,null 是针对数据库而言,如果 null=True, 表示数据库的该字段可以为空。blank 是针对表单的,如果 blank=True,表示你的表单填写该字段的时候可以不填

null和空字符串的区别

一、空值(null)和空字符串(’’)

空值也就是在字段中存储NULL值,空字符串就是字段中存储空字符(’’)。

二、区别

2.1占用空间区别

空字符串(’’)的长度是0,是不占用空间的;而的NULL的长度是NULL,其实它是占用空间的。

2.2插入/查询方式区别

NULL值查询使用is null/is not null查询,而空字符串(’’)可以使用=或者!=、<、>等算术运算符。

2.3COUNT 和 IFNULL函数

使用 COUNT(字段) 统计会过滤掉 NULL 值,但是不会过滤掉空字符串。

关系型字段

区分一对一、一对多、多对多

一对一: 一般用于某张表的补充,比如员工表(包含姓名、性别、年龄、电话等),每个员工还有张用户表(包含关联员工表、用户名、密码、角色),一对一关联

一对多: 是最常见的一种设计。就是 A 表的一条记录,对应 B 表的多条记录,且 A 的主键作为 B 表的外键。这主要看以哪张表为中心,以上示例以 A 表为中心,就是一对多,如果以 B 表为中心,则是多对一。举几个例子:

  1. 班级表 与 学生表,一个班级对应多个学生,或者多个学生对应一个班级。
  2. 角色表 与 用户表,一个角色对应多个用户,或者多个用户对应一个角色。
  3. 商品表 与 图片表,一个商品对应多张图片,或者多张图片对应一个商品。

多对多: 在数据库中也比较常见,可以理解为是一对多和多对一的组合。要实现多对多,一般都需要有一张中间表(也叫关联表),将两张表进行关联,形成多对多的形式

  • ForeiginKey一对多
# 一对多,外键字段推荐建在一对多中多的一方
# Student表和 Grade 表是一对多的关系, Student 表是多,在多的一方创建外键     一个班级对应多个学生
grade = models.ForeignKey(to='Grade', on_delete=models.SET_NULL, null=True)

参数

  • to:设置要关联的表,即想与哪张表进行关联
  • to_field:指定要与关联的表中的哪一个字段进行关联,默认是和主键关联
  • related_query_name:反向查询操作时,使用的连接前缀,用于替换表名。
  • related_name:反向操作时,使用的字段名,用于代替原反向查询时的“表名_set”
    例如:
class Student(models.Model):name = models.CharField(max_length=32)class = models.ForeignKey(to="Classes")class Classes(models.Model):name = models.CharField(max_length=32)

查询某个班级关联的所有学生(反向查询)

models.Classes.objects.first().student_set.all()

在ForeignKey字段中添加了参数 related_name

class Student(models.Model):name = models.CharField(max_length=32)class = models.ForeignKey(to="Classes", related_name="students")

查询某个班级关联的所有学生(反向查询)

models.Classes.objects.first().students.all()
  • db_constraint:是否在数据库中创建外键约束,本来当ForeignKey关联了某张表后,那么外键就只能是那张表的id中出现的值了,但是如果设置了db_constraint为True后就可以将外键设置成关联表id以外的值了,关联表将对该表没有任何约束

必须指定one_delete级联删除策略

  • on_delete = models.CASCADE:当父表数据删除之后,对应的从表数据会被自动删除
  • on_delete = models.SET_NULL:当父表删除之后,对应的从表数据的外键字段会被自动设置为null,前提是外键允许为空
  • on_delete =SET_DEFAULT: 当父表删除时,对应的从表数据的外键字段会被自动设置为default参数指定的默认值,前提是外键设置了default参数
  • on_delete = models.RESTRICT:当父表删除时,对应的从表数据的外键字段会被自动设置为default参数指定的默认值
  • on_delete = models.PROTECT:当父表删除时,如果存在对应的从表数据,那么会抛出异常
  • on_delete = models.SET:删除关联数据,
    a.将与之关联的记录的外键设置成指定值,models.SET(‘指定值’)
    b. 将与之关联的记录的外键设置成指定可执行对象的返回值,即如下所示:
def func():return 10class MyModels(models.Model)fk = models.ForeignKey(to='User', to_field='id', on_delete=models.SET(func(), ))
models.SET
  • OneToOneField一对一
# 建议外键字段建立在查询频率较高的一方
# Student 和 StudentDetail 表是一对一的关系,在父表中创建,一个学生有一条详情
detail = models.OneToOneField(to='StudentDetail', on_delete=models.CASCADE)
  • to:设置要关联的表,即想与哪张表进行关联

  • to_field:指定要与关联的表中的哪一个字段进行关联,默认是和主键关联

  • one_delete:同上

  • ManyToManyField多对多

# 建议外键字段推荐建在查询频率较高的一方,且无需手动创建中间表,models会自动帮你创建一张虚拟表
# Course 和 Student 表是多对多的关系,一个课程可以有多个学生报,一个学生也可以报多个课程,在那边设置都可以
students = models.ManyToManyField(to='Student', through='Enroll')
  • to:设置要关联的表,即想与哪张表进行关联
  • to_field:指定要与关联的表中的哪一个字段进行关联,默认是和主键关联
  • related_query_name:反向查询操作时,使用的连接前缀,用于替换表名。
  • related_name :反向操作时,使用的字段名,用于代替原反向查询时的“表名_set”
  • symmetrical :仅用于多对多自关联时,指定内部是否创建反向操作的字段。默认为True。
  • through:在使用ManyToManyField字段时,Django将自动生成一张表来管理多对多的关联关系。但我们也可以手动创建第三张表来管理多对多关系,此时就需要通过through来指定第三张表的表名。自定义第三张表时,第三张表的表名
  • through_fields:自定义第三张表时,第三张表中可能有很多字段与多对多的两张表进行外键关联,使用through_fields可以指定那两个字段为联系两张表的外键 through_fields=('group', 'person')
  • db_table:默认创建第三张表时,数据库中表的名称。
  • db_constraint:是否在数据库中创建外键约束,与一对多的db_constraint一致

多对多关联关系的三种方式

  1. 方式一:自行创建第三张表
class Book(models.Model):title = models.CharField(max_length=32, verbose_name="书名")class Author(models.Model):name = models.CharField(max_length=32, verbose_name="作者姓名")# 自己创建第三张表,分别通过外键关联书和作者
class Author2Book(models.Model):author = models.ForeignKey(to="Author",on_delete=models.CASCADE)book = models.ForeignKey(to="Book",on_delete=models.CASCADE)class Meta:unique_together = ("author", "book")
  1. 方式二:通过ManyToManyField自动创建第三张表
class Book(models.Model):title = models.CharField(max_length=32, verbose_name="书名")# 通过ORM自带的ManyToManyField自动创建第三张表
class Author(models.Model):name = models.CharField(max_length=32, verbose_name="作者姓名")books = models.ManyToManyField(to="Book", related_name="authors")
  1. 方式三:设置ManyTomanyField并指定自行创建的第三张表
class Book(models.Model):title = models.CharField(max_length=32, verbose_name="书名")# 自己创建第三张表,并通过ManyToManyField指定关联,
class Author(models.Model):name = models.CharField(max_length=32, verbose_name="作者姓名")books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book"))# through_fields接受一个2元组('field1','field2'):# 其中field1是定义ManyToManyField的模型外键的名(author),field2是关联目标模型(book)的外键名。class Author2Book(models.Model):author = models.ForeignKey(to="Author")book = models.ForeignKey(to="Book")class Meta:unique_together = ("author", "book")


注意:

当我们需要在第三张关系表中存储额外的字段时,就要使用第三种方式。

但是当我们使用第三种方式创建多对多关联关系时,就无法使用set、add、remove、clear方法来管理多对多的关系了,需要通过第三张表的model来管理多对多关系。

元信息

class Meta:# 如果 abstract = True, 就表示模型是 抽象基类abstract = True#app_label声明属于哪个应用app_label='Students'#table_name自定义表名、如果没有指定表名会是:应用名_类名db_table='Students'#有些数据库有数据库表空间,比如Oracle。你可以通过db_tablespace来指定这个模型对应的数据库表放在哪个数据库表空间。db_tablespace = "user"#个 DateField 或 DateTimeField 字段的名字. 若提供该选项, 该模块将拥有一个 get_latest() 函数以得到 "最新的" 对象(依据那个字段): 得到最近一		条order_date字段记录、get_latest_by = "order_date"   #给这个模型取一个更简单、好读的名字verbose_name = "pizza"        #如果将上面的verbose_name跟verbose_name_plural设置成同样的值,就不会再admin中显示sverbose_name_plural = verbose_name# 联合索引: 索引的一个主要目的就是加快检索表中数据index_together=("grade","user")# 联合约束: 两个字段全部重复才算重复unique_together = ("grade","user")# 指定默认按什么字段排序,只有设置了该属性,我们查询到的结果才可以被reverse()。ordering="grade"

Django项目使用MySQL数据库

在Django项目的settings.py文件中,配置数据库连接信息:

DATABASES = {"default": {"ENGINE": "django.sql","NAME": "你的数据库名称",  # 需要自己手动创建数据库"USER": "数据库用户名","PASSWORD": "数据库密码","HOST": "数据库IP","POST": "数据库端口"}
}

在Django项目的__init__.py文件中写如下代码,告诉Django使用pymysql模块连接MySQL数据库:

import pymysqlpymysql.install_as_MySQLdb()

Django测试环境搭建

只需要测试Django项目中某个py文件的内容,可以不必通过前端,单独进行测试即可

  • 使用脚本形式:任意创建一个 py 文件(或者直接在test.py中), 在该文件内书写固定的配置(可以去manage.py文件中去复制前四行)
# 测试环境的准备 去manage.py中拷贝前四行代码 然后自己写两行
import osif __name__ == "__main__":os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django.settings.dev')import djangodjango.setup()# 在这个代码块的下面就可以测试django里面的单个py文件了(注意: 导模块也要写在这下面)# 可以使用原生sql的查询方式from django.db import connectioncursor = connection.cursor()ute('select name from students_student')print(cursor.fetchall())

ORM常用关键字

1.create()

创建数据并直接获取当前创建的数据对象

# 创建方式一:
res = ate(num='1',college='第一小学')
# 创建方式二:
res = StudentDetail(num='2',college='第一小学')
res.save()

2.all()

查询所有数据,结果是QuerySet [数据对象1,数据对象2]

res = Student.objects.all()

3.filter()

根据条件筛选数据,结果是QuerySet [数据对象1,数据对象2]

res = Student.objects.filter() # 和all()一样
res1 = Student.objects.filter(name='娜美',age=18) # and的关系

4.first()、last()

QuerySet支持索引取值但是只支持正数 并且orm不建议你使用索引

res = Student.objects.filter(age=18).first() # 取queryset里的第一个数据,数据不存在不会报错而是返回None
res1 = Student.objects.filter().last() # 取queryset里的最后一个数据,数据不存在不会报错而是返回None

5.update()

更新数据(支持批量更新)

Student.objects.filter(name='路飞').update(name='lufei') # 单个更新
Student.objects.filter().update(sex=2) # 批量更新

6.delete()

删除数据(支持批量删除)

Student.objects.filter().delete() # 批量删除
Student.objects.filter(id=1).delete() # 单个删除

7.values()

根据指定字段获取数据,结果是QuerySet [{},{},{},{}]

res = Student.objects.filter().values() # 表里的所有字段
res1 = Student.objects.values() # 同上
res2 = Student.objects.all().values('name') # 表里的name字段 <QuerySet [{'name': 'lufei'}, {'name': '娜美'}, {'name': '山治'}]>
res3 = Student.objects.filter().values('name','age') # 同上

8.values_list()

根据指定字段获取数据,结果是QuerySet [(),(),(),()]

res4 = Student.objects.all().values_list('name','age') # 只有字段的值 <QuerySet [('lufei', 18), ('娜美', 18), ('山治', 18), ('索隆', 18)]>

9.distinct()

去重(数据一定要一模一样才可以,如果有主键肯定不行)

res = Student.objects.values('name','age').distinct()

10.order_by()

根据指定条件排序,默认是升序,字段前面加负号就是降序

res = Student.objects.all().order_by('-id')

11.get()

根据条件筛选数据并直接获取到数据对象 一旦条件不存在会直接报错 不建议使用

res = (id=11) #lufei-18  数据不存在会报错,不建议使用

12.exclude()

排除

res = lude(id=1) # 查询出除了id=1的其他的数据

13.count()

统计结果集中数据的个数

res = Student.objects.all().count()

14.exists()

判断结果集中是否含有数据 如果有则返回True 没有则返回False

res = Student.objects.filter(id=11).exists()  # False

15.及时查看sql语句

res = Student.objects.all()
print(res.query)

双下划线查询

只要还是queryset对象就可以无限制的点queryset对象的方法
queryset.filter().values().filter().values_list().filter()…

参数释义例子说明
__in是否在给定的数据集中res=Student.objects.filter(age__in=(18,28,38))查询年龄是18或28或38的数据
__gt大于res=Student.objects.filter(age__gt=18)查询年龄大于18的数据
__lt小于res=Student.objects.filter(age__lt=18)查询年龄小于18的数据
__gte大于等于res=Student.objects.filter(age__gte=18)查询年龄大于等于18的数据
__lte小于等于res=Student.objects.filter(age__lte=18)查询年龄小于等于18的数据
__range在…之间, 闭区间res=Student.objects.filter(age__range=(18,38))查询年龄范围在18到38之间的数据
__contains包含res=Student.objects.filter(name__contains=‘y’)查询姓名包含字母y的数据,区分大小写
__icontains包含(忽略大小写)res=Student.objects.filter(name__contains=‘y’)查询姓名包含字母y的数据,不区分大小写
__startwith以…开头res=Student.objects.filter(name__startswith=‘lu’)查询姓名以lu开头的数据
__endwith以…结尾res=Student.objects.filter(name__endwith=‘mei’)查询姓名以mei结尾的数据
__year取出年份(仅限于时间类型)res = Student.objects.filter(c_time__year=2023)查询创建时间是2023年的数据
__month取出月份(仅限于时间类型)用法同上
__day取出日期(仅限于时间类型)用法同上
__hour取出小时(仅限于时间类型)用法同上
__minute取出分钟(仅限于时间类型)用法同上
__second取出秒(仅限于时间类型)用法同上

创建表

from django.db import modelsclass Book(models.Model):"""图书表"""title = models.CharField(verbose_name='书名',max_length=32)price = models.DecimalField(verbose_name='价格',max_digits=8, decimal_places=2)publish_time = models.DecimalField(verbose_name='出版日期',auto_now_add=True)# 创建书籍与出版社的一对多外键字段,一个出版社对应多个书籍,书籍是多的一方,在多的一方设外键"""on_delete=models.CASECADE 设置级联级联删除,在publish删除出版社后,出版社所关联的书籍也会被删掉(在没有publish_id的那一方删除)"""publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)# 创建书籍与作者的多对多外键字段,authors = models.ManyToManyField(to='Author')class Publish(models.Model):"""出版社表"""name = models.CharField(verbose_name='名称',max_length=32)address = models.CharField(verbose_name='地址',max_length=64)class Author(models.Model):"""作者表"""name = models.CharField(verbose_name='姓名',max_length=32)age = models.IntegerField(verbose_name='年龄') # 创建作者与作者详情表之间一对一外键字段"""on_delete=models.CASECADE,在AuthorDetail表删除author表关联的数据时,author表的数据也会被删掉(在没有author_detail_id的那一方删除)"""author_detail = models.OneToOneField(to='AuthorDetail',on_delete=models.CASCADE)class AuthorDetail(models.Model):"""作者详情表"""phone = models.BigIntegerField(verbose_name='手机号')address = models.CharField(verbose_name='家庭住址',max_length=64)

数据库迁移

python manage.py makemigrations books
python manage.py migrate books






通过ORM创建书籍表

import osdef main():os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django.settings.dev')import djangodjango.setup()from books import models"""创建数据的两种方式"""# 方式1:外键字段绑定要关联的id,注意外键字段之后拼接"_id"models.ate(title='三国演义',price=88.88,publish_id=1)models.ate(title='红楼梦', price=66.66, publish_id=2)models.ate(title='西游记', price=99.99, publish_id=1)# 方式2:先获取关联表中要绑定的对象,外键字段直接绑定该对象publish_obj = models.Publish.objects.filter(pk=3).first()models.ate(title='水浒传', price=77.77, publish=publish_obj)main()

针对多对多关系的增、删、改、查

增加绑定关系:

add() 括号里面可以是一个或多个位置参数,支持数字和对象

"""针对多对多关系绑定的两种方式"""# 方式1:直接添加关系表中的id值book_obj1 = models.Book.objects.filter(pk=1).first() # 在book表查出要绑定的数据book_obj1.authors.add(1)    # 在第三张关系表中 book_author 中给当前书籍绑定作者,(id=1)book_obj1.authors.add(2,3)    # 支持一次性绑定多个# 方式2:先获取关联表中要绑定的数据对象,添加该对象book_obj2 = models.Book.objects.filter(pk=3).first()author_obj1 = models.Author.objects.filter(pk=2).first()   # 获取作者对象2author_obj2 = models.Author.objects.filter(pk=3).first()    # 获取作者对象3book_obj2.authors.add(author_obj1,author_obj2)    # 绑定上述两个作者对象

删除绑定关系:

remove() 括号里面可以是一个或多个位置参数,支持数字和对象

"""删除绑定关系"""# 方式1:book_ve(1)    # 删除书籍对象book_obj1绑定的作者id值为1的关系book_ve(2,3)  # 支持一次性删除多个# 方式2:book_ve(author_obj1,author_obj2)  # 删除书籍对象book_obj2绑定的两个作者对象

修改绑定关系:

set() 注意括号里面为可迭代对象(元组 列表),支持数字和对象

# 方式1:book_obj1.authors.set((4,))     # 本来是1对应1,修改后是1对应4,没有4的话不修改book_obj1.authors.set([4])book_obj1.authors.set((5,6))    # 本来是1对应1,修改后是1对应5,1对应6没有的话不修改book_obj1.authors.set([5, 6])# 方式2:book_obj2.authors.set((author_obj1,))book_obj2.authors.set((author_obj1, author_obj2))

清除绑定关系:

clear()

book_obj1.authors.clear()  # 清空book_obj1绑定的作者

ORM查询

正反向查询的概念

# 正向查询按外键字段,反向查询按表名小写# 一对一# 正向:author---关联字段在author表里--->authordetail        按字段# 反向:authordetail---关联字段在author表里--->author        按表名小写# 一对多# 正向:book---关联字段在book表里--->publish        按字段# 反向:publish---关联字段在book表里--->book        按表名小写_set.all() 因为一个出版社对应着多个图书# 多对多# 正向:book---关联字段在book表里--->author        按字段# 反向:author---关联字段在book表里--->book        按表名小写_set.all() 因为一个作者对应着多个图书

书籍与作者, 外键字段在书籍 book
作者与作者详情, 外键字段在作者 author
书籍与出版社外键字段在书籍 book

基于对象的跨表查询

正向

1.查询主键为1的书籍对应的出版社名称

# 先根据条件获取数据对象
book_obj = models.Book.objects.filter(pk=1).first()
# 再判断正反向的概念  由书查出版社 外键字段在书所在的表中 所以是正向查询
print(book_obj.publish.name)

2.查询主键为3的书籍对应的作者姓名

# 先根据条件获取数据对象
book_obj = models.Book.objects.filter(pk=3).first()
# 再判断正反向的概念  由书查作者 外键字段在书所在的表中 所以是正向查询 多对多关系
print(book_obj.authors)  
print(book_obj.authors.all())
print(book_obj.authors.all().values('name'))

3.查询lufei的电话号码

# 根据作者查作者详情,外键字段在作者表,author和author_detail是一对一关系
author_obj = models.Author.objects.filter(name='lufei').first()
print(author_obj.author_detail.phone)
反向

4.查询朵朵出版社出版过的书籍

# 根据出版社查询对应的书籍,外键字段在书籍
publish_obj = models.Publish.objects.filter(name='朵朵出版社').first()
print(publish_obj.book_set)  
print(publish_obj.book_set.all())
print(publish_obj.book_set.all().values('title'))

5.查询lufei写过的书籍

# 根据作者查书籍,外键字段在书籍,多对多关系
author_obj = models.Author.objects.filter(name='lufei').first()
print(author_obj.book_set) 
print(author_obj.book_set.all())
print(author_obj.book_set.all().values('title'))

6.查询电话号码是110的作者姓名

# 根据作者详情查作者,外键字段在作者author表,用表名小写
author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
print(author_detail_obj.author)
print(author_detail_obj.author.name)

基于双下划线的跨表查询

正向

1.查询主键为1的书籍对应的出版社名称

 # 根据书籍查出版社,正向查询,按照书籍表中外键字段publish查询,__name获取出版社名字res = models.Book.objects.filter(pk=1).values('publish__name')

2.查询主键为3的书籍对应的作者姓名

# 根据书籍查询作者,正向查询,按照书籍表中外键字段authors查询,__name获取作者姓名
res = models.Book.objects.filter(pk=3).values('authors__name')

3.查询lufei的电话号码

# 根据作者查作者详情,正向查询,按照作者表中外键字段author_detail查询,__phone获取电话
res = models.Author.objects.filter(name='lufei').values('author_detail__phone')
反向

4.查询北方出版社出版过的书籍名称和价格

# 根据出版社查书籍,反向查询,按照被查表表名小写book查询,__XX获取相应的信息
res = models.Publish.objects.filter(name='北方出版社').values('book__title','book__price')

5.查询lufei写过的书籍

# 根据作者查书籍,反向查询,按照被查表表名小写book查询,__XX获取相应的信息
res = models.Author.objects.filter(name='lufei').values('book__title')

6.查询电话号码是110的作者姓名

# 根据作者详情查作者,反向查询,按照被查表表名小写author查询,__XX获取相应的信息
res = models.AuthorDetail.objects.filter(phone=110).values('author__name')

进阶操作

1.查询主键为1的书籍对应的出版社名称

# 根据书籍查出版社,正向查询,主键在书籍表中,从出版社查询为反向,按照正向的书籍表表名小写book查询,条件写在filter()括号中,values()括号中直接填写需要的键值'name'
res = models.Publish.objects.filter(book__pk=1).values('name') 

2.查询主键为3的书籍对应的作者姓名

#根据书籍查作者,正向查询 主键在书籍表中,从作者查询为反向,按照正向的书籍表表名小写book查询,条件写在filter()括号中,values()括号中直接填写需要的键值'name'
res = models.Author.objects.filter(book__pk=3).values('name')

3.查询lufei的电话号码

# 根据作者查作者详情,正向查询,主键在作者表中,从电话号码查询为反向,按照正向的作者表表名小写author查询,条件写在filter()括号中,values()括号中直接填写需要的键值'phone'
res = models.AuthorDetail.objects.filter(author__name='lufei').values('phone')

4.查询北方出版社出版过的书籍名称和价格

# 根据出版社查询书籍,反向查询,主键在书籍表中,从书籍查询为正向,按照正向书籍表中外键名publish查询
res = models.Book.objects.filter(publish__name='北方出版社').values('title','price')

5.查询lufei写过的书籍

# 根据作者查询书籍,反向查询,主键在书籍表中,从书籍查询为正向,按照正向书籍表外键名authors查询
res = models.Book.objects.filter(authors__name='lufei').values('title')

6.查询电话号码是110的作者姓名

# 根据作者详情查作者,反向查询, 主键在作者表中,从作者查询为正向,按照正向作者表外键名author_detail查询
res = models.Author.objects.filter(author_detail__phone=110).values('name')

7.查询主键为3的书籍对应的作者的电话号码

# 1.从书籍表查询
# 书籍———>作者(正向按外键authors)————>详情(正向按外键author_detail)
res = models.Book.objects.filter(pk=3).values('authors__author_detail__phone')
# 2.从详情表查询
# 详情————>作者(反向按表名author)————>书籍(反向按表名book)
res = models.AuthorDetail.objects.filter(author__book__pk=3).values('phone')
# 3.从作者表查询
# 作者————>书籍(反向按表名book)
# 根据书籍主键获取到作者之后,直接到详情表中获取电话号码(正向按外键author_detail)
res = models.Author.objects.filter(book__pk=3).values('author_detail__phone')

聚合查询 aggregate( *args,**kwargs)

五种聚合函数
  • Avg (Average) : 平均值
  • Max (Maximum) : 最大值
  • Min (Minimum) : 最小值
  • Sum (Summary) : 求和
  • Count : 个数

1、aggregate()

from dels import Avg,Max,Min,Sum,Count  # 导入聚合函数# 计算平均值
res = models.Book.objects.aggregate(Avg('price')) 
# 指定名称
res = models.Book.objects.aggregate(avg_price=Avg('price'))  res = models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Avg('price')) # 统计东方出版社出版的书籍的个数
res = models.Publish.objects.filter(name='东方出版社').aggregate(count_num=Count('book__id'))

分组查询 annotate

  • annotate() 直接跟在 objects 之后,则表示直接以当前的基表为分组依据objects.annotate()
  • annotate() 跟在 values() 之后,则表示按照values括号内指定的字段来进行分组values().annotate()
  • annotate( ) 跟在values( ) 在之前,则表示取values括号内的字段annotate().values()
  • annotate( ) 跟在filter( ) 之后,则表示 where 条件 filter().annotate()
  • annotate( ) 跟在filter( ) 之前,则表示 having 条件annotate().filter()
#需要在测试文件中先导包
from dels import Max,Min,Count,Sum,Avg# 统计每个出版社出版的书的平均价格
res = models.Publish.objects.annotate(avg_price=Avg('book__price')).values('name','avg_price')# 统计每一本书的作者个数
res = models.Book.objects.annotate(count_num=Count('authors')).values('title','count_num')# 统计出每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')# 查询每个作者出的书的总价格
res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price')# 查询每个作者出的书的数量和总价格
res = models.Author.objects.annotate(total_num=Count('book__pk'),total_price=Sum('book__price'),).values('name','total_num','total_price')# 统计有多个作者的图书
# 第1步:先统计每本书的作者个数
author_num = models.Book.objects.annotate(authors_num=Count('authors__pk'))# 第2步:筛选出作者个数大于1的图书
res = models.Book.objects.annotate(author_num=Count('authors__pk')).filter(author_num__gt=1).values('title','author_num')"""按照字段分组"""
# 统计每个出版社所出的书的数量
res = models.Book.objects.values('publish_id').annotate(total_num=Count('pk')).values('publish__name','total_num')

还有F查询Q查询only、defer、select_related、prefetch_related,后续再了解

本文发布于:2024-01-29 11:51:59,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170650032515079.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:项目   ORM   django   orm
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23