如何将Django模型限制为几种可能的关系之一?

时间:2012-12-28 23:01:49

标签: python django

鉴于这些模型,我如何防止将FinancialTransaction分配给多个Thing?

换句话说,如果ThingOne有一个FinancialTransaction,那么ThingTwo或ThingThree就无法与之建立关系。

如何在管理员中强制执行此操作?我当然可以使用Inlines在SomeThing管理员中获得Thing *,但这允许我设置多个Thing *。

我的第一个倾向是我的建模是错误的,并且所有的东西都应该用一个模型来表示,但它们肯定是不同类型的东西。

from django.db import models


class ThingOne(models.Model):
    name = models.CharField(max_length=20)

    some_things = models.ForeignKey('FinancialTransaction', blank = True, null = True)


class ThingTwo(models.Model):
    name = models.CharField(max_length=20)

    some_things = models.ForeignKey('FinancialTransaction', blank = True, null = True)
    thingone = models.ForeignKey(ThingOne)


class ThingThree(models.Model):
    name = models.CharField(max_length=20)

    some_things = models.ForeignKey('FinancialTransaction', blank = True, null = True)
    thingtwo = models.ForeignKey(ThingTwo)


class FinancialTransaction(models.Model):
    value = models.IntegerField()

1 个答案:

答案 0 :(得分:1)

您可以使用通用外键在FinancialTransaction上建立关系。

https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#id1

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic

class FinatialTransation(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

然后关系存在于一个地方,只能有一个。

然后从FinancialTransaction检查对象ID和对象ContentType并相应地查找。

ft = FinancialTransaction.objects.get(...)
thing = ft.content_type.get_object_for_this_type(id=ft.object_id)

此外,您可以使用以下内容将GenericForeignKey限制为某些内容类型:

class FinatialTransation(models.Model):
    limit = models.Q(
        models.Q(app_label='yourappsname', model='ThingOne') | models.Q(app_label='yourappsname', model='ThingTwo') | models.Q(app_label='yourappsname', model='ThingThree')
    )
    content_type = models.ForeignKey(ContentType, limit_choices_to=limit)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')