在Django中,模型是数据描述的准确载体,每个模型映射一张数据库表,模型类继承自 django.db.models.Model,其属性对应数据库字段。Django 通过这些字段类自动生成数据库访问 API,并指定数据库数据类型,提供表单渲染和基础验证。
一、常用字段类型
AutoField:自增整数字段,根据可用 ID 自动递增。BigAutoField:64位自增整数,范围 1 到 9223372036854775807。BooleanField:布尔字段,默认表单部件为 CheckboxInput(null=True 时为 NullBooleanSelect),默认值为 None。CharField:字符串字段,适用于中小型文本,需指定 max_length(必填)和可选的 db_collation。DateField:日期字段,对应 datetime.date 实例,支持 auto_now(每次保存时更新为当前时间)和 auto_now_add(创建时设为当前时间)参数。
二、字段选项
• null:设为 True 时,空字段在数据库中存为 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 支持三种数据库关联:多对一(ForeignKey)、多对多(ManyToManyField)、一对一(OneToOneField)。
Foreignkey 需要两个位置参数:关联的模型类(或 'self' 表示自关联)和 on_delete 参数。若关联尚未定义的模型,可使用模型名称字符串。
示例:Car 与 Manufacturer 的多对一关系- from django.db import models
- class Manufacturer(models.Model):
- # ...
- pass
- class Car(models.Model):
- manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
- # ...
复制代码
四、on_delete 参数详解
当被引用的对象被删除时,on_delete 决定 ForeignKey 的行为,可选值在 django.db.models 中:
• CASCADE:级联删除,被引用的对象删除时,同时删除包含 ForeignKey 的对象。
• PROTECT:通过引发 ProtectedError(IntegrityError 子类)阻止删除被引用的对象。
• RESTRICT(Django 3.1+):通过引发 RestrictedError 防止删除,但若被引用对象在同一操作中被 CASCADE 关联删除则允许。
• SET_NULL:将 ForeignKey 设为 NULL,需同时指定 null=True。
• SET_DEFAULT:设为默认值,需为 ForeignKey 设置 default。
• SET():设为指定值或可调用对象的返回值。
• DO_NOTHING:不采取措施,由数据库自身约束处理。
示例:- manufacturer = models.ForeignKey(Manufacturer, on_delete=models.SET_NULL, null=True)
- manufacturer = models.ForeignKey(Manufacturer, on_delete=models.SET_DEFAULT, default=1)
- def get_manufacturer():
- return 1
- manufacturer = models.ForeignKey(Manufacturer, on_delete=models.SET(get_manufacturer))
复制代码
五、地区自关联实战
以地区表自关联为例,模型中使用自引用 ForeignKey:- class 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_name
- class Meta:
- managed = True
- verbose_name = "地区信息"
- verbose_name_plural = verbose_name
复制代码
配合 DRF 视图实现父级下二级地区查询,并接入缓存(Redis 等):- class CityCountyView(APIView):
- authentication_classes = [BasicAuthentication]
- permission_classes = (AllowAny,)
- def get(self, request, pk):
- # 缓存键
- cache_key = 'sub_data_%s' % pk
- sub_data = cache.get(cache_key)
- if not sub_data:
- try:
- 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.set(cache_key, sub_data, 3600 * 24)
- return Response({'code': 0, 'errmsg': 'ok', 'sub_data': sub_data})
复制代码
六、动态生成模型类
有时需要根据不同参数动态创建模型。以下两种方式均可实现:
方式一:函数返回内部类- 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_name
- return MyClass
复制代码
方式二:使用 type() 动态创建- def create_task_detail_model(password_code):
- classname = f'TaskDetail_{password_code}'
- class Meta:
- db_table = classname
- return 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__,
- })
复制代码
通过以上内容,可以系统地掌握 Django 模型字段类型的选择、字段选项配置、ForeignKey 关联及 on_delete 参数的应用,并学会自关联和动态模型生成的实战技巧。 |