Skip to content

Instantly share code, notes, and snippets.

@andrefsp
Last active March 1, 2021 22:22
Show Gist options
  • Save andrefsp/5115772 to your computer and use it in GitHub Desktop.
Save andrefsp/5115772 to your computer and use it in GitHub Desktop.
Simple way to inject custom parameters on a Django formset without using django.utils.functional.curry()
"""
Simple example on how to inject a custom user parameters onto a formset
and its forms.
curry(): https://github.com/django/django/blob/1.4.3/django/utils/functional.py#L9
Another answer on:
http://stackoverflow.com/questions/622982/django-passing-custom-form-parameters-to-formset
"""
class BaseAddToBasketForm(forms.Form):
product = forms.ModelChoiceField(queryset=Product.objects.none())
quantity = forms.IntegerField(initial=0)
    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user') # user was passed to a single form
        super(BaseAddToBasketForm, self).__init__(*args, **kwargs)
# create a base Formset class
BaseAddToBasketFormSet = formset_factory(BaseAddToBasketForm)  
class AddToBasketFormSet(BaseAddToBasketFormSet): # sub class it
    def __init__(self, *args, **kwargs):
#  create a user attribute and take it out from kwargs
# so it doesn't messes up with the other formset kwargs
        self.user = kwargs.pop('user')
        super(AddToBasketFormSet, self).__init__(*args, **kwargs)   
    def _construct_form(self, *args, **kwargs):
# inject user in each form on the formset
        kwargs['user'] = self.user       
        return super(AddToBasketFormSet, self)._construct_form(*args, **kwargs)
# Instantiate a form for user 'blabla':
AddToBasketFormSet(user="blabla")  
@AndrewIngram
Copy link

To be honest, I prefer the currying approach (which is why I used it in django-extra-views). My reasoning is that it's an ball-ache having to make a custom formset class and override a private API method just to add an extra kwarg to the forms constructor. The approach you have here is what I used to do before discovering the curry approach, it's even used in Oscar: https://github.com/tangentlabs/django-oscar/blob/1f64bc07ec8845a36ee43f6e6b4ef28d29ee617f/oscar/apps/basket/forms.py#L73-L82

@andrefsp
Copy link
Author

True. The underlying issue here is that simply injecting a kwarg on a Formset will mess the order in which arguments get's passed to the constructor. A formset expects the first argument to be data.
In my opinion using kwargs.pop() its a good way to don't mess up with the kwargs order and doesn't bring the level of complexity curry() does.

@eagle-r
Copy link

eagle-r commented Sep 18, 2015

One issue that I encountered with this approach is that it doesn't work for the empty_form

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment