views:

1117

answers:

4

Hi everyone,

A Django autofield when displayed using a formset is hidden by default. What would be the best way to show it?

At the moment, the model is declared as,

class MyModel:
   locid = models.AutoField(primary_key=True)
   ...

When this is rendered using Django formsets,

class MyModelForm(ModelForm):
  class Meta:
    model = MyModel
    fields = ('locid', 'name')

it shows up on the page as,

<input id="id_form-0-locid" type="hidden" value="707" name="form-0-locid"/>

Thanks.


Edit

I create the formset like this -

LocFormSet = modelformset_factory(MyModel) 
pformset = LocFormSet(request.POST, request.FILES, queryset=MyModel.objects.order_by('name'))


Second Edit

Looks like I'm not using the custom form class I defined there, so the question needs slight modification..

How would I create a formset from a custom form (which will show a hidden field), as well as use a custom queryset?

At the moment, I can either inherit from a BaseModelFormSet class and use a custom query set, or I can use the ModelForm class to add a custom field to a form. Is there a way to do both with a formset?


Third Edit

I'm now using,

class MyModelForm(ModelForm):
  def __init__(self, *args, **kwargs):
    super(MyModelForm, self).__init__(*args, **kwargs)
    locid = forms.IntegerField(min_value = 1, required=True)
    self.fields['locid'].widget.attrs["type"] = 'visible'
    self.queryset = MyModel.objects.order_by('name')
  class Meta:
    model = MyModel
    fields = ('locid', 'name')

LocFormSet = modelformset_factory(MyModel, form = MyModelForm)
pformset = LocFormSet()

But this still doesn't

  • Show locid
  • Use the custom query that was specified.
+1  A: 

Try changing the default field type:

from django import forms
class MyModelForm(ModelForm):
  locid = forms.IntegerField(min_value=1, required=True)
  class Meta:
    model = MyModel
    fields = ('locid', 'name')

EDIT: Tested and works...

Paolo Bergantino
Thanks for your reply. Unfortunately, this doesn't seem to change what is being displayed on the page..
viksit
Did you restart the server? Depending on how you have your environment setup you might have to. I just tested the above (with my own model, but same thing...) and it worked fine.
Paolo Bergantino
Hmm, usually my changes show up without a restart (for instance, adding new fields etc) - Ive got an apache/mod_python setup that refreshes on each request..
viksit
Maybe there is a way we're creating our formsets differently?I use something like,LocFormSet = modelformset_factory(MyModel)pformset = LocFormSet(request.POST, request.FILES, queryset=MyModel.objects.order_by('name'))
viksit
I'm not sure what to tell you, "it works on my machine" :P What exactly happens? It just keeps showing a hidden field?
Paolo Bergantino
Mm, I wasn't trying it from a formset, just a straight form. let me try formsets...
Paolo Bergantino
:) I can't understand myself! This sounds very logical. And yes - it just keeps showing a hidden field..
viksit
I just tried it on a formset and it works too! Are you explicitly naming the id field on fields and you don't have it on ignore or anything?
Paolo Bergantino
Could you paste your code (or an approximation?).. I think I know the problem - I don't think I'm actually using the custom formset class at all - I end up building it from the main model since I need to use a custom queryset.
viksit
@Paolo - It looks like I need to override the field in the formset, and at the same time have a custom queryset for the formset. Any ideas?
viksit
Override the queryset inside the __init__ of the modelform
Paolo Bergantino
Tried a bunch of things. I'm either stuck with a Manytomany error with the modelform, or an auto_id error!
viksit
Paolo, +1 for effort and tenacity. To me, it sounds like your approach was correct.
Jarret Hardie
+1  A: 

As you say, you are not using the custom form you have defined. This is because you aren't passing it in anywhere, so Django can't know about it.

The solution is simple - just pass the custom form class into modelformset_factory:

LocFormSet = modelformset_factory(MyModel, form=MyModelForm)

Edit in response to update 3:

Firstly, you have the redefinition for locid in the wrong place - it needs to be at the class level, not inside the __init__.

Secondly, putting the queryset inside the form won't do anything at all - forms don't know about querysets. You should go back to what you were doing before, passing it in as a parameter when you instantiate the formset. (Alternatively, you could define a custom formset, but that seems like overkill.)

class MyModelForm(ModelForm):
    locid = forms.IntegerField(min_value=1, required=True)

    def __init__(self, *args, **kwargs):
        super(MyModelForm, self).__init__(*args, **kwargs)
        self.fields['locid'].widget.attrs["type"] = 'visible'
    class Meta:
        model = MyModel
        fields = ('locid', 'name')

LocFormSet = modelformset_factory(MyModel, form = MyModelForm)
pformset = LocFormSet(request.POST, request.FILES,
                      queryset=MyModel.objects.order_by('name')))
Daniel Roseman
Thanks for the info on form = .. I'm not sure how I missed that in the docs!I'm still stuck with my original issue though - Edit no. 3 in the question illustrates the current code. Any ideas on how I could achieve that?
viksit
As Daniel said, you still need to move the locid declaration outside of the __init__ method.
Chris Lawlor
Thanks - the queryset now works, but I'm still stuck with not being able to see the locid! Declaring it *exactly* as above - locid is part of the class not __init__ - and I have the self.fields in there as well - don't end up in locid being visible.
viksit
In fact, the self.fields complains about not having the locid key..
viksit
+1 for the straightforward efforts in your examples, Daniel.
Jarret Hardie
A: 

Okay, none of the approaches above worked for me. I solved this issue from the template side, finally.

to be shown. This is available as a patch, which can be installed in the SVN version of django using "patch -p0 file.patch"

  • Remember, the {{form.locid.value}} variable will be used in conjunction with the invisible form - otherwise, the submit and save operations for the formset will crash.

  • This is Not the same as {{form.locid.data}} - as is explained in the ticket referred to above.

viksit
A: 

The reason that the autofield is hidden, is that both BaseModelFormSet and BaseInlineFormSet override that field in add_field. The way to fix it is to create your own formset and override add_field without calling super. Also you don't have to explicitly define the primary key.

you have to pass the formset to modelformset_factory:

    LocFormSet = modelformset_factory(MyModel, 
           formset=VisiblePrimaryKeyFormSet)

This is in the formset class:

from django.forms.models import BaseInlineFormSet, BaseModelFormSet, IntegerField
from django.forms.formsets import BaseFormSet

class VisiblePrimaryKeyFormset(BaseModelFormSet):
    def add_fields(self, form, index):
        self._pk_field = pk = self.model._meta.pk
        if form.is_bound:
            pk_value = form.instance.pk
        else:
            try:
                pk_value = self.get_queryset()[index].pk
            except IndexError:
                pk_value = None
        form.fields[self._pk_field.name] = IntegerField( initial=pk_value,
                 required=True) #or any other field you would like to display the pk in
        BaseFormSet.add_fields(self, form, index) # call baseformset which does not modify your primary key field
specialunderwear