Django 如何约束或选择一个或其他外键?

Django 如何约束或选择一个或其他外键?,django,database,database-design,foreign-keys,Django,Database,Database Design,Foreign Keys,问题是概念性的(数据库关系),所以这里不关注语言,但我使用的是Python和Django 我有3个模型/表格: 公司 顾客 地址 例如 我希望地址属于客户或公司,但不能同时属于两者。 我知道我可以简单地创建2个地址类,例如CustomerAddress、CompanyAddress,每个类都有正确的外键: class Company(models.Model): name = models.CharField(max_lenght=100) #example class Custo

问题是概念性的(数据库关系),所以这里不关注语言,但我使用的是Python和Django

我有3个模型/表格:

  • 公司
  • 顾客
  • 地址
例如

我希望地址属于客户或公司,但不能同时属于两者。
我知道我可以简单地创建2个地址类,例如CustomerAddress、CompanyAddress,每个类都有正确的外键:

class Company(models.Model):
    name = models.CharField(max_lenght=100) #example

class Customer(models.Model):
    name = models.CharField(max_lenght=100) #example

class CompanyAdress(models.Model):
    country = models.CharField(max_lenght=100) #example
    state = models.CharField(max_lenght=100) #example
    company = models.ForeignKey(Company, on_delete=models.PROTECT)

class CustomerAdress(models.Model):
    country = models.CharField(max_lenght=100) #example
    state = models.CharField(max_lenght=100) #example
    customer = models.ForeignKey(Company, on_delete=models.PROTECT)
但我不想这么做有两个原因:

  • 重复的代码和django admin panel中我将有两个独立的地址列表这一事实没有多大意义,因为所有地址在结构上都是相同的。我可以修复创建基类、继承基类等重复的代码,但在管理面板中仍然有两个列表
  • 将来,我可能会遇到同样的概念性问题,但会更加复杂,例如,300个类中的某些东西和1个类,其中一个类应该只有一个外键
  • 那么,我该怎么办


    PS:我不会说英语,如果我犯了一些英语错误,非常抱歉。

    您可以尝试将外键设置为null=True,并根据需要通过视图控制数据库中的输入:

    class Address(models.Model):
        country = models.CharField(max_lenght=100) 
        state = models.CharField(max_lenght=100)
        company = models.ForeignKey(Company, on_delete=models.PROTECT, null=True)
        customer = models.ForeignKey(Customer, on_delete=models.PROTECT, null=True)
    

    您可以尝试将外键设置为null=True,并根据需要通过视图控制数据库中的输入:

    class Address(models.Model):
        country = models.CharField(max_lenght=100) 
        state = models.CharField(max_lenght=100)
        company = models.ForeignKey(Company, on_delete=models.PROTECT, null=True)
        customer = models.ForeignKey(Customer, on_delete=models.PROTECT, null=True)
    

    有关UML图,请查看Martin Fowler的。下面是一个DB模型

    ——地址ADR存在。
    --
    地址{ADR}
    PK{ADR}
    
    一方
    是个人或组织的通用术语;鉴别器
    TYP
    用于区分两者

    ——参与方类型的参与方PTY位于ADR地址。
    --
    当事人{PTY,TYP,ADR}
    PK{PTY}
    SK{PTY,TYP}
    检查{P',O'}中的类型
    FK{ADR}引用地址{ADR}
    
    --个人,存在类型为“P”的参与方PTY。
    --
    人{PTY,TYP}
    PK{PTY}
    检查类型='P'
    FK{PTY,TYP}引用方{PTY,TYP}
    
    --组织,存在类型为“O”的参与方PTY。
    --
    组织{PTY,TYP}
    PK{PTY}
    检查类型='O'
    FK{PTY,TYP}引用方{PTY,TYP}
    
    注:

    所有属性(列)不为空
    PK=主键
    AK=备用键(唯一)
    SK=正确的超级键(唯一)
    FK=外键
    

    关于子类型的一句话。实现子类型约束的正确方法是使用断言(
    createassertion
    ),但它在主要数据库中仍然不可用。我使用的是
    FKs
    ,与所有其他替代方法一样,它并不完美。关于SO和SE-DBA,人们争论了很多,什么更好。我鼓励您也检查其他方法。

    有关UML图,请查看Martin Fowler的。下面是一个DB模型

    ——地址ADR存在。
    --
    地址{ADR}
    PK{ADR}
    
    一方
    是个人或组织的通用术语;鉴别器
    TYP
    用于区分两者

    ——参与方类型的参与方PTY位于ADR地址。
    --
    当事人{PTY,TYP,ADR}
    PK{PTY}
    SK{PTY,TYP}
    检查{P',O'}中的类型
    FK{ADR}引用地址{ADR}
    
    --个人,存在类型为“P”的参与方PTY。
    --
    人{PTY,TYP}
    PK{PTY}
    检查类型='P'
    FK{PTY,TYP}引用方{PTY,TYP}
    
    --组织,存在类型为“O”的参与方PTY。
    --
    组织{PTY,TYP}
    PK{PTY}
    检查类型='O'
    FK{PTY,TYP}引用方{PTY,TYP}
    
    注:

    所有属性(列)不为空
    PK=主键
    AK=备用键(唯一)
    SK=正确的超级键(唯一)
    FK=外键
    

    关于子类型的一句话。实现子类型约束的正确方法是使用断言(
    createassertion
    ),但它在主要数据库中仍然不可用。我使用的是
    FKs
    ,与所有其他替代方法一样,它并不完美。关于SO和SE-DBA,人们争论了很多,什么更好。我建议您也检查其他方法。

    为什么不在公司和客户型号中添加外键
    地址
    字段?搜索
    派对型号
    。共同模式。或者超级类型、子类型为什么不在公司和客户型号中添加外键
    地址
    字段?搜索
    派对型号
    。共同模式。或者超级类型,子类型我认为正确的答案我认为正确的答案