2011-11-02 27 views
30

Ho un modello con una ManyToManyField simile a questo (il modello di Word ha un linguaggio, troppo):Django ManyToMany validazione del modello

class Sentence(models.Model): 
    words = models.ManyToManyField(Word) 
    language = models.ForeignKey(Language) 
    def clean(self): 
     for word in self.words.all(): 
      if word.language_id != self.language_id: 
       raise ValidationError('One of the words has a false language') 

Quando si tenta di aggiungere una nuova frase (per esempio attraverso Django admin) I ottenere 'Sentence' instance needs to have a primary key value before a many-to-many relationship can be used. Ciò significa che non posso accedere a self.words prima di salvarlo, ma questo è esattamente ciò che sto cercando di fare. C'è un modo per ovviare a questo in modo da poter validare questo modello, tuttavia? Voglio davvero convalidare direttamente i campi del modello.

Ho trovato molte domande relative a questa eccezione, ma non sono riuscito a trovare aiuto per il mio problema. Gradirei qualche suggerimento!

+0

Se si desidera creare una parola, come si convaliderà che è stata associata a una frase? Non ha un campo 'frase' nella sua definizione del modello. – johnklawlor

+0

Non tutti usano moduli. Considero questo un enorme difetto in Django. Qualcuno ha una risposta migliore? –

risposta

44

Non è possibile eseguire questa convalida nel metodo clean del modello, ma è possibile creare un modulo modello che possa convalidare la scelta di words.

from django import forms 

class SentenceForm(forms.ModelForm): 
    class Meta: 
     model = Sentence 

    def clean(self): 
     """ 
     Checks that all the words belong to the sentence's language. 
     """ 
     words = self.cleaned_data.get('words') 
     language = self.cleaned_data.get('language') 
     if language and words: 
      # only check the words if the language is valid 
      for word in words: 
       if words.language != language: 
        raise ValidationError("The word %s has a different language" % word) 
     return self.cleaned_data 

È quindi possibile personalizzare il Sentence modello di classe di amministrazione, di utilizzare il modulo in admin Django.

class SentenceAdmin(admin.ModelAdmin): 
    form = SentenceForm 

admin.register(Sentence, SentenceAdmin) 
+6

È spiacevole vedere che non esiste la possibilità di convalidarlo direttamente nel modello. Ma finora per me è sufficiente un ModelForm personalizzato. La ringrazio per la risposta! – purefanatic

+0

Inoltre, se il tuo modulo di frase può essere visto anche come un inline in un altro modello (ad esempio un paragrafo), dovrai aggiungere anche la riga 'form = SentenceForm' alla classe SentenceInline. –

+0

@purefanatic 'Non è previsto che Model.save()' aumenti 'ValidationErrors', quindi non c'è modo di convalidarlo direttamente. – jnns

1

Non puoi farlo dal metodo clean sul modello. Semplicemente non è possibile con il modo in cui le relazioni M2M funzionano in Django. Tuttavia, puoi eseguire questo tipo di convalida sui moduli utilizzati per creare uno Sentence come nell'admin o in un modulo sul tuo sito.

Problemi correlati