I am using Django Rest Framework as a backend for an app.
I have a User
that has one Wallet
. Then I have Item
. If a User
wants an Item
it creates an instance in his/her Wallet
called WalletItem
. All works well.
Now I want to limit the number of items for the User
using an attribute limit_usage
.
First, I added a check to post method adding new instance that checks the number of item instances in User
's Wallet
. So the user gets 403 when trying to add third WalletItem
if limit_usage == 2
for this Item
.
I would like to override a get_queryset()
method or queryset
in list()
/ retrieve()
methods so that if anonymous user calls /items/
there are unfiltered items in response. However if the user is authenticated I would like to filter only those Items that s/he is allowed to put in the Wallet, ie those that have not exceeded limit_usage for current user.
class Wallet(models.Model):
user = models.OneToOneField('auth.User', related_name='wallet')
class Item(models.Model):
valid_from = models.DateTimeField()
valid_to = models.DateTimeField()
limit_usage = models.PositiveSmallIntegerField(default=0)
class WalletItem(models.Model):
wallet = models.ForeignKey('Wallet', related_name='%(class)ss')
offer = models.ForeignKey('Item', related_name='offer')
class ItemViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Item.objects.all().order_by('-created_at')
serializer_class = ItemSerializer
def list(self, request, *args, **kwargs):
time_now = now()
self.queryset = self.queryset.filter(
valid_from__lte=time_now,
valid_to__gte=time_now,
)
serializer = self.get_serializer(self.queryset, many=True)
return Response(serializer.data)
I created a method of Item
class that should have helped me but I realized I cannot use it in the queryset:
def is_visible_for_user(self, user=None):
if not self.limit_usage or not user:
return True
ct = WalletItem.objects.filter(item=self, wallet=user.wallet).count()
return self.limit_usage > ct
So I can iterate through the queryset to see if each item can be visible for the user, however I cannot construct the queryset out of this filtered list. I found something similar here on SO: Django REST Framework : filtering with another table but the response did not help me.
You firstly need to check if user is authenticated, it not, then return every Item
. Then to filter out Item
objects if corresponding WalletItem
objects exceeded its limit.
from django.db.models import Count, F, Sum
...
class ItemViewSet(viewsets.ReadOnlyModelViewSet):
def get_queryset(self):
queryset = super().get_queryset()
user = self.request.user
if user.is_anonymous:
return queryset
queryset = queryset.annotate(user_wallet_items=Sum(
Case(
When(walletitem__wallet_id=user.wallet_id, then=1),
default=0, output_field=IntegerField()
)) \
.filter(user_wallet_items__lte=F('limit_usage'))
return queryset
I suggest you to move your filtration based on current time to the same get_queryset()
method, since it's belong there.
Note: i've not tested this approach.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.