模型准确且唯一的描述了数据。它包含您储存的数据的重要字段和行为。一般来说,每一个模型都映射一张数据库表。
- 每个模型都是一个 Python 的类,这些类继承 django.db.models.Model
- 模型类的每个属性都相当于一个数据库的字段。
- 利用这些,Django 提供了一个自动生成访问数据库的 API;
字段类型
模型中每一个字段都应该是某个 Field 类的实例, Django 利用这些字段类来实现以下功能:
- 字段类型用以指定数据库数据类型(如:INTEGER, VARCHAR, TEXT)。
- 在渲染表单字段时默认使用的 HTML 视图 (如: , )。
- 基本的有效性验证功能,用于 Django 后台和自动生成的表单。
字段 | 描述 |
---|---|
AutoField | 一个 IntegerField,根据可用的 ID 自动递增 |
BigAutoField | 一个 64 位整数,与 AutoField 很相似,但保证适合 1 到 9223372036854775807 的数字 |
BooleanField | 一个 true/false 字段。该字段的默认表单部件是 CheckboxInput,或者如果 null=True 则是 NullBooleanSelect。当 Field.default 没有定义时,BooleanField 的默认值是 None。 |
CharField | 一个字符串字段,适用于小到大的字符串。对于大量的文本,使用 TextField CharField 有两个额外的参数:CharField.max_length(必须的。该字段的最大长度)、CharField.db_collation(可选的。该字段的数据库字符序名称) |
DateField | 一个日期,在 Python 中用一个 datetime.date 实例表示 可选参数auto_now(每次保存对象时,自动将该字段设置为现在)、auto_now_add(当第一次创建对象时,自动将该字段设置为现在) |
详见:django官方文档–字段类型
字段选项
以下只介绍Field类中的选项,拓展类每个都有独特的选项,详细参考Django文档中每个类别的详细介绍(例如, CharField (以及它的子类)需要接收一个 max_length 参数,用以指定数据库存储 VARCHAR 数据时用的字节数。)
选型 | 描述 |
---|---|
null | 如果设置为 True,当该字段为空时,Django 会将数据库中该字段设置为 NULL。默认为 False 。 |
blank | 如果设置为 True,该字段允许为空。默认为 False。 |
choices | 一系列二元组,用作此字段的选项 CHOICES = [(‘FR’, ‘Freshman’),(‘SO’, ‘Sophomore’),] |
default | 该字段的默认值 |
help_text | 额外的“帮助”文本,随表单控件一同显示。 |
primary_key | 如果设置为 True ,将该字段设置为该模型的主键 |
unique | 如果设置为 True,这个字段的值必须在整个表中保持唯一 |
除了 ForeignKey, ManyToManyField 和 OneToOneField,任何字段类型都接收一个可选的位置参数 verbose_name,如果未指定该参数值, Django 会自动使用字段的属性名作为该参数值,并且把下划线转换为空格。
关联关系
显然,关系型数据库的强大之处在于各表之间的关联关系。 Django 提供了定义三种最常见的数据库关联关系的方法:多对一,多对多,一对一。
多对一关联
class ForeignKey(to, on_delete, **options)
一个多对一的关系。需要两个位置参数:模型相关的类和 on_delete 选项。
如果需要创建一个递归关系—— 一个与自己有多对一关系的对象
使用 models.ForeignKey(‘self’,on_delete=models.CASCADE)。
如果你需要在一个尚未定义的模型上创建关系,你可以使用模型的名称,而不是模型对象本身:
例如,如果一个 Car 模型有一个制造者 Manufacturer –就是说一个 Manufacturer
制造许多辆车,但是每辆车都仅有一个制造者– 那么使用下面的方法定义这个关系:
from django.db import modelsclass Manufacturer(models.Model):# ...passclass Car(models.Model):manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)# ...
on_delete参数设置
当一个由 ForeignKey 引用的对象被删除时,Django 将模拟 on_delete 参数所指定的 SQL 约束的行为。
- CASCADE
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.RESTRICT)
级联删除
。Django 模拟了 SQL 约束 ON DELETE CASCADE 的行为,也删除了包含 ForeignKey 的对象
。
Model.delete() 在相关的模型上没有被调用,但是 pre_delete 和 post_delete 信号是为所有被删除的对象发送的。
- PROTECT
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.PROTECT)
通过引发 ProtectedError错误
,即 django.db.IntegrityError 的子类,防止删除被引用对象。
- RESTRICT
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.RESTRICT)
这个在Django 3.1.以上版本使用
通过引发 RestrictedError错误
( django.db.IntegrityError 的一个子类)来防止删除被引用的对象。与 PROTECT 不同的是,如果被引用的对象也引用了一个在同一操作中被删除的不同对象,但通过 CASCADE 关系,则允许删除被引用的对象。
- SET_NULL
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.SET_NULL,null=True)
设置 ForeignKey 为空
;只有当 null 为 True 时,才有可能。
- SET_DEFAULT
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.SET_DEFAULT default=1)
将 ForeignKey 设置为默认值
,必须为 ForeignKey 设置一个默认值。
- SET()
#定义一个函数进行值得返回def get_manufacturer()return 1manufacturer = models.ForeignKey(Manufacturer, on_delete=models.SET(get_manufacturer),)
将 ForeignKey 设置为传递给 SET() 的值,如果传递了一个可调用的值,则为调用它的结果。在大多数情况下,为了避免在导入 models.py 时执行查询,传递一个可调用对象是必要的
- DO_NOTHING
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.DO_NOTHING)
不采取任何行动
。如果你的数据库后端强制执行引用完整性,这将导致一个 IntegrityError 除非你手动添加一个 SQL ON DELETE 约束条件到数据库字段。
on_delete 的可能值可以在 django.db.models 中找到。
地区的自关联实例
以下使用地区的自关联查询为实例
#模型创建model.pyclass District(models.Model):parent = models.ForeignKey("self",null=True,blank=True,on_delete=models.CASCADE,related_name="child", #verbose_name="父级地区",)name = models.CharField(max_length=128, help_text="地区名称", verbose_name="地区名称")level = models.IntegerField(default=0, help_text="地区级别", verbose_name="地区级别")full_name = models.CharField(max_length=256, help_text="地区全名", verbose_name="地区全名")def __str__(self):return self.full_nameclass Meta:managed=Trueverbose_name = "地区信息"verbose_name_plural = verbose_name
#视图调用模型以drf框架的视图的使用APIView主class CityCountyView(APIView):"""父级下二级地区信息获取"""authentication_classes = [BasicAuthentication]permission_classes = (AllowAny,)@swagger_auto_schema(operation_description='父级下二级地区信息获取', responses={200: {}})def get(self, request, pk):# 判断有没有缓存,有缓存使用缓存,没有缓存去数据库查询存入缓存一天sub_data = cache.get('sub_data_%s' % pk)if not sub_data:try:# 获取到前端传过来的父级id查询出父级对象parent_obj = District.objects.get(id=pk)# 获取对象的所有外键关联的子级sub_objs = parent_obj.child.all()subs = []# 组织数据for sub in sub_objs:subs.append({'id': sub.id, 'name': sub.name, })sub_data = {'id': pk, 'name': parent_obj.name, 'subs': subs}except Exception as e:print(e)return Response({'code': 400, 'errmsg': '查询失败'})cache_key_name = 'sub_data_%s' % pkcache.set(cache_key_name, sub_data, 3600 * 24) #return Response({'code': 0, 'errmsg': 'ok', 'sub_data': sub_data})
动态生成模型类
#使用函数+class来定义def getTaskDetailModel(table_name):class MyCLass(models.Model):task = models.ForeignKey(Task, on_delete=models.CASCADE, related_name='details', verbose_name='任务')user_id = models.IntegerField(verbose_name='用户ID')created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')is_complet = models.BooleanField(default=False, verbose_name='是否完成')class Meta:db_table = table_namereturn MyCLass#使用函数+type进行创建动态类def create_task_detail_model(password_code):classname = f'TaskDetail_{password_code}'class Meta:db_table = classnamereturn type(classname, (models.Model,), {'task': models.ForeignKey(Task, on_delete=models.CASCADE, related_name='details', verbose_name='任务'),'user_id': models.IntegerField(verbose_name='用户ID'),'created_time': models.DateTimeField(auto_now_add=True, verbose_name='创建时间'),'is_complet': models.BooleanField(default=False, verbose_name='是否完成'),'__str__': lambda self: f"{self.task.password_code} - {self.user_id}",'Meta': Meta,'__module__': __name__,})