Django无外键关联两模型 能否用多态关联实现Services访问PackageServices
答案
完全可以通过Django的泛型(多态)关联实现该需求,你现有的两个模型已经预置了多态关联必需的类型存储、关联ID存储字段,无需修改表结构,仅需调整模型代码即可,操作步骤如下:
前置准备
确保你的Django项目INSTALLED_APPS配置中已经启用了官方自带的泛型关联支持模块:
INSTALLED_APPS = [ # 其他原有配置 'django.contrib.contenttypes', ]
步骤1:修改PackageServices模型,配置正向多态关联
在PackageServices模型中添加GenericForeignKey定义,绑定现有assignable_type、assignable_id作为多态关联的标识字段:
from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType class PackageServices(models.Model): # --- 原有所有字段保持不变 --- id = models.BigAutoField(primary_key=True) billing_package = models.ForeignKey(BillingPackages, models.DO_NOTHING, blank=True, null=True) assignable_type = models.CharField(max_length=500, blank=True, null=True) assignable_id = models.BigIntegerField(blank=True, null=True) quantity = models.IntegerField() created_at = models.DateTimeField() updated_at = models.DateTimeField() # --- 新增多态关联配置 --- assignable = GenericForeignKey(ct_field="assignable_type", fk_field="assignable_id") class Meta: managed = False db_table = 'package_services'
步骤2:修改Services模型,配置反向多态关联
在Services模型中添加GenericRelation反向关联字段,实现直接从Services实例访问关联的PackageServices数据:
from django.contrib.contenttypes.fields import GenericRelation class Services(models.Model): # --- 原有所有字段保持不变 --- id = models.BigAutoField(primary_key=True) medical_unit = models.ForeignKey(MedicalUnits, models.DO_NOTHING, related_name='services_medical_unit', blank=True, null=True) created_at = models.DateTimeField() updated_at = models.DateTimeField() name = models.CharField(max_length=500, blank=True, null=True) billing_code = models.CharField(max_length=500, blank=True, null=True) department_id = models.IntegerField(blank=True, null=True) assignable_type = models.CharField(max_length=500, blank=True, null=True) assignable_id = models.BigIntegerField(blank=True, null=True) department_service_id = models.IntegerField(blank=True, null=True) user_id = models.IntegerField(blank=True, null=True) is_active = models.BooleanField(blank=True, null=True) ward_id = models.IntegerField(blank=True, null=True) # --- 新增反向多态关联配置 --- # 将代码中的your_app_name替换为两个模型所在的Django应用名称 related_package_services = GenericRelation( 'your_app_name.PackageServices', content_type_field='assignable_type', object_id_field='assignable_id', related_query_name='service' ) class Meta: managed = False db_table = 'services'
使用示例
配置完成后即可直接通过ORM访问关联数据:
- 获取单条Services记录关联的所有PackageServices数据:
service = Services.objects.get(id=xxx) related_packages = service.related_package_services.all()
- 反向筛选关联了指定Services的PackageServices记录:
target_service = Services.objects.get(id=xxx) packages = PackageServices.objects.filter(service=target_service)
注意事项
- 请确认数据库中
package_services表的assignable_type字段存储的Services模型标识格式为{应用名}.Services,如果存储格式为纯模型名等其他格式,需自行调整匹配逻辑 - 两个模型均配置了
managed=False,无需执行迁移操作,不会修改现有表结构
内容的提问来源于stack exchange,提问作者Adnan Roy
相关产品推荐
相关产品推荐

