19

I have a model with a ManyToMany relation that I would like to update with a CheckBoxSelectMultiple widget while everything else uses the default generic form, but when I redefine that one form field, it is the only one that shows up in the UpdateView. Is there a way to use a widget with just one field without having to redefine the entire form?

Views.py:

from django.views.generic.edit import UpdateView

from kunden.models import Kunde, Unternehmenstyp
from kunden.forms import KundeEditForm

class KundeUpdate(UpdateView):
    model = Kunde
    form_class =  KundeEditForm
    template_name = 'kunden/kunde_update.html'
    success_url = '/'

forms.py:

from django.forms.widgets import CheckboxSelectMultiple
from django.forms import ModelMultipleChoiceField,ModelForm

from kunden.models import Kunde, Unternehmenstyp

class KundeEditForm(ModelForm):
    model = Kunde
    unternehmenstyp = ModelMultipleChoiceField(widget=CheckboxSelectMultiple,required=True, queryset=Unternehmenstyp.objects.all())

I know this has a painfully simple solution, so thanks for your patience in advance everyone.

While I'm at it can anyone recommend any django books worth reading? I've gone through the base tutorial, dug through documentation as needed, and read Two Scoops of Django: https://django.2scoops.org/ so if you can think of a book for someone at my level, that'd be greatly appreciated. thanks again

skzryzg
  • 1,020
  • 8
  • 25

2 Answers2

17

Here's a mixin that allows you to define a widgets dictionary and still respects the fields list:

from django.forms.models import modelform_factory

class ModelFormWidgetMixin(object):
    def get_form_class(self):
        return modelform_factory(self.model, fields=self.fields, widgets=self.widgets)

It can be used with CreateView, UpdateView, etc. For example:

class KundleUpdate(ModelFormWidgetMixin, UpdateView):
    model = Kunde
    widgets = {
        'unternehmenstyp': CheckboxSelectMultiple,
    }
Jonathan Potter
  • 2,981
  • 1
  • 24
  • 19
15

Try this, with class Meta:

from django.forms.widgets import CheckboxSelectMultiple
from django.forms import ModelMultipleChoiceField,ModelForm

from kunden.models import Kunde, Unternehmenstyp

class KundeEditForm(ModelForm):
    class Meta: # model must be in the Meta class
        model = Kunde
    unternehmenstyp = ModelMultipleChoiceField(widget=CheckboxSelectMultiple,required=True, queryset=Unternehmenstyp.objects.all())

REF: https://docs.djangoproject.com/en/1.5/topics/forms/modelforms/#modelform

You can also use modelform factories if you only need to make a simple override:

from django.views.generic.edit import UpdateView
from django.forms.models import modelform_factory

from kunden.models import Kunde, Unternehmenstyp

class KundeUpdate(UpdateView):
    model = Kunde
    form_class =  modelform_factory(Kunde,
        widgets={"unternehmenstyp": CheckboxSelectMultiple })
    template_name = 'kunden/kunde_update.html'
    success_url = '/'

REF: https://docs.djangoproject.com/en/1.5/topics/forms/modelforms/#modelform-factory-function

Thomas
  • 11,757
  • 4
  • 41
  • 57
  • That was certainly quick. Thanks a bunch. I tried to accept this as an answer, but it said I have to wait 10 minutes :) anyway if you have the time, could you point me towards some documentation on what's going on here? – skzryzg Jun 05 '13 at 10:12
  • The meta informations on the KundeEditForm give you the possibility to set a custom widget to any form field. – FlogFR Aug 12 '14 at 14:40
  • For the second part, it does the same by passing the positional argument "widgets" to the modelform_factory. – FlogFR Aug 12 '14 at 14:40
  • 2
    Django v1.8 requires that you pass either _fields_ or _excludes_ to model form_factory. After you make that change (with a potentially long field list) the code gets ugly enough that I prefer the ModelFormWidgetMixin shown in Jonathan Potter's answer. – nmgeek May 11 '15 at 21:11