5

I have a model along with a ModelForm based on that model. The ModelForm contains a ModelMultipleChoice field, which I specify in the subclass of my ModelForm:

class TransactionForm(ModelForm):

    class Meta:
        model = Transaction

    def __init__(self, *args, **kwargs):
        super(TransactionForm, self).__init__(*args, **kwargs)
        self.fields['category'] = forms.ModelChoiceField(queryset=Category.objects.filter(user=user))

As you can see, I need to filter the Category queryset by user. In other words, users should only see their own categories on the drop down. But how can I do this when user, or more specifically, request.user, is not available in a Model instance?

Edit: Adding my subclass of the CBV:

class TransUpdateView(UpdateView):
    form_class = TransactionForm
    model = Transaction
    template_name = 'trans_form.html'
    success_url='/view_trans/'

    def get_context_data(self, **kwargs):
        context = super(TransUpdateView, self).get_context_data(**kwargs)
        context['action'] = 'update'
        return context

I tried form_class = TransactionForm(user=request.user) and I'm getting a NameError saying that request was not found.

trpt4him
  • 1,646
  • 21
  • 34

1 Answers1

16

You can pass request.user to form init in view:

def some_view(request):
     form = TransactionForm(user=request.user)

and add user parameter to form __init__ method (or pop it from kwargs in form):

class TransactionForm(ModelForm):
    class Meta:
        model = Transaction

    # def __init__(self, *args, **kwargs):
        # user = kwargs.pop('user', User.objects.get(pk_of_default_user))
    def __init__(self, user, *args, **kwargs):
        super(TransactionForm, self).__init__(*args, **kwargs)
        self.fields['category'] = forms.ModelChoiceField(
                                     queryset=Category.objects.filter(user=user))

update: in class based views you can add extra parameter to form init in get_form_kwargs:

class TransUpdateView(UpdateView):
    #...

    def get_form_kwargs(self):
        kwargs = super(YourView, self).get_form_kwargs()
        kwargs.update({'user': self.request.user})
        return kwargs
ndpu
  • 22,225
  • 6
  • 54
  • 69
  • Thanks, that solution in the Model makes a lot of sense. Now the question is, how would I do this using a class-based generic view? – trpt4him Jan 12 '14 at 19:12
  • Ok, I added that, now I get `cannot convert dictionary update sequence element #0 to a sequence`. – trpt4him Jan 12 '14 at 20:42
  • Yes, when adding exactly what you have but of course changing the super call to my own class name. I am using Django 1.5 by the way. When I try `self.request.user[0]` to narrow down the issue, I get `SimpleLazyObject does not support indexing`. – trpt4him Jan 12 '14 at 20:50
  • @trpt4him sorry, my error was here: `{'user', self.request.user}`, should be `{'user': self.request.user}` – ndpu Jan 12 '14 at 20:51
  • Ahh, I should have seen that myself. Ok added that, then I was getting `__init__ got unexpected keyword arg 'user'`, so I changed the `__init__` of the model subclass to `def __init__(self, user, *args, **kwargs):`, removed the `user=kwargs.pop`, then it works! Thanks!! – trpt4him Jan 12 '14 at 20:57
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/45132/discussion-between-trpt4him-and-ndpu) – trpt4him Jan 13 '14 at 16:19
  • @ndpu, How do I give bootstrap features like 'class':'form-control' to this helpful code??? – Ptar Mar 20 '21 at 15:52
  • 1
    @Ptar https://stackoverflow.com/questions/5827590/css-styling-in-django-forms – ndpu Mar 22 '21 at 15:37