限制子类的ForeignKey选择

时间:2015-02-24 22:43:09

标签: python django django-models

我有一套模型,关于餐馆和运营它们的厨师 *

class Chef(models.Model):
    name = models.TextField()

class Restaurant(models.Model):
    name = models.TextField()
    chef = models.ForeignKey(Chef)

class FrenchChef(Chef):
    angryness = models.PositiveIntegerField()

class FrenchRestaurant(Restaurant):
    region = models.TextField()

不幸的是,这个当前模型意味着非FrenchChef可以运行FrenchRestaurant

我是否可以将子类模型的ForeignKey的查询集限制为父类可用的子集?

*我的建模实际上并不是厨师和餐馆,但这更容易解释。这可能看起来不太明显,但ChefFrenchChef确实需要以不同方式建模。

3 个答案:

答案 0 :(得分:1)

如果您关注

,可以尝试定义干净的方法
class FrenchRestaurant(models.Model):
    # ...

    def clean(self):
        if not isinstance(self.chief, FrenchChief):
            raise ValidationError()

答案 1 :(得分:1)

通过这样做:

class FrenchChef(Chef):
    angryness = models.PositiveIntegerField()

除了Chef之外,您还要在数据库中再创建一个表。在此处阅读有关模型继承类型的信息:https://docs.djangoproject.com/en/1.7/topics/db/models/#model-inheritance

我认为你应该为厨师创建一个表,为餐馆创建一个表,这里不需要继承:

class Chef(models.Model):
    name = models.TextField()
    # all chefs with not null angryness is frenchchefs...
    # but you can add some field to explicitly save chef type
    angryness = models.PositiveIntegerField(null=True)

class Restaurant(models.Model):
    name = models.TextField()
    chef = models.ForeignKey(Chef)
    region = models.TextField()
    # rtype added here but it is not necessarily
    rtype = models.IntegerField(choices=restaurans_types)

选择的限制(过滤)应采用以下形式:

class FrenchRestaurantForm(forms.ModelForm):
    def __init__(self, *args,**kwargs):
        super (FrenchRestaurantForm, self ).__init__(*args,**kwargs)
        self.fields['chef'].queryset = Chef.objects.filter(
            angryness__gte=MIN_ANGRYNESS_LVL)
    def save(commit=True):
        model = super(FrenchRestaurantForm, self).save(commit=False)
        model.rtype = SomeFrenchRestTypeConst
        if commit:
            model.save()
        return model
    class Meta:
        model = Restaurant

要检查用户输入,您可以在表单字段https://docs.djangoproject.com/en/1.7/ref/forms/validation/#cleaning-a-specific-field-attribute

中添加干净方法

如果故意创建了FrenchChef(它是数据库中的不同表),那么您应该将其添加到FrenchRestaurant(另一个表 - >另一个fk id):

class FrenchRestaurant(Restaurant):
    region = models.TextField()
    frenchchef = models.ForeignKey(FrenchChef)

答案 2 :(得分:1)

就像我在评论中提到的那样,你可以看看django模型数据验证方法。刚刚在这篇文章中找到另一个注释。 Adding Custom Django Model Validation

以下是执行验证后的常见模式。代码段是从上面提到的帖子中的一个答案中提取的。由https://stackoverflow.com/users/247542/cerin

回答



class BaseModel(models.Model):

    def clean(self, *args, **kwargs):
        # add custom validation here
        super(BaseModel, self).clean(*args, **kwargs)

    def save(self, *args, **kwargs):
        self.full_clean()
        super(BaseModel, self).save(*args, **kwargs)




您可以继续阅读有关django文档中验证的更多信息。

如果您正在寻找可能存在的任何基于类型/固有的解决方案。我不确定它们是否存在。我还是想看看是否有人在django中提出这样的规定。