You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 12:27:01