2017-09-11 36 views
0

保存一個實例之前,我想阻止一個Django模型保存時一定約束條件沒有被滿足,給出一個驗證錯誤,這樣一個Django員工用戶知道什麼出錯。驗證計數()約束在Django

的約束是從count()使用through參數指定的中間表。

models.py

class Goal(models.Model): 
    name = models.CharField(max_length=128) 

class UserProfile(models.Model): 
    goals = models.ManyToManyField(Goal, through=UserProfileGoals, blank=True) 

class UserProfileGoal(models.Model): 
    goal = models.ForeignKey(Goals) 
    user_profile = models.ForeignKey(UserProfile) 

class UserGoalConstraint(models.Model): 
    user_profile = models.OneToOneField(UserProfile) 
    max_goals = models.PositiveIntegerField() 

所以UserGoalConstraint.max_goals給了我最大的可定義UserProfile.goal其存儲在UserProfileGoal型號數量(相同UserGoal可以更經常地被存儲到UserProfile

從幾個職位,它使用的ModelForm的 clean(),型號的 clean()pre_save信號前夕

我已閱讀並試圖解決方案NTS,

但實際的問題我已經是,我怎麼知道,如果它只是一個更新或新的數據庫條目,因爲

class UserProfileGoal(models.Model): 
    goal = models.ForeignKey(Goals) 
    user_profile = models.ForeignKey(UserProfile) 

    def clean(self): 
    goal_counter = self.user_profile.goals.count() + 1 

    try: 
     qs = UserGoalConstraint.objects.get(user_profile=self.user_profile) 
    except UserGoalConstraint.DoesNotExist: 
     raise ObjectDoesNotExist('Goal Constraint does not exist') 

    if goal_counter > qs.max_goals: 
     raise ValidationError('There are more goals than allowed goals') 

並未真正發揮作用,爲clean()也可以是一個更新+1會給我一個導致ValidationError的錯誤結果。

我的客戶應該使用Django的管理界面通過一個內嵌直接添加到目標用戶配置文件:

admin.py:

class UserProfileGoalInline(admin.TabularInline): 
    model=UserProfileGoal 

class UserProfileAdmin(admin.ModelAdmin) 
    ... 
    inlines = [UserProfileGoalInline, ] 

所以他需要很好地被告知,當他將許多目標添加到用戶配置文件中。

也許我失去了一些東西就如何解決這個問題很明顯...? 我正在尋找一個工作,並以某種方式用戶友好的解決方案(=在管理界面得到通知)。

[更新]: 我想知道請檢查是否在的clean()

if self.pk is not None: 
    return # it is not a create 
... 

開始創建或不與self.pk is None招它,我認爲這將解決這個問題... 然而,在管理員內聯中,當員工用戶同時添加多個目標時,clean()不會識別這些目標。調試輸出顯示加2個的目標,我們的目標計數器保持相同數量甚至第二個條目應該有一個,而應給出一個驗證錯誤

回答

0

由於@zaidfazil爲起始溶液:

class UserProfileGoalForm(forms.ModelForm): 
    class Meta: 
    model = UserProfileGoal 
    ... 

    def clean(self): 
    cleaned_data = super(UserProfileGoalForm, self).clean() 
    if self.instance.pk is not None: 
     return cleaned_data 
    user_profile = self.cleaned_data.get('user_profile') 
    goal_count = user_profile.goals.count() 
    goal_limit = UserGoalConstraint.objects.get(user_profile=user_profile).max_goals # removed try catch for get for easier reading 
    if goal_count >= goal_limit: 
     raise ValidationError('Maximum limit reached for goals') 
    return cleaned_data 

然而,這不處理內嵌在用戶配置管理界面:clean()將不能正確處理,如果你添加多個Goal同時按下保存。

所以我申請UserProfileGoalForm到內聯和定義max_num

class UserProfileGoalInline(admin.TabularInline): 
    model=UserProfileGoal 
    form = UserProfileGoalForm 

    def get_max_num(self, request, obj=None, **kwargs): 
    if obj is None: 
     return 
    goal_limit = UserGoalConstraint.objects.get(training_profile=obj).max_goals 
    return goal_limit # which will overwrite the inline's max_num attribute 

現在我的客戶只能從UserGoalConstraint添加在最大的max_goals價值,也爲UserProfileGoal可能的管理形式將處理約束:

class UserProfileGoalAdmin(admin.ModelAdmin): 
    form = UserProfileGoalForm 
0

你可以在ModelFormclean方法處理它,

class GoalForm(forms.ModelForm): 
    class Meta: 
     model = Goal 
     ..... 

    def clean(self): 
     cleaned_data = super(GoalForm, self).clean() 
     if self.instance.pk is not None: 
      return cleaned_data 
     goal_limit = self.user_profile.usergoalconstraint.max_goals 
     goal_count = self.user_profile.goals.count() 
     if goal_count >= goal_limit: 
      raise ValidationError("Maximum limit reached for goals") 
     return cleaned_data 
+0

我試過你對我的真實例子的建議。但是我已經在「GoalForm」類中掙扎了。 '目標'可以在沒有'UserProfile'的情況下創建。我想你的意思是'UserProfileGoal'?此方法也不起作用,請參閱問題中的UPDATE部分。然而'ModelForm'爲我提供瞭解決方案,我將作爲答案發布。 – Dowi