How to create a formset that contains forms with a dropdown? (Crucial)

1,319 views
Skip to first unread message

Houmie

unread,
Aug 16, 2012, 5:35:39 PM8/16/12
to django...@googlegroups.com
The question might seem too simplistic, but it seems formsets can only work with forms that have simple type fields such as charfield.
But has anyone tried to use a form with a dropdown and use that form to instantiate a formset?

Let me give you an example why this fails:

Model:

class SalesItem(models.Model):        
    item_description    
= models.CharField(max_length=40)
    company            
= models.ForeignKey(Company)

Here I create a form with a dropdown, hoping to pass in the company as a source for the dropdown. Hold on to this thought, as I think that is not possible in my scenario.

Form:

class SalesItemFSForm(Form):        
    sales_item      
=   forms.ModelChoiceField(required=False, queryset = '')

   
def __init__(self, company, *args, **kwargs):
       
super(SalesItemFSForm, self).__init__(*args, **kwargs)
       
self.fields.sales_item.queryset = company.salesitem_set.all()

Now within my view I would like to create a formset with this form:

formset_type = formset_factory(SalesItemFSForm, extra=0)

The problem becomes right away clear, as there seem to be no way that I could pass in the company to determine the source for the dropdown.


How would you solve this please?

Many Thanks,
Houman



Xavier Ordoquy

unread,
Aug 16, 2012, 5:47:42 PM8/16/12
to django...@googlegroups.com
Hi,

I'm not sure I understood what you're trying to do.

If you want to display all the SaleItem linked to a company in a formset, then inlines are what you're looking for.
You'll find the documentation about them there: https://docs.djangoproject.com/en/1.4/topics/forms/modelforms/#inline-formsets

Regards,
Xavier Ordoquy,
Linovia.

houmie

unread,
Aug 16, 2012, 6:05:02 PM8/16/12
to django...@googlegroups.com
Hi Xavier,

This wasn't the whole story.

I actually have a DealType class:

class DealType(models.Model):    
    deal_name           = models.CharField(max_length=40)
    sales_item          = models.ManyToManyField(SalesItem)    
    price               = models.DecimalField(decimal_places=2)


DealType class has a many to many relationship to sales_item.  Therefore using inline formsets wouldn't be possible.  I have tried it and inlines need foreign key.

What I am trying to achieve is to edit DealType like this:




Unlike the Many2Many widget, the one above is compatible to touch pads.

So I thought having an custom form that has a choiceField. I would feed the queryset of the choicefield with all entries of SalesItems.
And the user can Add these forms (as part of the formset) and select which sales item to put in the deal.

Once I get in the request.POST I could see which ones are added and do a manual custom save on DealType class.

Is it now a bit more clear what I am trying to achieve?

Many Thanks,
Houman

Xavier Ordoquy

unread,
Aug 16, 2012, 6:37:10 PM8/16/12
to django...@googlegroups.com
Hi Houman

Le 17 août 2012 à 00:05, houmie <hou...@gmail.com> a écrit :

> DealType class has a many to many relationship to sales_item. Therefore using inline formsets wouldn't be possible. I have tried it and inlines need foreign key.

DealType has a ForeignKey to Company which is what you're filtering with according to your previous mail.
You'll need to have a custom save but that could work.

However I think you should rather go with a dynamic form since you're editing only one object (a dealtype).
You'll find an example about it there: http://jacobian.org/writing/dynamic-form-generation/

Regards,
Xavier Ordoquy,
Linovia.

Houman

unread,
Aug 16, 2012, 7:05:26 PM8/16/12
to django...@googlegroups.com, django...@googlegroups.com
Hi xavier,

Apologies for the confusion.

What I am trying to achieve would be deal type having a m2m relationship to sales items. I don't like the m2m widget, so I thought I use formsets with dropdowns in them. The idea is good, somce the user would choose how many dropdowns he wants and point each to a salesitem. but I don't think it's possible with plain django.

I will have a look at this extension. Hopefully it solves it.

Thanks,
Houman

Sent from my iPhone
> --
> You received this message because you are subscribed to the Google Groups "Django users" group.
> To post to this group, send email to django...@googlegroups.com.
> To unsubscribe from this group, send email to django-users...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/django-users?hl=en.
>

Melvyn Sopacua

unread,
Aug 16, 2012, 8:01:03 PM8/16/12
to django...@googlegroups.com
On 17-8-2012 1:05, Houman wrote:

> What I am trying to achieve would be deal type having a m2m
> relationship to sales items. I don't like the m2m widget,

So change it. All ModelForm derivatives have a widgets argument that is
a dictionary of fieldname => widget instance:
<https://docs.djangoproject.com/en/1.4/topics/forms/modelforms/#overriding-the-default-field-types-or-widgets>
--
Melvyn Sopacua

Tomas Neme

unread,
Aug 16, 2012, 9:22:06 PM8/16/12
to django...@googlegroups.com
DropDownMultiple widget

http://djangosnippets.org/snippets/747/

--
"The whole of Japan is pure invention. There is no such country, there
are no such people" --Oscar Wilde

|_|0|_|
|_|_|0|
|0|0|0|

(\__/)
(='.'=)This is Bunny. Copy and paste bunny
(")_(") to help him gain world domination.

Simone Federici

unread,
Aug 17, 2012, 2:44:52 AM8/17/12
to django...@googlegroups.com, django...@googlegroups.com
Extend the model form set.


Many Thanks,
Houman




--
You received this message because you are subscribed to the Google Groups "Django users" group.
To view this discussion on the web visit https://groups.google.com/d/msg/django-users/-/YGT3FYCdYbUJ.

houmie

unread,
Aug 17, 2012, 6:48:27 AM8/17/12
to django...@googlegroups.com
Thanks Thomas.

Just trying to apply the DropDownMultiple Widget that you have suggested. I have followed the instruction:

class MyForm(forms.ModelForm):
    categories = forms.Field(widget=DropDownMultiple)

    def __init__(self, *args, **kwargs):
        self.base_fields['categories'].widget.choices = Category.objects.values_list('id', 'name')
        super(MyForm, self).__init__(*args, **kwargs)

And I get an exception at python level.  This code seems to have been written in 2008. I wonder if its still working with the latest python and django. :(

As soon as I add the line
categories = forms.Field(widget=DropDownMultiple)
to my form i get this exception:

Traceback:
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/auth/decorators.py" in _wrapped_view
  20.                 return view_func(request, *args, **kwargs)
File "/home/houman/projects/my/my_app/views.py" in deal_template_view
  303.         form = DealTypeForm(instance=deal)
File "/home/houman/projects/my/my_app/forms.py" in __init__
  252.         super(DealTypeForm, self).__init__(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/forms/models.py" in __init__
  247.                                             error_class, label_suffix, empty_permitted)
File "/usr/local/lib/python2.7/dist-packages/django/forms/forms.py" in __init__
  95.         self.fields = copy.deepcopy(self.base_fields)
File "/usr/lib/python2.7/copy.py" in deepcopy
  174.                 y = copier(memo)
File "/usr/local/lib/python2.7/dist-packages/django/utils/datastructures.py" in __deepcopy__
  129.                                for key, value in self.iteritems()])
File "/usr/lib/python2.7/copy.py" in deepcopy
  174.                 y = copier(memo)
File "/usr/local/lib/python2.7/dist-packages/django/forms/fields.py" in __deepcopy__
  180.         result.widget = copy.deepcopy(self.widget, memo)
File "/usr/lib/python2.7/copy.py" in deepcopy
  190.                 y = _reconstruct(x, rv, 1, memo)
File "/usr/lib/python2.7/copy.py" in _reconstruct
  334.             state = deepcopy(state, memo)
File "/usr/lib/python2.7/copy.py" in deepcopy
  163.         y = copier(x, memo)
File "/usr/lib/python2.7/copy.py" in _deepcopy_dict
  257.         y[deepcopy(key, memo)] = deepcopy(value, memo)
File "/usr/lib/python2.7/copy.py" in deepcopy
  163.         y = copier(x, memo)
File "/usr/lib/python2.7/copy.py" in _deepcopy_dict
  257.         y[deepcopy(key, memo)] = deepcopy(value, memo)
File "/usr/lib/python2.7/copy.py" in deepcopy
  190.                 y = _reconstruct(x, rv, 1, memo)
File "/usr/lib/python2.7/copy.py" in _reconstruct
  329.     y = callable(*args)
File "/usr/lib/python2.7/copy_reg.py" in __newobj__
  93.     return cls.__new__(cls, *args)
Exception Type: TypeError at /deal/add/
Exception Value: object.__new__(NotImplementedType) is not safe, use NotImplementedType.__new__()

    
On 17/08/12 02:22, Tomas Neme wrote:
DropDownMultiple widget

http://djangosnippets.org/snippets/747/


houmie

unread,
Aug 17, 2012, 9:00:36 AM8/17/12
to django...@googlegroups.com
Thanks Melvyn,

Yes, I know about overriding a widget. I could override a Charfield with
a TextArea. For simple stuff it makes sense.
Against which widget do I override the existing M2M widget though?

Melvyn Sopacua

unread,
Aug 17, 2012, 9:24:14 AM8/17/12
to django...@googlegroups.com
On 17-8-2012 15:00, houmie wrote:

> Yes, I know about overriding a widget. I could override a Charfield with
> a TextArea. For simple stuff it makes sense.
> Against which widget do I override the existing M2M widget though?

If the one that Tomas linked doesn't work for you, you'll need to
consult the roll-your-own department or keep looking around for
different widgets, for example:
<http://www.djangopackages.com/grids/g/widgets/>

--
Melvyn Sopacua

houmie

unread,
Aug 17, 2012, 9:36:45 AM8/17/12
to django...@googlegroups.com
Thanks Melvyn,

To be honest I would be willing to purchase a widget if there was one.
iw ill look into the list you have sent me.

On another note, Simone mentioned to extend the Formset in order to run
my own dropdown solution.

I was just looking at the modelformset_factory class and - surpise
surprise - it accepts a formfield_callback parameter, which could solve
my dilemma.

I have used callbacks previously within a form to set localized to True:

class CallsForm(ModelForm):

def contact_date_callback(self, field, **kwargs) :

return field.contact_date(localize=True, **kwargs)


But I have no idea how to use it from view

formset_type = modelformset_factory(SalesItem, form=SalesItemFSForm, extra=0, formfield_callback=???? )


Do you happen to know how to use it?

If I was able to set the queryset for the sales_item field in that
callback, I wouldn't have to extend the factory at all.


Many Thanks,
Houman

Kurtis Mullins

unread,
Aug 17, 2012, 6:40:56 PM8/17/12
to django...@googlegroups.com
+1 on "Roll your own" solution. Complicated M2Ms and Django Forms aren't always the cleanest pair of features to work with when combined.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To post to this group, send email to django...@googlegroups.com.
To unsubscribe from this group, send email to django-users+unsubscribe@googlegroups.com.

Melvyn Sopacua

unread,
Aug 18, 2012, 9:48:28 AM8/18/12
to django...@googlegroups.com
On 17-8-2012 0:05, houmie wrote:

> DealType class has a many to many relationship to sales_item. Therefore
> using inline formsets wouldn't be possible. I have tried it and inlines
> need foreign key.

You *can* use the reverse bit of a ManyToManyField with inline formsets.
The information on how to do it, is kind of hidden in the admin
documentation [1].
A many to many field in it's simplest form is an automatically generated
model of two foreign keys with a unique id. This model is made available
on the ManyToManyField's 'through' attribute and this is the model you
need to pass as the dependent model for inlineformset_factory.
So in your case it would be:
inlineformset_factory(SalesItem, DealType.sales_item.through, ...)

[1]
<https://docs.djangoproject.com/en/1.4/ref/contrib/admin/#working-with-many-to-many-models>
--
Melvyn Sopacua
Reply all
Reply to author
Forward
0 new messages