yung peso
yung peso

Reputation: 1766

How can I filter objects in my model to only show those of my ForeignKey user?

Trying to filter objects in my view.py to only show items (in my case Buckets) owned by Users.

I implemented the code below in my original Model [my model.py code is at the bottom of post]

    class PostObjects(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(status=Bucket.owner)

But I'm not sure if that is the correct procedure to list all items?

Here is the view.py where I'm trying to filter data by User aka owner. Users should ONLY be allowed to view their own items. (I will deal with permissions later)

class BucketList(generics.ListCreateAPIView):
    queryset = Bucket.objects.all() #INSERT FILTER HERE
    pass

Here is the model I'm referring too.

class Bucket(models.Model):

    options = (
        ('personal', 'Personal'),
        ('social', 'Social'),
    )


    class PostObjects(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(status=Bucket.owner)

    owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='buckets')
    users = models.ManyToManyField(settings.AUTH_USER_MODEL)
    category = models.CharField(max_length=30, choices=options)
    name = models.CharField(max_length=35)
    created = models.DateTimeField(default=timezone.now)
    slug = models.SlugField(unique=True, blank=True) 
    stock_count = models.IntegerField(blank=True, null=True)
    stock_list = ArrayField(models.CharField(max_length=6),size=10)

    objects = models.Manager()
    postobjects = PostObjects()

    class Meta:
        ordering = ('-created',)

    def total_stocks_calc(self):
        self.stock_count = Bucket.objects.aggregate(Sum('stock_list', distinct=True))
        self.save()

    def get_absolute_url(self):
        return reverse("bucket:bucket-view", kwargs={"slug": self.slug})

    def __str__(self):
        return self.stock_list

To re-state my question, how can I filter objects owned by users in class BucketList for their private view only?

UPDATE:

from django.db.models import Q

from rest_framework import generics
from bucket.models import Bucket
from .serializers import BucketSerializer

class OwnerOrUserFilterBackend(filters.BaseFilterBackend):

    queryset = Bucket.postobjects.all() # wondering if you didnt write this for brevity reasons or because its not need due to the class?
    
    def filter_queryset(self, request, queryset, view):
        return queryset.filter(
            Q(owner=request.user) |  #do I not need to change one of the filters too request.owner?
            Q(users=request.user)
        )


class BucketList(generics.ListCreateAPIView):
    model = Bucket
    filter_backends = [OwnerOrUserFilterBackend]

Upvotes: 2

Views: 905

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476493

You can override the get_queryset method and filter with self.request.user:

class BucketList(generics.ListCreateAPIView):
    model = Bucket
    
    def get_queryset(self, *args, **kwargs):
        return super.get_queryset(*args, **kwargs).filter(
            owner=self.request.user
        )

For an API view, it probably is however better to define a filter, and then use this over all the API views where you want to apply this:

class IsOwnerFilterBackend(filters.BaseFilterBackend):
    
    def filter_queryset(self, request, queryset, view):
        return queryset.filter(owner=request.user)

Then you can use this in your ListCreateAPIView with:

class BucketList(generics.ListCreateAPIView):
    model = Bucket
    filter_backends = [IsOwnerFilterBackend]

The advantage of this is that if you have other views that require the same filtering, you only need to add the IsOwnerFilterBackend as filter_backend.

Another filter could include both the owner and the users as people who can see the BucketList:

from django.db.models import Q

class OwnerOrUserFilterBackend(filters.BaseFilterBackend):
    
    def filter_queryset(self, request, queryset, view):
        return queryset.filter(
            Q(owner=request.user) |
            Q(users=request.user)
        )

then we thus filter with this filter:

class BucketList(generics.ListCreateAPIView):
    model = Bucket
    filter_backends = [OwnerOrUserFilterBackend]

Upvotes: 3

Related Questions