Question

I'm using Django 1.6 and have following models (a bit simplified for readability):

class Person(models.Model):
    name = models.CharField(max_length=128)

class Room(models.Model):
    max_persons = models.SmallIntegerField()
    name = models.CharField(max_length=30, unique=True)

class Stay(models.Model):
    person = models.ForeignKey(Person)
    STAY_TYPE = (
        (1, 'Type 1'),
        (2, 'Type 2'),
        (3, 'Type 3'),
    )
    stay_type = models.CharField(max_length=1, choices=STAY_TYPE)

class Hospitalization(models.Model):
    stay = models.ForeignKey(Stay)
    date_in = models.DateField()
    date_out = models.DateField(blank=True, null=True)
    room = models.ForeignKey(Room)

With a queryset (in a manager), I'd like to obtain all the available rooms for a given date, i.e. where max_persons isn't met.

So far, I've tried to play around with Q and things like Room.objects.filter(hospitalization__date_out__lt="2014-04-25") but I'm not able to figure out the max_persons comparison.

Would you have any idea?

EDIT

The count of Person objects related to each room is representative of the number of people in that room.

Therefore, as per Karl's suggestions below, I've tried to play around with:

  • Room.objects.filter(hospitalization__date_out__lte="2014-04-25").annotate(num_persons=hospitalization_set__stay__person.Count()).exclude(num_persons__lte=max_persons)
    • Yields NameError: name 'hospitalization_set__stay__person' is not defined
  • Room.objects.filter(hospitalization__date_out__lte="2014-04-25").annotate(num_persons=Count('hospitalization_set__stay__person')).exclude(num_persons__lte=max_persons)
    • Yields FieldError: Cannot resolve keyword 'hospitalization_set' into field.
  • Room.objects.filter(hospitalization__date_out__lte="2014-04-25").annotate(num_persons=Count('hospitalization__stay__person')).exclude(num_persons__lte=F('max_persons'))
    • Yields nothing ([]), while I'm expecting at least three results according to my current DB.
    • When removing .exclude(), I still get no results. It looks like the .annotate() I'm using is doing something wrong.
Was it helpful?

Solution

I believe that something similar to Room.objects.filter(hospitalization__date_out="2014-04-25", max_persons__lt=x) should do the trick. Remember that you can have multiple declarations in a filter operation, and that you can also chain both exclusions and filters. This doesn't add to database activity; queryset filters and the like are only executed when the queryset itself is evaluated. See The Django Docs on making queries.

EDIT: This actually turned out to be slightly more complicated than I first thought, but I believe I have worked it out (after importing your model declarations and having a shell session!)

rooms = Room.objects.filter(DATE FILTERING HERE).annotate(num_persons=Count('hospitalization__room__id')).filter(num_persons__lt=F('max_persons')).count()

Will give you the number of rooms in which num_persons (our annotated variable above) is less than max_persons, with the date filtering occurring beforehand.

Remember to include the required imports: from django.db.models import Count from django.db.models import F

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top