【问题标题】:Model can have a ForeignKey with one of the two models模型可以具有两个模型之一的 ForeignKey
【发布时间】:2018-08-08 15:28:58
【问题描述】:

我需要一些帮助来解决我自己无法解决的问题。因此,在此模型中,租赁文档可以有一个带 Building 或 Property 的 ForeignKey。

我们可能会就整栋建筑物或该建筑物内的单个物业签订租赁协议。在前一种情况下,租赁文件适用于建筑物,而在后一种情况下,它们仅适用于房产。

我使用 content_types 添加通用外键,但现在我不知道如何将自动完成字段添加到 contenttype 和下拉列表中, 我只看到管理形式的建筑物和财产。我想查看建筑物名称和属性名称。

我了解了 Django 2.0 中的自动完成字段,这很棒,但我不知道在这种特殊情况下如何使用类似的东西,或者是否有更好的方法来做到这一点?

models.py:

class TenancyDocument(models.Model):

    KINDS = Choices('Tenancy Agreement', 'Stamp Duty', 'Inventory List')

    id = FlaxId(primary_key=True)
    kind = StatusField(choices_name='KINDS')
    start_date = models.DateField(blank=True, null=True)
    end_date = models.DateField(blank=True, null=True)

    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

    content_type_limit = Q(
        app_label='properties', model='building') | Q(
            app_label='properties', model='property')

    content_type = models.ForeignKey(
        ContentType,
        limit_choices_to=content_type_limit,
        on_delete=models.CASCADE,
        verbose_name='Lease type'
        )

    object_id = FlaxId(blank=True, null=True)
    content_object = GenericForeignKey('content_type', 'object_id')

    def __str__(self):
        return self.kind

admin.py:

@admin.register(TenancyDocument)
class TenancyDocumentAdmin(admin.ModelAdmin):
    list_display = ('id', 'kind', 'start_date', 'end_date','content_type')
    list_filter = ('kind',)

【问题讨论】:

    标签: django django-models django-admin django-contenttypes django-2.0


    【解决方案1】:

    似乎通用外键总是比它的价值更麻烦。它需要一个简单的概念,一个关系连接,并试图让它变得聪明,但是像自动完成这样的下游包就不起作用了。

    我最终切换到两个单独的外键,然后向类添加属性以从正确的相关记录中提取字段。

    class TenancyDocument(models.Model):
        building = models.ForeignKey(Building, ondelete='CASCADE', null=True, blank=True)
        prop = models.ForeignKey(Property, ondelete='CASCADE', null=True, blank=True)
    
        def clean(self):
            if not self.building and not self.prop:
                raise ValidationError('Must provide either building or property.')
            if self.building and self.prop:
                raise ValidationError('Select building or property, but not both.')
            super().clean()
    

    【讨论】:

    • 我喜欢这种方法,因为它是明确的,但是它增加了复杂性,因为您的代码必须围绕 FK 填充和表单交互等管理业务规则。此外,这种方法增加了循环导入作为您的代码库的风险,并且项目复杂性增加。它可能会迫使您最终重写或将您的代码分散到许多不同的模块或应用程序中(我以前不小心走上了这条路,这很讨厌)。
    猜你喜欢
    • 1970-01-01
    • 2016-09-06
    • 2018-06-04
    • 2022-06-29
    • 2012-01-02
    • 1970-01-01
    • 1970-01-01
    • 2019-09-26
    • 1970-01-01
    相关资源
    最近更新 更多