简体   繁体   中英

How to create default filter on django queryset

I have below model in my django app:

class Segment(BaseSegmentModel):
    payload_json = JSONField(null=True, default=None, blank=True)
    owner = models.ForeignKey(CustomUser, null=True, blank=True, on_delete=models.SET_NULL, related_name='segments')
    name = models.CharField(max_length=100, null=True, blank=False)
    status = models.CharField(max_length=100, null=True, blank=True, choices=SegmentStatuses.choices, default=SegmentStatuses.STOPPED)
    created_date = models.DateTimeField(null=True, auto_now_add=True)

There is a field status which has three values:

class SegmentStatuses:
    STOPPED = 'stopped'
    ACTIVE = 'active'
    ARCHIVE = 'archive'

    choices = ((STOPPED, STOPPED), (ACTIVE, ACTIVE), (ARCHIVE, ARCHIVE))

I need to add a default filter on this model where it should not show any results with status = Archive .

So whenever someone query this model it should not show any Archive results.

You can have 2 managers for your model: one for all objects and one for excluded objects

class SegmentStatuses:
    STOPPED = 'stopped'
    ACTIVE = 'active'
    ARCHIVE = 'archive'

    choices = ((STOPPED, STOPPED), (ACTIVE, ACTIVE), (ARCHIVE, ARCHIVE))

class UnArchivedManager(models.Manager):
    def get_queryset(self):
        return super(UnArchivedManager, self).get_queryset().exclude(status=SegmentStatuses.ARCHIVE)


class Segment(BaseSegmentModel):
    payload_json = JSONField(null=True, default=None, blank=True)
    owner = models.ForeignKey(CustomUser, null=True, blank=True, on_delete=models.SET_NULL, related_name='segments')
    name = models.CharField(max_length=100, null=True, blank=False)
    status = models.CharField(max_length=100, null=True, blank=True, choices=SegmentStatuses.choices, default=SegmentStatuses.STOPPED)
    created_date = models.DateTimeField(null=True, auto_now_add=True)
    
    objects = UnArchivedManager()
    objects_all = models.Manager()

As you can in this image, I just have only one object in DB and it has 'archive' status, so when I used the 'object' manager I didn't see any objects in the result, but when I used the 'object_all' manager I saw 1 object in the result

example queries

If you don't want to have access to archived status at all, you can ignore the objects_all manager.

In the view you can do it using exclude() :

views.py:

Segment.objects.exclude(status='archive')

Edit:

You can override the get_queryset of manager.

An Example:

models.py

class AnyManager(models.Manager):
    def get_queryset(self):
        qs = super().get_queryset()
        return qs.exclude(status='archive')

class Segment(BaseSegmentModel):
    payload_json = JSONField(null=True, default=None, blank=True)
    owner = models.ForeignKey(CustomUser, null=True, blank=True, on_delete=models.SET_NULL, related_name='segments')
    name = models.CharField(max_length=100, null=True, blank=False)
    status = models.CharField(max_length=100, null=True, blank=True, choices=SegmentStatuses.choices, default=SegmentStatuses.STOPPED)
    created_date = models.DateTimeField(null=True, auto_now_add=True)

    objects = AnyManager()

It will exclude the fields which have status='archive' , so you can now directly do it as:

views.py:

Segment.objects.all()

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM