I want to pass request.user or request.user.pk from class based view to the ModelForm in order to filter query set with request.user.pk . I have a following view:


class ArticleResurrectionView(MessageLoginRequiredMixin, FormView):
    model = Article
    form_class = ArticleResurrectionForm
    template_name = "articles/resurrection.html"
    success_url = reverse_lazy("articles:articles_main")
    redirect_message = "You have to be logged in to recover articles "

    def get_form_kwargs(self):
        kwargs = FormView.get_form_kwargs(self)
        kwargs["author_id"] = self.request.user.pk
        return kwargs

def get_form_kwargs(self): should pass self.request.user.pk as a kwargs["author_id"] to form’s init

Then I have following form for this view:

class ArticleResurrectionForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        self.author_id = kwargs.pop("author_id", None)
        forms.ModelForm.__init__(self, *args, **kwargs)


    title = forms.ModelMultipleChoiceField(label="Deleted articles", 

help_text="Please select the    article to recover", 

queryset=Article.default.filter(show=False, author=???) )

# I can not use self.author_id  here

Target is to use self.author_id from init in the title to filter queryset in a such way to show entries only made by current user. In another words I need to pass self.author_id in the queryset in title.

Perhaps it is possible to do it by something like that:

def __init__(self, *args, **kwargs):
        self.author_id = kwargs.pop("author_id", None)
        forms.ModelForm.__init__(self, *args, **kwargs)
        self.fields[“title"].queryset = ???

Anyway, if you know how to get request.user in the queryset – I would be happy to get your solution on that. Thank you!

p.s regarding Related managers: "default" instead of standard "objects", i use 2 managers:


class ArticleManager(models.Manager):
    """Shows only non deleted articles"""
    def get_queryset(self):
        return models.Manager.get_queryset(self).exclude(show=False)


class Article(models.Model):
    # related managers
    default = models.Manager() # shows all articles
    objects = ArticleManager() # shows only non deleted articles
.....
.....
.....

1 Answers

1
Willem Van Onsem On Best Solutions

Your second approach is indeed toe correct one, although you probably want to use a ModelChoiceField [Django-doc] instead of a ModelMultipleChoiceField [Django-doc], since the latter allows you to select multiple such Articles, but your form logic (title) hints that it is singular.

class ArticleResurrectionForm(forms.ModelForm):

    title = forms.ModelChoiceField(
        queryset=Article.objects.none()
        label='Deleted articles',
        help_text='Please select the article to recover'
    )

    def __init__(self, *args, **kwargs):
        author_id = kwargs.pop("author_id", None)
        forms.ModelForm.__init__(self, *args, **kwargs)
        self.fields['title'].queryset = Article.objects.filter(
            author_id=author_id,
            show=False
        )

We initially thus specify the queryset to be empty, but later patch that by specifying another queryset in the constructor of the form.

As for your view, you probably want to make a super() call instead of calling the method of a specific class, like:

class ArticleResurrectionView(MessageLoginRequiredMixin, FormView):

    # ...

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['author_id'] = self.request.user.pk
        return kwargs