0

I don't know how to remove results from a queryset without using .exclude(). I want to filter the result if the argument is_active is passed as a parameter of my search based on the result of the property is_active.

My model with the calculated property 'is_active':

class Discount(models.Model):
    name = models.CharField(_("name"), max_length=255)
    date_start = models.DateField(_("Date start"), null=True, blank=True)
    date_end = models.DateField(_("Date end"), null=True, blank=True)
    [...]

    @property
    def is_active(self):
        if self.date_start and self.date_end:
            return self.date_start <= date.today() <= self.date_end
        return True

My viewset:

class DiscountViewSet(viewsets.ModelViewSet):    
    """
    A simple ViewSet for listing or retrieving discounts.
    """
    permission_classes = [CustomDjangoModelPermission]
    filter_backends = [DjangoFilterBackend]
    filter_fields = '__all__'
    
    def get_serializer_class(self):
        if hasattr(self, 'action') and self.action in ['list', 'retrieve']:
            return DiscountListSerializer
        return DiscountSerializer 
    
    def get_queryset(self):
        if self.request.user.is_staff:
            return Discount.objects.all().prefetch_related('products') \
                    .prefetch_related('machines').prefetch_related('categories')
        else:
            return Discount.objects.all().prefetch_related('products') \
                    .filter(machines__site__client__in=self.request.user.profil.client.all()) \
                    .prefetch_related('machines').prefetch_related('categories')
                    
    @swagger_auto_schema(manual_parameters=[height, width], 
                        responses={200: DiscountListSerializer})
    def list(self, request):
        height = self.request.query_params.get('height')
        width = self.request.query_params.get('width')
        queryset = self.get_queryset()
        queryset = self.filter_queryset(self.get_queryset())

        active_filter = request.data.get('is_active')

        if active_filter:
            for item in qs:
                if not item.is_active:
                    ???? // remove item
        
        if height and width:
            for discount in queryset:
                if discount.menu_photo:
                    discount.menu_photo = generate_thumbnail(discount.menu_photo, width, height)
                if discount.standby_photo:
                    discount.standby_photo = generate_thumbnail(discount.standby_photo, width, height)
        
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

In the list section, how I can remove in my queryset the Discount non active ? I can't use .exclude() because is_active is not registered in database.

darkvodka
  • 303
  • 1
  • 3
  • 11

1 Answers1

0

You cannot filter on model methods. you could write a custom manager for the model which filters the data directly or returns an annotated queryset with filterable values, using your model method

check the docs for managers

class MyManager(models.Manager):
    def is_active(self):
        # Put your method here to filter the queryset
        return 

add objects = MyManager() to the model (to override the default manager

then you could use MyModel.objects.is_active()

caleo
  • 96
  • 5