2011-11-02 28 views
30

Tengo un modelo con un ManyToManyField similar a este (el modelo Word tiene una lengua, también):Django ManyToMany validación del modelo

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') 

Cuando se trata de añadir una nueva frase (por ejemplo, a través de administración de Django) I obtener 'Sentence' instance needs to have a primary key value before a many-to-many relationship can be used. Esto significa que no puedo acceder a self.words antes de guardarlo, pero esto es exactamente lo que estoy tratando de hacer. ¿Hay alguna manera de evitar esto para que pueda validar este modelo sin embargo? Realmente quiero validar directamente los campos del modelo.

Encontré muchas preguntas sobre esta excepción, pero no pude encontrar ayuda para mi problema. ¡Apreciaria cualquier sugerencia!

+0

Si quisiera crear una palabra, ¿cómo podría validar que estaba asociada con una oración? No tiene un campo 'oración' en su definición de modelo. – johnklawlor

+0

No todo el mundo usa formularios. Considero esto una falla masiva en Django. ¿Alguien tiene una mejor respuesta? –

Respuesta

44

No es posible hacer esta validación en el método clean del modelo, pero puede crear un modelo que pueda validar la elección de 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 

A continuación, puede personalizar su Sentence modelo de clases de administración, utilizar el formulario en la administración de Django.

class SentenceAdmin(admin.ModelAdmin): 
    form = SentenceForm 

admin.register(Sentence, SentenceAdmin) 
+6

Es lamentable ver que no hay posibilidad de validarlo directamente en el modelo. Pero hasta ahora, un ModelForm personalizado es suficiente para mí. ¡Gracias por su respuesta! – purefanatic

+0

Además, si su formulario de Sentencia también se puede ver como en línea en otro modelo (por ejemplo, un párrafo), también deberá agregar la línea 'form = SentenceForm' a la clase SentenceInline. –

+0

@purefanatic 'Model.save()' no se espera que levante 'ValidationErrors' por lo que no hay forma de validarlo directamente. – jnns

1

No se puede hacer desde el método clean en el modelo. Simplemente no es posible con la forma en que las relaciones M2M funcionan en Django. Sin embargo, puede hacer este tipo de validación en los formularios utilizados para crear un Sentence, como en el administrador o un formulario en su sitio.

Cuestiones relacionadas