'Exclude many to many results from Queryset in Django

I have 3 models and I'm trying to exclude certain things in a query, but am struggling to do so because the many-to-many is returning None and it's breaking the exclude portion of the query.

My models:

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

class RelatedCamps(models.Model):
    name = models.CharField(max_length=50, null=True, blank=True)
    camps = models.ManyToManyField(Camp, related_name="related_camps")

class CourseDetail(models.Model):
    camp = models.ForeignKey(Camp, on_delete=models.PROTECT)
    ...other attributes...

I am trying to limit the CourseDetails that I'm getting back like so:

    # Get CourseDetails (this is well tested and works to return appropriate models)
    initial_course_details = get_available_course_details(student_id)
    # Get the camp_ids to check for 'related camps'
    course_detail_camp_ids = initial_course_details.values_list(
        "camp__id", flat=True
    )
    # Get the related_camp ids, so we can remove all of those from the total list
    related_camp_ids = initial_course_details.values_list(
        "camp__related_camps__camps", flat=True
    )
    # get the course_details, but remove the 'related_camp_ids'
    course_detail_camp_ids = course_detail_camp_ids.exclude(camp__in=related_camp_ids)

This works if there are related_camps. But in some cases it doesn't work because the 'related_camp_ids' returns a list like this: [1, 2, None]

When a list with None in it comes back - the .exclude() does not work properly and the course_detail_camp_ids list becomes empty.

Is doing something like this the most 'django' way?

    related_camp_ids = initial_course_details.values_list(
        "camp__related_camps__camps", flat=True
    ).exclude(camp__related_camps__camps=None)

Doing the exclude this way appears to work - but is it the best way?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source