In my application, the models Bet and Tag have a many to many relationship, in which tags are used to label bets. One tag can label zero, one or more bets, and a bet can have zero, one or more tags as labels. Both bets and tags have a bet_owner and tag_owner Foreign Key (the CustomUser model).
It is of course trivial to filter ListViews so that only objects belonging to the current user are displayed. However, in my NewTagView (CreateView) and UpdateTagView (UpdateView), a form is rendered that includes a multiple select widget where the user can pick zero, one or more bets to be immediately (upon submission) labeled with the tag being created/updated. However, it displays every single bet in the database, and not just those belonging to the current user. As the forms are rendered by the generic CBVs, I’m a bit confused as to how can I have them display only a filtered queryset (or if I should pass a custom context in the view).
The model:
from django.db import models
from django.conf import settings
from django.urls import reverse
from bets.models import Bet
from users.models import CustomUser
class Tag(models.Model):
"""Model a single Tag, which is a label associated with one or more bets."""
associated_bets = models.ManyToManyField(Bet, related_name='tags', blank=True)
label = models.CharField(max_length=25)
description = models.CharField(max_length=50, blank=True)
tag_owner = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
def __str__(self):
return self.label
The views:
class NewTagView(LoginRequiredMixin, CreateView):
model = Tag
form_class = TagForm
template_name = "tags/new_tag.html"
login_url = "/users/login/"
success_url = reverse_lazy("tag_list")
def form_valid(self, form):
# Set the owner of the bet to the current user
form.instance.tag_owner = self.request.user
return super().form_valid(form)
class UpdateTagView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Tag
form_class = TagForm
template_name = "tags/update_tag.html"
login_url = "/users/login/"
success_url = reverse_lazy("tag_list")
def test_func(self):
"""Checks if bet owner is the same as the current user."""
obj = self.get_object()
return obj.tag_owner == self.request.user
The form:
from django import forms
from .models import Tag
class TagForm(forms.ModelForm):
class Meta:
model = Tag
fields = ['label', 'description', 'associated_bets']
The templates:
{% block content %}
<form action="" method="post">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-warning active ml-2 border border-dark" type="submit">Add Tag</button>
</form>
{% endblock content %}