If the values in formset_kwargs
and factory_kwargs
need to be modified at run time, they can be set by overloading the get_formset_kwargs()
and get_factory_kwargs()
methods on any formset view (model, inline or generic) and the InlineFormSetFactory
classes:
class AddressFormSetView(FormSetView):
...
def get_formset_kwargs(self):
kwargs = super(AddressFormSetView, self).get_formset_kwargs()
# modify kwargs here
return kwargs
def get_factory_kwargs(self):
kwargs = super(AddressFormSetView, self).get_factory_kwargs()
# modify kwargs here
return kwargs
The formset_class
option should be used if you intend to override the formset methods of a view or a subclass of InlineFormSetFactory
.
For example, imagine you'd like to add your custom clean
method for an inline formset view. Then, define a custom formset class, a subclass of Django's BaseInlineFormSet
, like this:
from django.forms.models import BaseInlineFormSet
class ItemInlineFormSet(BaseInlineFormSet):
def clean(self):
# ...
# Your custom clean logic goes here
Now, in your InlineFormSetView
sub-class, use your formset class via formset_class
setting, like this:
from extra_views import InlineFormSetView
from my_app.models import Item
from my_app.forms import ItemForm
class ItemInlineView(InlineFormSetView):
model = Item
form_class = ItemForm
formset_class = ItemInlineFormSet # enables our custom inline
This will enable clean
method being executed on the formset used by ItemInlineView
.
Passing initial data into ModelFormSet and InlineFormSet works slightly differently to a regular FormSet. The data passed in from initial
will be inserted into the extra
forms of the formset. Only the data from get_queryset()
will be inserted into the initial rows:
from extra_views import ModelFormSetView
from my_app.models import Item
class ItemFormSetView(ModelFormSetView):
template_name = 'item_formset.html'
model = Item
factory_kwargs = {'extra': 10}
initial = [{'name': 'example1'}, {'name': 'example2'}]
The above will result in a formset containing a form for each instance of Item
in the database, followed by 2 forms containing the extra initial data, followed by 8 empty forms.
Altenatively, initial data can be determined at run time and passed in by overloading get_initial()
:
...
class ItemFormSetView(ModelFormSetView):
model = Item
template_name = 'item_formset.html'
...
def get_initial(self):
# Get a list of initial values for the formset here
initial = [...]
return initial
In order to change the arguments which are passed into each form within the formset, this can be done by the 'form_kwargs' argument passed in to the FormSet constructor. For example, to give every form an initial value of 'example' in the 'name' field:
from extra_views import InlineFormSetFactory
class ItemInline(InlineFormSetFactory):
model = Item
formset_kwargs = {'form_kwargs': {'initial': {'name': 'example'}}}
If these need to be modified at run time, it can be done by get_formset_kwargs()
:
from extra_views import InlineFormSetFactory
class ItemInline(InlineFormSetFactory):
model = Item
def get_formset_kwargs(self):
kwargs = super(ItemInline, self).get_formset_kwargs()
initial = get_some_initial_values()
kwargs['form_kwargs'].update({'initial': initial})
return kwargs
If you want more control over the names of your formsets (as opposed to iterating over inlines
), you can use NamedFormsetsMixin
:
from extra_views import NamedFormsetsMixin
class CreateOrderView(NamedFormsetsMixin, CreateWithInlinesView):
model = Order
inlines = [ItemInline, TagInline]
inlines_names = ['Items', 'Tags']
fields = '__all__'
Then use the appropriate names to render them in the html template:
...
{{ Tags }}
...
{{ Items }}
...
When using Django's messages framework, mixins are available to send success messages in a similar way to django.contrib.messages.views.SuccessMessageMixin
. Ensure that 'django.contrib.messages.middleware.MessageMiddleware'
is included in the MIDDLEWARE
section of settings.py.
extra_views.SuccessMessageMixin
is for use with views with multiple inline formsets. It is used in an identical manner to Django's SuccessMessageMixin, making form.cleaned_data
available for string interpolation using the %(field_name)s
syntax:
from extra_views import CreateWithInlinesView, SuccessMessageMixin
...
class CreateOrderView(SuccessMessageMixin, CreateWithInlinesView):
model = Order
inlines = [ItemInline, ContactInline]
success_message = 'Order %(name)s successfully created!'
...
# or instead, set at runtime:
def get_success_message(self, cleaned_data, inlines):
return 'Order with id {} successfully created'.format(self.object.pk)
Note that the success message mixins should be placed ahead of the main view in order of class inheritance.
extra_views.FormSetSuccessMessageMixin
is for use with views which handle a single formset. In order to parse any data from the formset, you should override the get_success_message
method as below:
from extra_views import FormSetView, FormSetSuccessMessageMixin
from my_app.forms import AddressForm
class AddressFormSetView(FormSetView):
form_class = AddressForm
success_url = 'success/'
...
success_message = 'Addresses Updated!'
# or instead, set at runtime
def get_success_message(self, formset)
# Here you can use the formset in the message if required
return '{} addresses were updated.'.format(len(formset.forms))