2015-11-02 34 views
1

我在我的Django应用两种型号:如果相关对象存在,防止更改字段?

class Survey(models.Model): 
    survey_type = models.CharField(max_length=1, choices=SURVEY_TYPES) 

class Response(models.Model): 
    survey = models.ForeignKey(Survey) 
    response = models.TextField() 

当调查的组织者已经创建了调查,他们到达指定类型。一旦出现第一个响应,我不希望组织者能够使用站点管理员更改类型(因为响应模型中的自由文本响应字段会改变含义)。

我已经看过使用验证器,但据我可以确定,他们打算在窗体上操作,而不是在要保存的对象上操作。我找不到在它们中执行数据库查询的任何支持。

我也研究过重写保存方法,但据我可以确定的是,它不是用于验证(我不希望将任何逻辑放入我的模型中)。

我会在其他框架中完成这项工作的方式,它在ORM上方引入了一些层,允许我引入业务规则。请指教 - 这里最好的做法是什么?

+0

只是为了阐明:survey_type应该放在Survey模型上,而不是响应中。 –

回答

2

实际上,你可以使用模型级验证:

class Survey(models.Model): 
    survey_type = models.CharField(max_length=1, choices=SURVEY_TYPES) 

    def __init__(self, *args, **kwargs): 
     super().__init__(self, *args, **kwargs) 
     self._old_survey_type = self.survey_type 

    def clean(self): 
     if (self.survey_type != self._old_survey_type) \ 
       and survey_typeself.response_set.exists(): 
      raise ValidationError('Cannot modify the type of a started survey') 

不过要小心,Model.clean是不会自动当你保存一个对象时调用。当ModelForm得到验证时(因此也在管理员中),它会执行此操作,但除此之外,您必须检查它是否确实或自己调用它。

+2

这不会检查调查类型是否已更改,因此如果存在响应,它总是会引发验证错误。如果“Survey”模型中有第二个字段允许更改,那该怎么办? – Alasdair

+1

来自@Alasdair的评论是准确的 - 如果有响应,这应该只能防止“survey_type”的更改。有什么方法可以访问当前存储的字段值和传入字段值? –

+0

谢谢。我会尝试将它变成一些通用模式,我可以以某种方式将业务规则放在模型之外。需要更多地考虑它。 :-) –

0

设置surveyResponse模型独特response场由 unique together这样的:

class Response(models.Model): 
    survey = models.ForeignKey(Survey) 
    response = models.TextField() 

    class Meta: 
     unique_together = (("survey", "response"),) 
相关问题