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.
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)
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.
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.
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)
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.