Django ORM(Object-Relational Mapping) 把对象自动映射到数据库中,是业务逻辑和数据库层的桥梁

使用 ORM 可以提升开发效率,但是会一定程度上影响程序的性能。

http请求都封装成事务
DATABASES[“default”][“ATOMIC_REQUESTS”] = True

模型类常用字段

  1. from django.db import models
  2. class NormalField(modes.Model):
  3. # 自增字段
  4. auto = models.AutoField()
  5. big_auto = models.BigAutoField() # 64位整数 保证从数字1到9223372036854775807
  6. # 二进制数据
  7. binary = models.BinaryField()
  8. # 布尔型
  9. boolean = models.BooleanField()
  10. null_boolean = models.NullBooleanField() # 允许为空的布尔型
  11. # 整型
  12. positive_small_integer = models.PositiveSmallIntegerField() # 正整数 5个字节
  13. small_integer = models.SmallIntegerField() # 整数 6个字节
  14. positive_integer = models.PositiveIntegerField() # 10个字节
  15. integer = models.IntegerField() # 11个字节
  16. bit_integer = models.BigIntegerField() # 20个字节
  17. # 字符串类型
  18. char = models.CharField() # varchar
  19. text = models.TextField() # lonetext 不需要指定长度
  20. # 时间日期类型
  21. date = models.DateField()
  22. date_time = models.DateTimeField()
  23. duration = models.DurationField() # int, 通过 timedelta 实现 obj = timedelta(days=20, hours=10)
  24. # 浮点型
  25. float = models.FloatField()
  26. decimal = models.DecimalField(..., max_digits=5, decimal_places=2) # 需要指明整数位和小数位
  27. # 其他字段
  28. email = models.EmailField()
  29. image = models.ImageField()
  30. file = models.FileField()
  31. file_path = models.FilePathField()
  32. url = models.URLField()
  33. uuid = models.UUIDField()
  34. generic_IP_address = models.GenericIPAddressField()
  35. class A(models.Model):
  36. one_to_one = models.OneToOneField(NormalField)
  37. class B(models.Model):
  38. foreign = models.ForeiognKey(A)
  39. class C(model.Model):
  40. many_to_many = models.ManyToManyField(B)

在数据库中对应的表名与字段名

表名:

  • app 的名为 course 模型名为 Teacher,表名为:course_teacher

字段名:

  • 如果字段名为 sex 数据库中也会为 sex,可以通过属性 (db_colum=’gender’) 更改在数据库中的字段名

注意:由于 Django 的查询语法,字段名除了不能是关键字外,也不能包含连续多个下划线

自定义表名与字段名

Django 用来做数据库管理系统是极其方便的,如果用来管理已存在的数据库一般要自定义表名与字段名

  1. class Article(models.Model):
  2. """文章模型"""
  3. # 通过db_column自定义数据表中字段名
  4. title = models.CharField('标题', max_length=200, db_column='article_title')
  5. slug = models.SlugField('slug', max_length=60, blank=True)
  6. def __str__(self):
  7. return self.title
  8. class Meta:
  9. db_table = 'article' # 通过db_table自定义数据表名

字段参数

通用参数

primary_key=True/False

  • 设置字段是否为主键,每个表只能有一个主键

verbose_name=’xx’

  • 字段的别名或备注

unique=True

  • 该字段在表中值唯一

null=True,blank=True

  • null 是数据库层是否为空,而blank=True表示在表单提交时是否可以为空

db_index=True

  • 是否为该字段建立索引,每次插入数据都会更新索引,查看慢查询日志考量后添加索引

help_text=’xx’

  • 帮助说明

editable=False

  • 在 admin 或 ModelForm 里不会被用户编辑

    字符串参数

    max_length=100

  • 最长utf8编码的100个字符串

    时间日期参数

    unique_for_date=True、unique_for_month=True

  • 该字段的日期/月份唯一

auto_now=True

  • 更新当前记录的时间

auto_now_add=True

  • 创建当前记录的时间

    浮点型Decimal参数

    max_digits=4

  • 总共有4位数

decimal_places=2

  • 小数位2位

关系型字段参数

related_name=’books’

  • 用于外键关联中的反向查询

on_delete=models.XXX
当一个外键被删除是,Django 会模仿 on_delete 参数定义的 SQL 约束执行相应操作

  • CASCADE:模拟 SQL 语言中的 ON DELETE CASCADE 约束,将定义有外键的模型对象同时删除
  • PROTECT: 阻止上面的删除操作,并报 ProtectedError 异常
  • SET_NULL: 将外键字段设置为 null,只有当前字段设置了 null=True 时,方可使用该值
  • SET_DEFAULT: 将外键字段设置为默认值,只有当字段设置了 default 参数时,方可使用
  • DO_NOTHING: 什么都不做
  • SET(): 设置为一个传递给 SET() 的值或者一个回调函数的返回值

自关联

  1. class AddressInfo(models.Model):
  2. """省市县地址信息"""
  3. address = models.CharField(max_length=200, null=True, blank=True, verbose_name="地址")
  4. pid = models.ForeignKey('self', null=True, blank=True, verbose_name="上级地址")
  5. # 或者 pid = models.ForeignKey('AddressInfo', null=True, blank=True, verbose_name="上级地址")
  6. def __str__(self): # python2 __unicode__(self) 返回一个可读的字符串
  7. return self.address

元数据

  1. class SomeModel(models.Model):
  2. title = models.CharField(max_length=100)
  3. note = models.CharField(max_length=100)
  4. sort = models.PositiveIntegerField(default=0)
  5. order_date = models.DateTimeField(auto_now_add=True)
  6. class Meta:
  7. db_table = 'some_model' # 自定义表名
  8. ordering = 'sort' # 设置排序
  9. verbose_name = '某个模型' # 设置直观可读名称
  10. verbose_name_plural = verbose_name # 设置可读名称的复数形式
  11. abstract = True # 不生成数据表,只供其他子类集成
  12. permissions = (('定义的权限', '权限说明'), ('xxx', 'xx')) # 给表设置额外的权限,二元tuple
  13. managed = False # 由于Django会自动根据模型类生成映射的数据库表,如果你不希望Django这么做,可以把managed的值设置为False
  14. unique_together = ('title', 'note') # 对应数据表中的联合唯一约束,可以是一元元或多元元组
  15. app_label = 'xxx' # 如果没有在 Django settings 的 INSTALLED_PPS 添加app,就要设置该类属于哪个应用
  16. db_tablespace = 'xxx' # 定义数据表空间的名字
  17. get_latest_by = "order_date" # 可以在模型中使用Manager的 latest()和 earliest()方法找到对应数据

Manager

通过其向Django模型提供数据库查询操作的接口

返回 QuerySet 的 API

新的 QuerySet

all() : 查询所有
fileter(): 返回符合规则的
order_by(): 根据字段排序
exclude(): 排除符合规则的
reverse(): 相反排序,要在源数据中设置 order
distinct(): 去重
extra():

  • 取别名:
    • Student.object.all().extra(select={“name”: “nickname”})
    • key 是新字段名,value是原字段名

defer():

  • 结果模型中排除某些字段

only():

  • 限制模型返回的字段
    • Student.object.all().only(“nickname”, “age”)

字典或元组形式的 QuerySet

values():

  • 返回字典形式的 QuerySet

values_list():

  • 返回元组形式的 QuerySet,只有value,如果是单个字段,可以设置参数 flat=True 返回数组形式的querySet

一对一,多对多查询优化

select_related()

  • 一对一查询优化
  • 查询子表时一次性吧附表也查询出来,否则遍历取附表值时每次都要执行一遍对附表的查询

    1. course = Course.objects.all().select_related('teacher')
    2. for c in courses:
    3. print(f"{c.teacher.nickname}")

    prefetch_related()

  • 多对多查询优化

  • 如果不优化同样在遍历时都要执行关联查询
    1. students = Student.object.filter(age__lt=20).prefetch_related('course')
    2. for item in students:
    3. print(item.course.all())

聚合

annotate()

  • 对分组后的结果进行统计,一般配合 values 使用 ```python from django.db.models import Sum, Count, Avg, Max, Min

每个老师有多个课程,返回老师和对应老师的 volume 和

print(Course.objects.values(‘teacher’).annotate(vol=Sum(‘volume’)))

  1. <a name="gx7Fm"></a>
  2. ### 不返回 QuerySet 的 API
  3. get(): 返回单条数据,没有或者有多条会报错<br />get_or_created(): 与 get() 不同的是如果没有匹配数据就创建
  4. create(): 根据传入的键值对参数创建数据<br />bulk_create(): 根据传入的 对象列表,批量创建数据<br />update_or_create(): 如果没有匹配的值,就创建,default参数里是默认值, 如果有就更新 default 里面的字段
  5. - CustomUser.objects.update_or_create(nickname='小张', defaults={'age': 20, gender=1})
  6. update(): 更新前面所有对象里的值<br />delete(): 删除前面对象
  7. first(): 首条记录<br />last(): 末尾记录<br />latest(): 在 model 设置 get_latest_by 的前提下,输出最近时间数据<br />earliest(): 输出 最早的 数据<br />in_bulk(): 根据列表参数里的值,批量返回对象
  8. - Course.objects.in_bulk(['课程名1', '课程名2'])
  9. exists(): 结果是否存在 <br />count(): 结果数量
  10. aggregate(): 对前面的数据进行统计
  11. ```python
  12. from django.db.models import Max, Min, Avg, Sum
  13. Course.objects.aggregate(Max('price'), Min('price'), average=Avg('price'), Sum('price'))
  14. # 结果
  15. {'price__max': 300, 'price__min':210, 'average': 22.22, 'price__sum': 42888}

F 对象与 Q 对象

F对象 使原本 先 select 再 处理 数据的方式只需一条查询即可完成

  1. from django.db.models import F
  2. Course.objects.update(price=F('price') - 11)
  3. Course.objects.filter(volume__lte=F('price') * 10)

Q 对象 可以结合 与(&), 或(|), 非(~) 完成复杂查询

  1. from django.db.models import Q
  2. Course.objects.filter(~Q(title__icontains='java') | Q(price__gat=10))

获取随机 N 条数据

使用mysql数据库,数据量在百万级以下时

  1. Record.objects.order_by('?')[:2]

来获取随机记录序列,性能不会比

  1. sample = random.sample(xrange(Record.objects.count()),n)
  2. result = [Record.objects.all()[i]) for i in sample]

差。