80 votes

Django's ModelForm unique_together validation

J'ai un Django modèle qui ressemble à ceci.

class Solution(models.Model):
    '''
    Represents a solution to a specific problem.
    '''
    name = models.CharField(max_length=50)
    problem = models.ForeignKey(Problem)
    description = models.TextField(blank=True)
    date = models.DateTimeField(auto_now_add=True)

    class Meta:
        unique_together = ("name", "problem")

J'utilise un formulaire pour l'ajout de modèles qui ressemble à ceci:

class SolutionForm(forms.ModelForm):
    class Meta:
        model = Solution
        exclude = ['problem']

Mon problème est que l' SolutionForm ne pas valider Solutions' unique_together de la contrainte et par conséquent, il renvoie un IntegrityError lorsque vous essayez d'enregistrer le formulaire. Je sais que je pourrais utiliser validate_unique afin de vérifier manuellement pour cela, mais je me demandais si il y a moyen de rattraper ce dans la validation du formulaire et retourner un formulaire d'erreur automatiquement.

Merci.

40voto

Jarmo Jaakkola Points 219

J'ai résolu le même problème en surchargeant la méthode validate_unique() du ModelForm:

 
def validate_unique(self):
    exclude = self._get_validation_exclusions()
    exclude.remove('problem') # allow checking against the missing attribute

    try:
        self.instance.validate_unique(exclude=exclude)
    except ValidationError, e:
        self._update_errors(e.message_dict)
 

Maintenant, je vérifie toujours que l'attribut non fourni sur le formulaire est toujours disponible, par exemple instance=Solution(problem=some_problem) sur l'initialiseur.

33voto

sttwister Points 765

J'ai réussi à résoudre ce problème sans modifier la vue en ajoutant une méthode propre à mon formulaire:

 class SolutionForm(forms.ModelForm):
    class Meta:
        model = Solution
        exclude = ['problem']

    def clean(self):
        cleaned_data = self.cleaned_data

        try:
            Solution.objects.get(name=cleaned_data['name'], problem=self.problem)
        except:
            pass
        else:
            raise ValidationError('Solution with this Name already exists for this problem')

        # Always return cleaned_data
        return cleaned_data
 

La seule chose que je dois faire maintenant dans la vue est d'ajouter une propriété de problème au formulaire avant d'exécuter is_valid .

32voto

Daniel Roseman Points 199743

Comme Felix le dit, ModelForms est censé vérifier la contrainte unique_together dans leur validation.

Cependant, dans votre cas, vous excluez en réalité un élément de cette contrainte de votre formulaire. J'imagine que c'est votre problème - comment la forme va-t-elle vérifier la contrainte, si la moitié n'est même pas sur la forme?

1voto

Sam Hartsfield Points 820

Avec l'aide de Jarmo réponse, la suite semble fonctionner bien pour moi (dans Django 1.3), mais c'est possible, j'ai cassé certains cas de coin (il y a beaucoup de billets entourant _get_validation_exclusions):

class SolutionForm(forms.ModelForm):
    class Meta:
        model = Solution
        exclude = ['problem']

    def _get_validation_exclusions(self):
        exclude = super(SolutionForm, self)._get_validation_exclusions()
        exclude.remove('problem')
        return exclude

Je ne suis pas sûr, mais cela semble être un Django bug pour moi... mais je dois regarder autour de la déjà des problèmes signalés.


Edit: j'ai parlé trop vite. Peut-être ce que j'ai écrit ci-dessus va travailler dans certaines situations, mais pas dans la mienne; j'ai fini à l'aide de Jarmo répondre directement.

0voto

douglaz Points 180

Vous devrez faire quelque chose comme ça:

 def your_view(request):
    if request.method == 'GET':
        form = SolutionForm()
    elif request.method == 'POST':
        problem = ... # logic to find the problem instance
        solution = Solution(problem=problem) # or solution.problem = problem
        form = SolutionForm(request.POST, instance=solution)
        # the form will validate because the problem has been provided on solution instance
        if form.is_valid():
            solution = form.save()
            # redirect or return other response
    # show the form
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X