ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Django 模型如何定义 CompositePrimaryKey 复合主键并处理关联

Django 模型如何定义 CompositePrimaryKey 复合主键并处理关联 Django 模型如何定义 CompositePrimaryKey 复合主键并处理关联【免费下载链接】djangoThe Web framework for perfectionists with deadlines.项目地址: https://gitcode.com/GitHub_Trending/dj/django当数据库设计无法用单个字段做主键时例如“订单明细”需要同时由产品 ID 和订单号唯一确定一行在 Django 中可以通过CompositePrimaryKey为模型定义由多个字段组成的复合主键。该特性在 Django 5.2 中引入见 5.2 版本说明在 Django 6.0 中又补齐了QuerySet.raw支持以及对复合主键结果的子查询 lookup 支持见 6.0 版本说明。本文覆盖两个连续任务在模型上正确声明复合主键以及处理其他模型指向该模型的关联——因为关系字段目前不支持引用复合主键模型需要用ForeignObject作为替代路径。在模型上声明 CompositePrimaryKeyCompositePrimaryKey是一个虚拟字段用于定义复合主键。它必须被定义为模型的pk属性否则检查框架会报告fields.E013CompositePrimaryKeymust be namedpk见 checks 文档。参数*field_names是组成主键的字段名的位置参数列表Django 建表时会创建对应的复合主键如PRIMARY KEY (product_id, order_id)。字段定义参考 fields 文档from django.db import models class Product(models.Model): name models.CharField(max_length100) class Order(models.Model): reference models.CharField(max_length20, primary_keyTrue) class OrderLineItem(models.Model): pk models.CompositePrimaryKey(product_id, order_id) product models.ForeignKey(Product, on_deletemodels.CASCADE) order models.ForeignKey(Order, on_deletemodels.CASCADE) quantity models.IntegerField()这段示例直接来自 复合主键主题文档。注意pk参数中写的是product_id、order_id即两个ForeignKey在数据库中实际产生的列名而不是外键字段的属性名。复合主键的运行表现声明后实例的pk是一个tuple。以下交互输出为文档中的示例结果用于判断行为是否符合预期 product Product.objects.create(nameapple) order Order.objects.create(referenceA755H) item OrderLineItem.objects.create(productproduct, orderorder, quantity1) item.pk (1, A755H)可以把tuple直接赋给pk属性这会把各成员字段的值一并设置 item OrderLineItem(pk(2, B142C)) item.pk (2, B142C) item.product_id 2 item.order_id B142C过滤也接受tuple OrderLineItem.objects.filter(pk(1, A755H)).count() 1在应用代码中识别主键成员时不要依赖字段的primary_key属性复合主键模型的各成员字段该属性均为False为了保持“一个模型至多一个字段primary_keyTrue”的不变量。应改用Options.pk_fields属性见 meta 文档 Product._meta.pk_fields [django.db.models.fields.AutoField: id] OrderLineItem._meta.pk_fields [ django.db.models.fields.ForeignKey: product, django.db.models.fields.ForeignKey: order ]上面的输出同样是文档示例展示单字段模型与复合主键模型返回值的差异。处理指向复合主键模型的关联关系字段包括ForeignKey和泛型关系GenericForeignKey目前不支持引用复合主键模型。对OrderLineItem写下面这种ForeignKey是不支持的检查框架会报告fields.E347Field defines a relation involving model which has aCompositePrimaryKeyand such relations are not supported# 不支持ForeignKey 无法引用复合主键模型 class Foo(models.Model): item models.ForeignKey(OrderLineItem, on_deletemodels.CASCADE)文档给出的替代路径是ForeignObject自己声明指向复合主键各列的字段再用from_fields/to_fields建立关联class Foo(models.Model): item_order_id models.CharField(max_length20) item_product_id models.IntegerField() item models.ForeignObject( OrderLineItem, on_deletemodels.CASCADE, from_fields(item_order_id, item_product_id), to_fields(order_id, product_id), )使用这条路径前要知道ForeignObject与ForeignKey的三个差异均来自 主题文档它不会在数据库创建额外列如item_id、外键约束或索引on_delete参数会被忽略。也就是说引用完整性由你自己声明的字段承载而不是数据库约束。已建表模型的迁移限制Django 不支持在表创建之后通过迁移切换到或从复合主键也不支持向复合主键中增删字段。如果已有单主键表需要改为复合主键按对应数据库后端的说明在数据库层面完成之后在模型上补加CompositePrimaryKey让 Django 能识别并正确处理该主键。对于主键字段上的迁移操作如AddField、AlterFieldDjango 不支持执行但makemigrations仍会检测到这些变更。为避免报错文档建议用--fake应用这类迁移或者使用SeparateDatabaseAndState在单个操作中同时执行后端相关迁移和 Django 生成的状态迁移。此外检查框架的models.E048会拦截constraints/indexes/unique_together引用CompositePrimaryKey字段名的写法CompositePrimaryKeys are not supported for that option声明相关约束时要避开这种写法。数据库函数、表单与校验中的边界这几处行为直接来自文档遇到报错时可对照判断数据库函数多数聚合只接受单个表达式Max(pk)这类对复合主键的引用会抛ValueError因为pk由多个列表达式组成Count是例外。文档示例Max(order_id)合法Max(pk)抛ValueErrorCount(pk)合法。ModelForms复合主键是虚拟字段不对应单个数据库列因此fields __all__的 ModelForm 不包含pk表单字段把pk显式写成表单字段会抛FieldErrorunknown field。由于修改已存在对象的主键再保存会新建对象复合主键同样如此文档建议对所有主键字段设置editable False将其排除出 ModelForm。模型校验pk只是虚拟字段在clean_fields的exclude参数里写pk不生效要跳过复合主键各字段的校验需逐字段列出。validate_unique则可以直接用exclude{pk}跳过唯一性检查。Django admin复合主键模型目前不能注册到 admin。查询增强Django 6.0 起QuerySet.raw支持复合主键模型返回复合主键的子查询可以用作__in以外的 lookup如__exact目标。验证定义是否正确完成声明后可以按顺序核对运行 Django 检查框架manage.py check。若CompositePrimaryKey没有命名为pk会看到fields.E013若有关系字段指向复合主键模型会看到fields.E347错误码含义见 checks 文档。在 shell 中创建对象并查看item.pk确认返回由各成员列值组成的tuple与上文示例结果形态一致。用Model._meta.pk_fields确认返回的字段列表包含复合主键引用的所有字段。执行objects.filter(pk(...))的tuple过滤确认命中预期行。目前这一特性的已知边界是关系字段含泛型关系与 Django admin 的支持仍在完善中文档明确提示这些能力预计在后续版本提供引用复合主键模型时请固定使用ForeignObject路径而不是等待ForeignKey支持。【免费下载链接】djangoThe Web framework for perfectionists with deadlines.项目地址: https://gitcode.com/GitHub_Trending/dj/django创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表