Tengo dos objetos que están conectados entre sí por una ForeignKey.
class Question(models.Model):
text = models.Charfield()
class AnswerOption(models.Model):
text = models.Charfield()
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name="options")
Cuando se crea Question
en la interfaz de administración, estoy usando un formulario en línea para AnswerOptions
para que puedan crearse al mismo tiempo. Me gustaría realizar alguna validación en el Question
y necesita acceso al nuevo AnswerOptions
para tomar la decisión.
Agregué un método clean
a Question
pero la propiedad options
está vacía.
¿Cuál es la forma correcta de validar Question
?
[EDITAR] Dejó en claro que Question
necesita acceso a AnswerOptions
para poder validar todo.
[EDITAR] Se agregó una referencia explícita al uso de un InlineForm para AnswerOptions
en la interfaz de administración.
2 respuestas
Esto es lo que he descubierto:
Al crear formularios en línea en la interfaz de administración, Django crea un Formset
para manejar los múltiples formularios. (El ejemplo aquí es el mismo que mi caso de uso)
Formsets
tienen un método clean()
como otros formularios y tienen una propiedad forms
para acceder a los formularios secundarios. Al igual que los formularios normales, tienen una propiedad instance
que se refiere a la clase 'base' y los formularios individuales tienen una propiedad instance
que le proporciona una instancia de los datos recién enviados.
Poniendolo todo junto:
# models.py
class Question(models.Model):
text = models.Charfield()
class AnswerOption(models.Model):
text = models.Charfield()
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name="options")
# admin.py
from django.contrib import admin
from django.forms.models import BaseInlineFormSet
class AnswerOptionFormset(BaseInlineFormset):
def clean(self):
super().clean() # See note in docs about calling this to check unique constraints
#self.instance -> Question, with all the newly submitted, and validated, data.
#self.forms -> iterator over all the submitted AnswerOption forms
#for f in self.forms:
# f.instance -> instance of AnswerOption containing the new validated data
#Note: self.instance.options will refer to the previous AnswerOptions
#raise ValidationError for anything that is wrong.
#It is also possible to modify the data in self.instance or form.instance instead.
class AnswerOptionInline(admin.TabularInline):
formset = AnswerOptionFormset # note formset on AnswerOption NOT QuestionAdmin
class QuestionAdmin(admin.ModelAdmin):
inlines = [AnswerOptionInline]
Lo haría a través de un formulario de Django, que tiene una interfaz más robusta para validación. El método clean
en su formulario es el lugar para este tipo de validación.
# forms.py
from django import forms
from .models import Question
class QuestionForm(forms.Form):
text = models.Charfield()
class Meta:
model = Question
def clean(self):
options = self.cleaned_data['options']
if not option.are_ok:
raise forms.ValidationError
# admin.py
from django import admin
from .forms import QuestionForm
class QuestionAdmin(admin.ModelAdmin):
form = QuestionForm
...
De los documentos:
El método clean () de la subclase de formularios puede realizar una validación que requiere acceso a múltiples campos de formulario. Aquí es donde puede poner controles como "si se proporciona el campo A, el campo B debe contener una dirección de correo electrónico válida". Este método puede devolver un diccionario completamente diferente si lo desea, que se utilizará como la limpieza de datos.
Preguntas relacionadas
Nuevas preguntas
django
Django es un marco de aplicación web del lado del servidor de código abierto escrito en Python. Está diseñado para reducir el esfuerzo requerido para crear sitios web y aplicaciones web complejos basados en datos, con un enfoque especial en menos código, sin redundancia y siendo más explícito que implícito.