How do I make my Django dropdown form show items owned by a user and not all users?

Viewed 56

I am having trouble displaying items owned only by specific users, rather than each user getting to see all items in my database. Below is an example of a non-superuser who has access to all items in my database when this user should only have access to the ones they created

image of dropdown menu with all items instead of just some

Below are the Form, View, and Models I have created in attempt to do this.

forms.py

class RoutineForm(forms.ModelForm):
"""creates a form for a routine"""
class Meta:
    model = Routine
    fields = ['workout']
    labels = {'workout': 'Workout'}

Here is the views.py

from django.shortcuts import render, redirect
from django.http import HttpResponseRedirect, Http404
from django.urls import reverse
from django.contrib.auth.decorators import login_required
@login_required
def routine(request):
    """display a dropdown of all workouts for a user"""
    if request.method != 'POST':
        form = RoutineForm()
    else:
        form = RoutineForm(data=request.POST)
        if form.is_valid():
            new_routine = form.save(commit=False)
            new_routine.save()
            return redirect('index')
    context = {'workouts':workouts, 'form':form}
    return render(request, 'routine_workouts_app/routine.html', context)

and finally, the models.py file

from django.db import models
from django.contrib.auth.models import User

# Create your models here.
class Workout(models.Model):
    """A workout group the user will use to workout"""
    text = models.CharField(max_length=200) #titles should not be too long
    owner = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        """Return a string representation of the model"""
        return self.text


class Routine(models.Model):
    """Shows a routine"""
    workout = models.ForeignKey(Workout, on_delete=models.CASCADE)
    owner = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return 'this is a routine'

Am I missing some sort of filter? Something Fundamental? I have been able to filter some other views that I have made. For example:

@login_required
def workouts(request):
    """This is the page that will display all the workout groups"""
    workouts = Workout.objects.filter(owner=request.user).order_by('text') #filter by user ownership
    context = {'workouts': workouts}
    return render(request, 'routine_workouts_app/workouts.html', context)

on line 4 of this snippet, I have successfully filtered items that only belong to a specific user. But this is not a form, just a display on an html file. I have tried to put a similar line in the routine view function but it did not work. Any suggestions?

1 Answers

You can add a parameter to the constructor of the RoutineForm, that will filter the queryset specified to link to a Workout. This thus means that the form looks like:

class RoutineForm(forms.ModelForm):
    """creates a form for a routine"""
    
    def __init__(self, *args, user=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['workout'].queryset = Workout.objects.filter(owner=user)
    
    class Meta:
        model = Routine
        fields = ['workout']
        labels = {'workout': 'Workout'}

In the view, we then can construct a Form where we pass the logged in user to the constructor of the form:

from django.shortcuts import render, redirect
from django.http import HttpResponseRedirect, Http404
from django.urls import reverse
from django.contrib.auth.decorators import login_required

@login_required
def routine(request):
    """display a dropdown of all workouts for a user"""
    if request.method != 'POST':
        form = RoutineForm(user=request.user)
    else:
        form = RoutineForm(data=request.POST, user=request.user)
        if form.is_valid():
            form.instance.owner = request.user
            new_routine = form.save()
            return redirect('index')
    context = {'workouts':workouts, 'form':form}
    return render(request, 'routine_workouts_app/routine.html', context)
Related