【六】Django框架之ORM常用字段及参数

【一】引入

一些说明:

  • 表myapp_person的名称是自动生成的,如果你要自定义表名,需要在model的Meta类中指定 db_table 参数,强烈建议使用小写表名,特别是使用MySQL作为后端数据库时。
  • id字段是自动添加的,如果你想要指定自定义主键,只需在其中一个字段中指定 primary_key=True 即可。
    • 如果Django发现你已经明确地设置了Field.primary_key,它将不会添加自动ID列。
  • 本示例中的CREATE TABLE SQL使用PostgreSQL语法进行格式化,但值得注意的是,Django会根据配置文件中指定的数据库后端类型来生成相应的SQL语句。
  • Django支持MySQL5.5及更高版本。

【二】常用字段

【1】AutoField

  • int自增列
    • 必须填入参数 primary_key=True。
  • 当model中如果没有自增列,则自动会创建一个列名为id的列。

【2】IntegerField

  • 一个整数类型
    • 范围在 -2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存,)

【3】CharField

  • 字符类型,必须提供max_length参数, max_length表示字符长度。
  • 这里需要知道的是Django中的CharField对应的MySQL数据库中的varchar类型,没有设置对应char类型的字段,但是Django允许我们自定义新的字段,下面我来自定义对应于数据库的char类型

自定义字段在实际项目应用中可能会经常用到,这里需要对他留个印象!

from django.db import models

# Create your models here.
#Django中没有对应的char类型字段,但是我们可以自己创建
class FixCharField(models.Field):
    '''
    自定义的char类型的字段类
    '''
    def __init__(self,max_length,*args,**kwargs):
        self.max_length=max_length
        super().__init__(max_length=max_length,*args,**kwargs)

    def db_type(self, connection):
        '''
        限定生成的数据库表字段类型char,长度为max_length指定的值
        :param connection:
        :return:
        '''
        return 'char(%s)'%self.max_length
#应用上面自定义的char类型
class Class(models.Model):
    id=models.AutoField(primary_key=True)
    title=models.CharField(max_length=32)
    class_name=FixCharField(max_length=16)
    gender_choice=((1,'男'),(2,'女'),(3,'保密'))
    gender=models.SmallIntegerField(choices=gender_choice,default=3)

【4】DateField

  • 日期字段
    • 日期格式 YYYY-MM-DD
  • 相当于Python中的datetime.date()实例。

【5】DateTimeField

  • 日期时间字段
    • 格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
  • 相当于Python中的datetime.datetime()实例。

【三】字段合集

【1】AutoField(Field)

  • int自增列
    • 必须填入参数 primary_key=True

【2】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)

【3】SmallIntegerField(IntegerField):

  • 小整数 -32768 ~ 32767
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
    - 正小整数 0 ~ 32767
IntegerField(Field)
    - 整数列(有符号的) -2147483648 ~ 2147483647

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

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

【4】BooleanField(Field)

  • 布尔值类型

【5】NullBooleanField(Field):

  • 可以为空的布尔值

【6】CharField(Field)

  • 字符类型
    • 必须提供max_length参数, max_length表示字符长度

【7】TextField(Field)

  • 文本类型

【8】EmailField(CharField):

  • 字符串类型
    • Django Admin以及ModelForm中提供验证机制

【9】IPAddressField(Field)

  • 字符串类型
    • Django Admin以及ModelForm中提供验证 IPV4 机制

【10】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"

【11】URLField(CharField)

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

【12】SlugField(CharField)

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

【13】CommaSeparatedIntegerField(CharField)

  • 字符串类型
    • 格式必须为逗号分割的数字

【14】UUIDField(Field)

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

【15】FilePathField(Field)

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

【16】FileField(Field)

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

【17】ImageField(FileField)

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

【18】DateTimeField(DateField)

  • 日期+时间格式
    • YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

【19】DateField(DateTimeCheckMixin, Field)

  • 日期格式
    • YYYY-MM-DD

【20】TimeField(DateTimeCheckMixin, Field)

  • 时间格式
    • HH:MM[:ss[.uuuuuu]]

【21】DurationField(Field)

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

【22】FloatField(Field)

  • 浮点型

【23】DecimalField(Field)

  • 10进制小数
参数:
    max_digits,小数总长度
    decimal_places,小数位长度

【24】BinaryField(Field)

- 二进制类型

【四】字段参数

【1】null

  • 用于表示某个字段可以为空。

【2】unique

  • 如果设置为unique=True 则该字段在此表中必须是唯一的 。

【3】db_index

  • 如果db_index=True 则代表着为此字段设置索引。

【4】default

  • 为该字段设置默认值。

【五】DateField和DateTimeField

【1】auto_now_add

  • 配置auto_now_add=True
    • 创建数据记录的时候会把当前时间添加到数据库。

【2】auto_now

  • 配置上auto_now=True
    • 每次更新数据记录的时候会更新该字段。

【六】关系字段 ForeignKey

  • 外键类型在ORM中用来表示外键关联关系
    • 一般把ForeignKey字段设置在 '一对多'中'多'的一方。
  • ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。

【七】ForeignKey 字段参数

【1】to

  • 设置要关联的表

【2】to_field

  • 设置要关联的表的字段

【3】on_delete

  • 当删除关联表中的数据时,当前表与其关联的行的行为。

【4】models.CASCADE

  • 删除关联数据,与之关联也删除

【5】其他on_delete参数

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相似

【6】代码配置

def func():
    return 10

class MyModel(models.Model):
    user = models.ForeignKey(
        to="User",
        to_field="id",
        on_delete=models.SET(func)
    )

【八】ForeignKey操作

【1】正向查找(两种方式)

1.对象查找(跨表)

  • 语法:
对象.关联字段.字段

要点:先拿到对象,再通过对象去查对应的外键字段,分两步

  • 示例:
book_obj = models.Book.objects.first()  # 第一本书对象(第一步)
print(book_obj.publisher)  # 得到这本书关联的出版社对象
print(book_obj.publisher.name)  # 得到出版社对象的名称

2.字段查找(跨表)

  • 语法:
关联字段__字段

要点:利用Django给我们提供的神奇的双下划线查找方式

  • 示例:
models.Book.objects.all().values("publisher__name")
#拿到所有数据对应的出版社的名字,神奇的下划线帮我们夸表查询

【2】反向操作(两种方式)

1.对象查找

  • 语法:
obj.表名_set

要点:先拿到外键关联多对一,一中的某个对象,由于外键字段设置在多的一方,所以这里还是借用Django提供的双下划线来查找

  • 示例:
publisher_obj = models.Publisher.objects.first()  # 找到第一个出版社对象
books = publisher_obj.book_set.all()  # 找到第一个出版社出版的所有书
titles = books.values_list("title")  # 找到第一个出版社出版的所有书的书名

结论:如果想通过一的那一方去查找多的一方,由于外键字段不在一这一方,所以用__set来查找即可

2.字段查找

  • 语法:
表名__字段

要点:直接利用双下滑线完成跨表操作

titles = models.Publisher.objects.values("book__title")

【九】OneToOneField

  • 一对一字段。
  • 通常一对一字段用来扩展已有字段。
  • (通俗的说就是一个人的所有信息不是放在一张表里面的,简单的信息一张表,隐私的信息另一张表,之间通过一对一外键关联)

【十】OneToOneField 字段参数

【1】to

  • 设置要关联的表。

【2】to_field

  • 设置要关联的字段。

【3】on_delete

  • 当删除关联表中的数据时,当前表与其关联的行的行为。(参考上面的例子)

【十一】ManyToManyField

【1】class RelatedManager

  • "关联管理器"是在一对多或者多对多的关联上下文中使用的管理器。

它存在于下面两种情况:

  1. 外键关系的反向查询
  2. 多对多关联关系
  • 简单来说就是在多对多表关系并且这一张多对多的关系表是有Django自动帮你建的情况下,下面的方法才可使用。

【2】方法

(1)create()

  • 创建一个关联对象,并自动写入数据库,且在第三张双方的关联表中自动新建上双方对应关系。
models.Author.objects.first().book_set.create(title="偷塔秘籍")
上面这一句干了哪些事儿:
1.由作者表中的一个对象跨到书籍比表
2.新增名为偷塔秘籍的书籍并保存
3.到作者与书籍的第三张表中新增两者之间的多对多关系并保存

(2)add()

  • 把指定的model对象添加到第三张关联表中。

  • 添加对象

>>> author_objs = models.Author.objects.filter(id__lt=3)
>>> models.Book.objects.first().authors.add(*author_objs)
  • 添加id
>>> models.Book.objects.first().authors.add(*[1, 2])

(3)set()

  • 更新某个对象在第三张表中的关联对象。不同于上面的add是添加,set相当于重置
>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.set([2, 3])

(4)remove()

  • 从关联对象集中移除执行的model对象(移除对象在第三张表中与某个关联对象的关系)
>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.remove(3)

(5)clear()

  • 从关联对象集中移除一切对象。(移除所有与对象相关的关系信息)
>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.clear()

注意:

​ 对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。

(6)举个例子:

  • ForeignKey字段没设置null=True时,
class Book(models.Model):
    title = models.CharField(max_length=32)
    publisher = models.ForeignKey(to=Publisher)
  • 没有clear()和remove()方法:
>>> models.Publisher.objects.first().book_set.clear()
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'RelatedManager' object has no attribute 'clear'
  • 当ForeignKey字段设置null=True时,
class Book(models.Model):
    name = models.CharField(max_length=32)
    publisher = models.ForeignKey(to=Class, null=True)
  • 此时就有clear()和remove()方法:
>>> models.Publisher.objects.first().book_set.clear()

再次强调:

​ 对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。

​ 换句话说,在关联的任何一端,都不需要再调用save()方法。

【十二】在Python脚本中调用Django环境

  • 一般操作
    • 在进行一般操作时先配置一下参数,使得我们可以直接在Django页面中运行我们的测试脚本

这样就可以直接运行你的test.py文件来运行测试

【十三】必知必会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个必会操作总结

【1】返回QuerySet对象的方法

(1)all():

  • 该方法返回一个包含所有记录的QuerySet对象。
  • 示例:objects.all()

(2)filter(**kwargs):

  • 该方法返回一个满足筛选条件的QuerySet对象。
  • 可以使用关键字参数来指定筛选条件,如 field_name=value
  • 示例:objects.filter(name='John')

(3)exclude(**kwargs):

  • 该方法返回一个不满足筛选条件的QuerySet对象。
  • 可以使用关键字参数来指定筛选条件,如 field_name=value
  • 示例:objects.exclude(age__lt=18)

(4)order_by(*fields):

  • 该方法用于对QuerySet对象进行排序,并返回排序后的QuerySet对象。
  • 可以传入一个或多个字段作为参数,使用负号(-)表示降序排序。
  • 示例:objects.order_by('name', '-age')

(5)reverse():

  • 该方法用于将QuerySet对象中的记录顺序反转,并返回反转后的QuerySet对象。
  • 示例:objects.reverse()

(6)distinct(*fields):

  • 该方法用于查询不重复的记录,返回一个去重后的QuerySet对象。
  • 可以传入一个或多个字段作为参数,只返回在指定字段上不重复的记录。
  • 示例:objects.distinct('category')

【2】特殊的QuerySet

(1)values()

  • 返回一个可迭代的字典序列

  • values() 方法返回一个可迭代的字典序列,每个字典表示一个查询结果对象,并且字典的键是字段名,值是该字段的值。

  • 你可以使用 values() 方法指定要获取的字段,也可以使用其他查询方法进行过滤、排序等操作。

  • 示例代码:

python# 获取学生表中所有学生的姓名和年龄
student_data = Student.objects.values('name', 'age')
for data in student_data:
    print(data['name'], data['age'])

(2)values_list()

  • 返回一个可迭代的元祖序列

  • values_list() 方法返回一个可迭代的元组序列,每个元组表示一个查询结果对象,并且元组的元素顺序与指定的字段顺序一致。

  • 你可以使用 values_list() 方法指定要获取的字段,也可以使用其他查询方法进行过滤、排序等操作。

  • 示例代码:

python# 获取学生表中所有学生的姓名和年龄
student_data = Student.objects.values_list('name', 'age')
for data in student_data:
    print(data[0], data[1])

【3】返回具体对象的

(1)get()

  • get() 方法用于获取符合查询条件的单个对象。

  • 如果查询结果为空或者超过一个对象符合查询条件,get() 方法会抛出MultipleObjectsReturned 或者 DoesNotExist 异常。

  • 你可以使用其他查询方法或者查询参数来限定查询条件。

  • 示例代码:

    python# 获取名字为 "John" 的学生对象
    student = Student.objects.get(name="John")

(2)first()

  • first() 方法用于获取查询结果中的第一个对象,如果查询结果为空,则返回None

  • 你可以使用其他查询方法或者查询参数来限定查询条件。

  • 示例代码:

python# 获取学生表中的第一个学生对象
student = Student.objects.first()

(3)last()

  • last() 方法用于获取查询结果中的最后一个对象,如果查询结果为空,则返回None
  • 你可以使用其他查询方法或者查询参数来限定查询条件。
python# 获取学生表中的最后一个学生对象
student = Student.objects.last()

【4】返回布尔值的方法:

exists()

  • 在Django的QuerySet中,exists() 是一个返回布尔值的方法,它用于检查查询结果是否存在。

  • exists() 方法的作用是判断查询结果集中是否存在符合给定查询条件的对象。

    • 如果存在至少一个匹配的对象,则 exists() 方法返回 True
    • 否则返回 False
  • 示例代码:

# 检查名字为 "John" 的学生是否存在
student_exists = Student.objects.filter(name="John").exists()

if student_exists:
    print("名字为 John 的学生存在")
else:
    print("名字为 John 的学生不存在")

注意事项:

  • exists() 方法只是检查查询结果中是否有对象存在,并不会实际获取这些对象的数据。
  • 使用 exists() 方法可以避免将整个查询结果集加载到内存中,因此在性能方面更加高效。
  • 你可以在任何基于 QuerySet 的查询中都使用 exists() 方法。

【5】返回数字的方法

count()

在使用Django进行数据库查询时,我们通常会首先获取一个QuerySet对象,然后可以对该对象进行过滤、排序等操作。

count() 方法可以用于获取符合查询条件的结果数量,而无需获取实际的数据记录。

这对于在不需要获取所有数据的情况下,仅仅需要知道匹配的结果数量非常有用。

  • count() 方法是Django中QuerySet对象的方法。

  • 它用于获取满足查询条件的记录数量。

  • 通过调用 count() 方法,可以避免获取所有记录,只获取满足条件的记录数量。

  • 使用 count() 方法可以快速获取满足查询条件的记录数量,可以用于在Django项目中进行数据统计、结果分页等操作。

  • 示例

from myapp.models import MyModel

# 获取所有满足条件的记录数量
count = MyModel.objects.filter(some_field='some_value').count()
print(count)  # 输出匹配条件的记录数量

【6】案例演示

  • 假设我们有一个学生表(Student)存储了学生的信息,包括姓名(name)、年龄(age)和成绩(score)。

  • 首先,我们引入模型和创建几条学生记录作为示例:

from django.db import models

class Student(models.Model):
    name = models.CharField(max_length=50)
    age = models.IntegerField()
    score = models.FloatField()

# 创建几个学生记录
Student.objects.create(name='Alice', age=18, score=90)
Student.objects.create(name='Bob', age=20, score=85)
Student.objects.create(name='Charlie', age=19, score=92)
Student.objects.create(name='David', age=22, score=88)

(1)返回QuerySet对象的方法

  1. 使用 all() 方法返回所有学生记录:
all_students = Student.objects.all()
  1. 使用 filter() 方法筛选年龄大于等于20的学生记录:
filtered_students = Student.objects.filter(age__gte=20)
  1. 使用 exclude() 方法排除成绩小于90的学生记录:
excluded_students = Student.objects.exclude(score__lt=90)
  1. 使用 order_by() 方法按照成绩降序排序学生记录:
ordered_students = Student.objects.order_by('-score')
  1. 使用 reverse() 方法反转学生记录的顺序:
reversed_students = Student.objects.reverse()
  1. 使用 distinct() 方法获取具有不重复姓名的学生记录:
distinct_names = Student.objects.distinct('name')

(2)特殊的QuerySet

特殊的QuerySet方法 values()values_list() 提供了以特定格式返回查询结果的功能。

  1. values() 方法返回一个可迭代的字典序列,每个字典对应查询结果中的一条记录,字典的键是字段名,值是字段的值。这个方法可以用于获取指定字段的值,或者用于进行进一步处理和分析。
  • 示例代码如下:
students = Student.objects.values('name', 'age', 'score')
for student in students:
    print(student['name'], student['age'], student['score'])
  • 以上代码会打印出每个学生记录的姓名、年龄和成绩。
  1. values_list() 方法返回一个可迭代的元组序列,每个元组对应查询结果中的一条记录,元组的元素是按照字段在查询中的顺序排列的。这个方法可以用于获取指定字段的值,并且可以选择只获取单个字段的值。
  • 示例代码如下:
students = Student.objects.values_list('name', 'age', 'score')
for student in students:
    print(student[0], student[1], student[2])
  • 以上代码会打印出每个学生记录的姓名、年龄和成绩。

(3)返回具体对象

在 Django 的 QuerySet 中,我们可以使用 get()first()last() 方法来返回具体的对象。

  1. get() 方法用于获取满足查询条件的单个对象。如果查询结果为空或者超过一个对象,则会引发 MultipleObjectsReturnedDoesNotExist 异常。你可以在查询中使用筛选条件来获取特定的对象。

示例代码如下:

student = Student.objects.get(name='Alice')
print(student.name, student.age, student.score)

以上代码将返回名为 "Alice" 的学生对象,并打印出其姓名、年龄和成绩。

  1. first() 方法用于获取查询结果集中的第一个对象。如果查询结果集为空,则返回 None
  • 示例代码如下:
student = Student.objects.first()
if student:
    print(student.name, student.age, student.score)
  • 以上代码将返回查询结果集中的第一个学生对象,并打印出其姓名、年龄和成绩。
  1. last() 方法用于获取查询结果集中的最后一个对象。如果查询结果集为空,则返回 None
  • 示例代码如下:
student = Student.objects.last()
if student:
    print(student.name, student.age, student.score)
  • 以上代码将返回查询结果集中的最后一个学生对象,并打印出其姓名、年龄和成绩。

(4)返回布尔值的方法:

在许多编程语言和框架中,包括 Django,我们经常需要判断某个条件是否成立,返回一个布尔值以表示条件的真假。在 Django 的 QuerySet 中,我们可以使用 exists() 方法来检查查询结果是否存在。

exists() 方法用于检查查询结果集中是否至少存在一个对象。如果存在满足查询条件的对象,则返回 True;否则返回 False。

  • 示例代码如下:
# 检查是否存在年龄大于等于18岁的学生
if Student.objects.filter(age__gte=18).exists():
    print("存在年龄大于等于18岁的学生")
else:
    print("不存在年龄大于等于18岁的学生")

# 检查是否存在姓名为Alice的学生
if Student.objects.filter(name='Alice').exists():
    print("存在姓名为Alice的学生")
else:
    print("不存在姓名为Alice的学生")
  • 以上代码会根据查询结果输出相应的信息。

(5)返回数字的方法有

在编程中,我们常常需要计算某个集合中元素的数量。在许多编程语言和框架中,包括 Django,我们可以使用 count() 方法来返回集合中元素的数量。

在 Django 的 QuerySet 中,count() 方法用于返回查询结果集中对象的数量。

示例代码如下:

# 统计学生表中的学生数量
student_count = Student.objects.count()
print("学生数量:", student_count)

# 统计年龄大于等于18岁的学生的数量
adult_student_count = Student.objects.filter(age__gte=18).count()
print("年龄大于等于18岁的学生数量:", adult_student_count)

以上代码会分别统计学生表中的学生数量和年龄大于等于18岁的学生数量,并输出结果。

通过使用 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即可查看查询语句,具体操作如下:

【十六】单表查询之神奇的双下划线

models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值
 
models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
 
models.Tb1.objects.filter(name__contains="ven")  # 获取name字段包含"ven"的
models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
 
models.Tb1.objects.filter(id__range=[1, 3])      # id范围是1到3的,等价于SQL的bettwen and
 
类似的还有:startswith,istartswith, endswith, iendswith 

date字段还可以:
models.Class.objects.filter(first_day__year=2017)
date字段可以通过在其后加__year,__month,__day等来获取date的特点部分数据
# date
        #
        # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
        # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

        # year
        #
        # Entry.objects.filter(pub_date__year=2005)
        # Entry.objects.filter(pub_date__year__gte=2005)

        # month
        #
        # Entry.objects.filter(pub_date__month=12)
        # Entry.objects.filter(pub_date__month__gte=6)

        # day
        #
        # Entry.objects.filter(pub_date__day=3)
        # Entry.objects.filter(pub_date__day__gte=3)

        # week_day
        #
        # Entry.objects.filter(pub_date__week_day=2)
        # Entry.objects.filter(pub_date__week_day__gte=2)
需要注意的是在表示一年的时间的时候,我们通常用52周来表示,因为天数是不确定的,老外就是按周来计算薪资的哦~

【十七】聚合查询和分组查询

【1】聚合(利用聚合函数)

  • aggregate()QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。
  • 键的名称是聚合值的标识符,值是计算出来的聚合值。
    • 键的名称是按照字段和聚合函数的名称自动生成出来的。
  • 用到的内置函数:
from django.db.models import Avg, Sum, Max, Min, Count
  • 示例:
>>> from django.db.models import Avg, Sum, Max, Min, Count
>>> models.Book.objects.all().aggregate(Avg("price"))
{'price__avg': 13.233333}
  • 如果你想要为聚合值指定一个名称,可以向聚合子句提供它。
>>> models.Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 13.233333}
  • 如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。
  • 所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
>>> models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
{'price__avg': 13.233333, 'price__max': Decimal('19.90'), 'price__min': Decimal('9.90')}

【2】分组

  • 我们在这里先复习一下SQL语句的分组。
  • 假设现在有一张公司职员表:

  • 我们使用原生SQL语句,按照部分分组求平均工资:
select dept,AVG(salary) from employee group by dept;
  • ORM查询:
from django.db.models import Avg
Employee.objects.values("dept").annotate(avg=Avg("salary").values(dept, "avg")

这里需要注意的是annotate分组依据就是他前面的值,

如果前面没有特点的字段,则默认按照ID分组,

这里有dept字段,所以按照dept字段分组

  • 连表查询的分组:

  • SQL查询:
select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;
  • ORM查询:
from django.db.models import Avg
models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")

【3】更多示例

  • 示例1:统计每一本书的作者个数
>>> book_list = models.Book.objects.all().annotate(author_num=Count("author"))
>>> for obj in book_list:
...     print(obj.author_num)
...
1
  • 示例2:统计出每个出版社买的最便宜的书的价格
>>> publisher_list = models.Publisher.objects.annotate(min_price=Min("book__price"))
>>> for obj in publisher_list:
...     print(obj.min_price)
...     
9.90
19.90

方法二:

models.Book.objects.values("publisher__name").annotate(min_price=Min("price"))
<QuerySet [{'publisher__name': '沙河出版社', 'min_price': Decimal('9.90')}, {'publisher__name': '人民出版社', 'min_price': Decimal('19.90')}]>
  • 示例3:统计不止一个作者的图书
models.Book.objects.annotate(author_num=Count("author")).filter(author_num__gt=1)
<QuerySet [<Book: 番茄物语>]>
  • 示例4:根据一本图书作者数量的多少对查询集 QuerySet进行排序
models.Book.objects.annotate(author_num=Count("author")).order_by("author_num")
<QuerySet [<Book: 香蕉物语>, <Book: 橘子物语>, <Book: 番茄物语>]>
  • 示例5:查询各个作者出的书的总价格
models.Author.objects.annotate(sum_price=Sum("book__price")).values("name", "sum_price")
<QuerySet [{'name': '小精灵', 'sum_price': Decimal('9.90')}, {'name': '小仙女', 'sum_price': Decimal('29.80')}, {'name': '小魔女', 'sum_price': Decimal('9.90')}]>

【4】总结

  • value里面的参数对应的是sql语句中的select要查找显示的字段,
  • filter里面的参数相当于where或者having里面的筛选条件
  • annotate本身表示group by的作用,前面找寻分组依据,内部放置显示可能用到的聚合运算式,后面跟filter来增加限制条件,最后的value来表示分组后想要查找的字段值

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值