Cross queries in django

Viewed 56

I have two models as below

class Watched(Stamping):
    user = models.ForeignKey("User", null=True, blank=True, on_delete=models.CASCADE,
                             default=None)
    count = models.PositiveIntegerField()


class Link(Stamping):
    ...
    user = models.ForeignKey(User,  on_delete=models.CASCADE, default=None)
    url = models.CharField(max_length=256, default=None)
    watched = models.ForeignKey(Watched, null=True, blank=True, on_delete=models.CASCADE, default=None)
    ...

My forms.py

class SimpleLink(forms.Form):
    url = forms.URLField(max_length=256)

A user can create a Link object and when some conditions are met, the object will be added to Watched. The Watched model contains objects created by different users. Now I want to filter the Watched class and grab only the objects created by the requesting user in the Link model but I don't know how I can achieve that. Any help will be appreciated. A sample of what I want to achieve is... Watched.objects.filter(Link.objects.filter(user=request.user). I know my sample is crazy. But from the outside query, I want to grab the Link objects created by user making the request

1 Answers

You need to limit the queryset in your ModelForm. A ModelForm will thus look like:

from django import forms

class LinkForm(forms.ModelForm):
    
    def __init__(self, *args, user=None, **kwargs):
        super().__init__(*args, **kwargs)
        if user is not None:
            self.fields['watched'].queryset = Watched.objects.filter(
                link__user=user
            )

    class Meta:
        model = Link
        fields = ['url', 'watched']

In our view, we can then set the user object:

from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect, render

@login_required
def some_view(request):
    if request.method == 'POST':
        form = LinkForm(request.POST, user=request.user)
        if form.is_valid():
            form.instance.user = request.user
            form.save()
            return redirect('name-of-some-form')
    else:
        form = LinkForm(user=request.user)
    return render(request, 'some-template.html', {'form': form})

For a class-based view, we can override the .get_form_kwargs(…) method [Djangod-doc]:

from django.contrib.auth.mixins import LoginRequiredMixin

class SomeView(LoginRequiredMixin, CreateView):
    form_class = LinkForm
    
    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super().form_valid(form)
Related