django queryset filter on whether related field is empty

Question:

here is my models:

class Flag(models.Model):
    ban = models.ForeignKey('flags.Ban', on_delete=models.CASCADE, related_name='flags')


class Ban(models.Model):
    punished = models.BooleanField(default=None)

Flag is triggered when user report some content. and they are summarised in to a Ban instance for administrator to verify. briefly, a ban can have many flags.

there is one occasion, that the author getting reported, manually deletes the content he/she has sent before admin heads over there. the ban should be dismissed. therefore. in ban list view, I try to filter them out and delete.

    to_deletes = []
    for ban in Ban.objects.all():
        if not len(ban.flags.all()):
            to_deletes.append(ban)
    for ban in to_deletes:
        ban.delete()

I wonder if there is a way I can write this into a queryset, all I need is a Ban.objects.all() that rejected empty flags for list view for performance and elegancy.

Asked By: Weilory

||

Answers:

You can count instances of flags in each Ban instance, annotate it and then filer by this annotation, something like that:

from django.db.models import Count
bans_to_delete = Ban.objects.all().annotate(count=Count('flags')).filter(count=0)
Answered By: TrueGopnik

If you just want to check the absence of Flags you can use filter

bans_to_delete = (Ban
                  .objects
                  .filter(flags__isnull=True))

No need to count something you do not use.

Answered By: dgw