How does one use a custom widget with a generic UpdateView without having to redefine the entire form?
Asked Answered
N

2

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

Neale answered 5/6, 2013 at 10:5 Comment(0)
F
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

Fredel answered 5/6, 2013 at 10:9 Comment(4)
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?Neale
The meta informations on the KundeEditForm give you the possibility to set a custom widget to any form field.Ipecac
For the second part, it does the same by passing the positional argument "widgets" to the modelform_factory.Ipecac
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.Dorathydorca
N
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,
    }
Nikaniki answered 15/1, 2015 at 19:15 Comment(0)
F
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

Fredel answered 5/6, 2013 at 10:9 Comment(4)
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?Neale
The meta informations on the KundeEditForm give you the possibility to set a custom widget to any form field.Ipecac
For the second part, it does the same by passing the positional argument "widgets" to the modelform_factory.Ipecac
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.Dorathydorca

© 2022 - 2024 — McMap. All rights reserved.