开发者

specify queryset when instantiating an inlineformset

开发者 https://www.devze.com 2023-01-24 21:05 出处:网络
I have the following in views.py to generate a page that shows an inline set of forms for a user\'s \"qualifications\"

I have the following in views.py to generate a page that shows an inline set of forms for a user's "qualifications"

from django.db.models import User
from models import UserQualification

def edit_quals(request):
    QualsFormSet = inlineformset_factory(User, UserQualification, fields=('qualification', 'qualification_year', 'qualification_source'))
    if request.method == 'POST':
        formset = QualsFormSet(request.POST, request.FILES, instance = request.user)
        if formset.is_valid():
            formset.save()

            #send user somewhere
            return HttpResponseRedirect(request.user.get_profile_url())
    else:
        formset = QualsFormSet(instance = request.user)

    return render_to_response("edit_quals.html", {
        "formset": formset,
    }, context_instance=RequestContext(request)开发者_如何学Go)

This works fine, however, I would like to create a formset that only includes certain 'UserQualification' objects (ie, only ones that are marked as a certain type) so when a user gets to this page they are only editing a subset of their qualifications. This reference seems to be what I want: http://docs.djangoproject.com/en/1.1/topics/forms/modelforms/#changing-the-queryset. It deals with modelformset_factory, however inlineformset_factory is based on the prior, so I figure the same thing should work:

formset = QualsFormSet(instance = request.user, queryset=UserQualification.objects.filter(type__startswith='xyz'))

But going to this page just gives a TypeError: init() got an unexpected keyword argument 'queryset'. There are two methods listed on that reference and I'm having trouble with both.


I provided an answer to a slightly simpler version of this problem here: Limit Django's inlineformset_factory to only create new objects

For what you were trying to do, the InlineFormSet class would look like this instead:

class BaseInlineFilteredFormSet(BaseInlineFormSet):
    def get_queryset(self):
        ## See get_queryset method of django.forms.models.BaseModelFormSet
        if not hasattr(self, '_queryset'):
            self._queryset = self.queryset.filter(type__startswith='xyz'))
            if not self._queryset.ordered:
                self._queryset = self._queryset.order_by(self.model._meta.pk.name)                
        return self._queryset


I believe in this case you need to use the form parameter when calling inlineformset_factory and to pass it a custom form you made with an ad-hoc __init__ method.. If you need it to be parametric, I found around here some time ago the life-saving line

    FormSetName.form = staticmethod(curry(FormName, customparam=chosenparam))

where, as explained above, FormSetName was defined with form parameter pointing to FormName.

Btw, would love to give credit to the person suggesting the above solution, would have loved to leave a heart-warming reply, but too little reputation.

edit to explain better my solution:

This would be the custom form class (in this case, to chose a person as a relative, but only among a subset of people, those returned by the relatives() method):

class RelativeSelectForm(forms.ModelForm):
class Meta:
    model = Person
    fields = ('relative',)

def __init__(self, *args, **kwargs):
    try:
        profile = kwargs.pop('profile')
    except KeyError:
        super(RelativeSelectForm, self).__init__(*args, **kwargs)
        return
    super(RelativeSelectForm, self).__init__(*args, **kwargs)
    self.fields['relative'].queryset = profile.relatives().order_by('name')

and it would be used like so, in your vies.py:

RelativesFormSet = inlineformset_factory(Person, Person, form=RelativeSelectForm, can_delete=True, extra=1)
RelativesFormSet.form = staticmethod(curry(RelativeSelectForm, profile=request.user.profile))

so that every time you instantiate a formset it automatically gets the profile parameter filled with the right object and the queryset for the relative select box shows only people he has access to. Hope I made myself a bit clearer :)

0

精彩评论

暂无评论...
验证码 换一张
取 消