Hanny
Hanny

Reputation: 682

Get related objects through FK of a FK in django (will a _set work?)

If I had a model structure like this:

class Camp(models.Model):
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=200, blank=True, null=True)
    reg_start = models.DateTimeField()
    reg_end = models.DateTimeField()

class Course(models.Model):
    camp = models.ForeignKey(Camp, on_delete=models.PROTECT)
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=500, blank=True, null=True)

class ClassDetail(models.Model):
    course = models.ForeignKey(Course, on_delete=models.PROTECT)
    seat_count = models.IntegerField()
    limit_registrations = models.BooleanField(default=False)

class Registration(models.Model):
    person = models.ForeignKey(User, on_delete=models.PROTECT)
    class_detail = models.ForeignKey(CourseDetail, on_delete=models.PROTECT)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

If I had a user that had (potentially) multiple Registrations, is there a quick and easy way to get a list of the id's of those camps?

This is what I currently have (which is working but I'm trying to see if I can eliminate the list comprehension)

        registration_queryset = Registration.objects.filter(
            person__id=user_id
        )

        camps_to_exclude = [
            x.course_detail.course.camp.id for x in registration_queryset
        ]
        # camp_list is an already existing queryset of camps
        camp_list = camp_list.exclude(
            id__in=camps_to_exclude,
        )

Upvotes: 0

Views: 24

Answers (1)

schillingt
schillingt

Reputation: 13731

Here's one option. As long as they are querysets, django will reduce them into a single query. You can always check the query with print(queryset.query).

camp_list.exclude(
    id__in=registration_queryset.values_list('course_detail__course__camp__id', flat=True),
)

Or you can do:

camp_list.exclude(
    course_set__classdetail_set__registration_set__person_id=user_id
).distinct()

The distinct will be necessary since you're crossing a pair of reverse foreign keys.

Upvotes: 1

Related Questions