2011-04-18 29 views
6

Tengo un formulario de ejemplo:Django ModelForm (con el campo excluido)

class AdminDiscountForm(ModelForm): 
    class Meta: 
     model = Discount 
     exclude = ('company',) 

el modelo al que está señalando es:

class Discount(models.Model): 
    class Meta: 
     verbose_name=_('Discount') 
     verbose_name_plural=_('Discounts') 
     unique_together = ('company','type') 

    company = models.ForeignKey(Company) 
    type = models.CharField(max_length=5, choices=DISCOUNT_CHOICES) 
    discount = models.DecimalField(max_digits=7, decimal_places=2, verbose_name=_('Discount')) 

La forma excluye campo de la 'compañía' porque el usuario tiene ya seleccionado esto usando la IU.

Estoy pensando en hacer un:

company = blah 
if form.is_valid(): 
    obj = form.save(commit=False) 
    obj.company = company 
    obj.save() 

El problema es que la combinación de 'compañía' y 'tipo' debe ser único (de ahí el 'unique_together'). Esto se aplica en la base de datos, por lo que a django no le importa. I necesidad de extender el método clean() de esta forma para comprobar si hay singularidad como tal:

def clean(self): 
    cleaned_data = self.cleaned_data 
    # check for uniqueness of 'company' and 'type' 

El problema aquí es que la 'compañía' no está ahí porque se ha excluido. ¿Cuál es la mejor manera de generar un error de validación de formulario en este caso?

- edit Esto es solo para sumando entradas de descuento. No hay instancia inicial.

+0

respuestas que se encuentran aquí: http://stackoverflow.com/questions/2141030/djangos-modelform-unique-together-validation – gladysbixly

Respuesta

10

método de Jammon es el Yo suelo. Para ampliar un poco (usando tu ejemplo):

models.py

class Discount(models.Model): 
    class Meta: 
     verbose_name=_('Discount') 
     verbose_name_plural=_('Discounts') 
     unique_together = ('company','type') 

    company = models.ForeignKey(Company) 
    type = models.CharField(max_length=5, choices=DISCOUNT_CHOICES) 
    discount = models.DecimalField(max_digits=7, decimal_places=2, verbose_name=_('Discount')) 

forms.py

class AdminDiscountForm(ModelForm): 
    class Meta: 
     model = Discount 
     exclude = ('company',) 

views.py

def add_discount(request, company_id=None): 
    company = get_object_or_404(Company, company_id) 

    discount=Discount(company=company) 

    if request.method == 'post': 
     form = AdminDiscountForm(request.POST, instance=discount) 
     if form.is_valid(): 
      form.save() 
      return HttpResponse('Success') 
    else: 
     form = AdminDiscountForm(instance=company) 

    context = { 'company':company, 
       'form':form,} 

    return render_to_response('add-discount.html', context, 
     context_instance=RequestContext(request)) 

Esto funciona mediante la creación de una instancia de su modelo de descuento, luego vincula su formulario a esta instancia. Esta instancia no se guarda en su base de datos pero se usa para enlazar el formulario. Esta forma enlazada tiene un valor para la compañía de la instancia enlazada. Luego se envía a su plantilla para que el usuario la complete. Cuando el usuario envía este formulario y se valida el formulario, la verificación de validación del modelo verificará la exclusividad del conjunto único definido en Meta.

Ver Model Validation Docs y overriding clean for ModelForms

edición:

Puede hacer un par de cosas para atrapar intentos no exclusivos de entrada juntos.

  1. Dentro de su formulario.is_valid() se puede exceptuar un error de integridad de la siguiente manera:

    if request.method == 'post': 
        form = AdminDiscountForm(request.POST, instance=discount) 
        if form.is_valid(): 
         try: 
          form.save() 
          return HttpResponse('Success') 
         except IntegrityError: 
          form._errors["company"] = "some message" 
          form._errors["type"] = "some message" 
        else: 
         ... 
    
  2. Uso self.instance dentro de limpieza método del modelo de formulario para comprobar la singularidad.

+0

Ya veo. Me confundí con Discount(). Pensé que era Discount.objects.create(). Mi error. Gracias a ambos. – Dim

+0

Si bien ahora está bien, sigo recibiendo IntegrityError ya que la validación en unique_together no ocurre porque uno de los campos se ha excluido. – Dim

+0

Bien, editaré mi publicación para incluir validación personalizada. – DTing

2

Usted podría intentar esto:

discount = Discount(company = blah) 
form = AdminDiscountForm(request.POST, instance=discount) 
if form.is_valid(): 
    discount = form.save() 

Y el docs dicen: Por defecto el método clean() valida la singularidad de los campos que están marcados como ... unique_together

+0

Debo señalar que esto es sólo para añadir * *. Sin edición en absoluto. – Dim

+0

Eso está bien. Crea una instancia con los valores predeterminados establecidos y luego esa instancia toma todos los demás valores que están en el ModelForm. – jammon

+0

Seguramente no puedo simplemente crear una instancia con valores predeterminados cada vez. unique_together va a entrar en juego en algún momento. – Dim

Cuestiones relacionadas