Django模型外键ForeignKey的参数及其解析
Django模型外键ForeignKey的参数及其解析
目录
场景引言
Django后台数据库的表之间的关系能够通过外键进行关联。今天通过手头在做的一个与任务分配相关的应用来聊一聊表与表之间的关联情况,并重点针对Django模型外键ForeignKey进行解析。事实上,对于数据表之间的关联可以分为几种情况:
一对一:该类情况的场景可以考虑项目表与项目元数据表的关联,比如某个项目表需要存储与项目本身相关的创建人、创建时间、项目描述及其他不重要的元数据信息。这个时候可以将项目表作为主表,其他不重要信息存储到子表内。在django内靠OneToField()方法实现:
project = models.OneToOneField("Project", on_delete=models.CASCADE)
一对多:该类情况的场景可以考虑项目表与任务表的关联,比如同一项目可能同时管理多个任务,单个任务从属于单个项目。这个时候可以将项目表作为主表,任务表作为子表。在django内如下实现(ForeignKey),这也是本文我们要聊的重点:
project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True,)
多对多:该类情况的场景可以考虑任务表与数据表的关联,比如同一任务可能同时处理多个图片,一张图片也可被多个任务使用。django为这种多对多的场景提供了ManyToMany()的方法。
ForeignKey方法简介
# 外键示例代码
project = models.ForeignKey(to=Project, # 要关联的表名
on_delete=models.CASCADE, # 删除关联数据时,当前表关联数据的行为
null=True, # 控制列是否能为null
blank=True, # 控制列是否能为空
related_name="tasks", # 反向操作字段名
related_query_name="task") # 反向操作连接前缀
以下针对几个常用的重要的参数进行解析:
to:要关联的表的名称,即主表名称(当前表作为子表);
on_delete:删除主表内的关联数据时,当前子表关联数据的行为,存在以下几类情况:
# models.CASCADE:删除主表中的关联数据,相应的子表中的关联数据也被删除
# models.DO_NOTHING,删除关联数据,引发错误IntegrityError
# models.PROTECT,删除关联数据,引发错误ProtectedError
# models.SET_NULL:删除主表的关联数据,与之关联的值设置为null(前提是字段设置为可null)
# models.SET_DEFAULT:删除关联数据,与之关联的值设置为默认值(前提是字段需要设置默认值)
# 参考文献:https://blog.csdn.net/qq_19691995/article/details/102678264?spm=1001.2101.3001.6650.5&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-5-102678264-blog-51861868.235%5Ev38%5Epc_relevant_anti_t3_base&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-5-102678264-blog-51861868.235%5Ev38%5Epc_relevant_anti_t3_base&utm_relevant_index=6
related_name:该参数可能无法很直观的理解,可以举下面的项目和任务的例子帮助理解;
class Project(models.Model):
"""主表"""
name = SafeCharField(max_length=256)
owner = models.ForeignKey(User, null=True, blank=True,
on_delete=models.SET_NULL, related_name="+")
assignee = models.ForeignKey(User, null=True, blank=True,
on_delete=models.SET_NULL, related_name="+")
bug_tracker = models.CharField(max_length=2000, blank=True, default="")
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=32, choices=StatusChoice.choices(),
default=StatusChoice.ANNOTATION)
organization = models.ForeignKey(Organization, null=True, default=None,
blank=True, on_delete=models.SET_NULL, related_name="projects")
source_storage = models.ForeignKey('Storage', null=True, default=None,
blank=True, on_delete=models.SET_NULL, related_name='+')
target_storage = models.ForeignKey('Storage', null=True, default=None,
blank=True, on_delete=models.SET_NULL, related_name='+')
class Task(models.Model):
"""子表"""
objects = TaskQuerySet.as_manager()
project = models.ForeignKey(Project, on_delete=models.CASCADE,
null=True, blank=True, related_name="tasks",
related_query_name="task")

现在我们获取一个项目下所有的任务,可以如上图操作,也就是通过Project对象.related_name.all()进行访问。而当未定义参数related_name时,应该通过Project对象.task_set.all()进行访问,也就是说命名规则是:子表模型名称_set。
此外还有个需要注意的地方,如果我们想禁止这种反向引用的访问方法,可以设置related_name="+",例如上方Task模型的owner字段就使用该方法,我们尝试访问下来验证是否如此。

related_query_name:我们现在来如法理解参数related_query_name的含义。假设我们现在想查询任务名称为包含test-2的项目,可以进行如下操作:

现在我们观察filter的参数实际上的命名规则是:子模型名称__筛选字段名称。那假如参数related_query_name我们设置为默认值None呢,那过滤器将使用related_name的名称,即:related_query_name__name,即related_query_name__筛选字段名称。
参考文献:
1、https://www.cnblogs.com/limaomao/p/9273407.html
2、https://blog.csdn.net/hpu_yly_bj/article/details/78939748
3、※ https://www.cnblogs.com/xingxia/p/django_model_foreignKey.html
更多推荐

所有评论(0)