Greg Kaleka
Greg Kaleka

Reputation: 1990

Can I filter a parent model by occurences in a child model in django?

I have two models:

class User(models.Model):
    # stuff


class Task(models.Model):
    # stuff

When assigning new tasks to users, I want to avoid assigning tasks the worker has gotten before. The approach I'm trying to take is to add a third model, Assignment that tracks tasks assigned to a given user:

class Assignment(models.Model):
    worker = models.ForeignKey(User)
    task = models.ForeignKey(Task)

How, though, do I go about forming a query based on this? My thought was to start by filtering Assignments by the user being assigned to, but I'm getting stuck after that point.

def get_tasks(worker):
    previous_assignments = Assignment.objects.filter(worker=worker)
    # then something like...
    assignable_tasks = Task.objects.exclude(pk__in=previous_assignments.task)  #clearly wrong

Is there a way to access the task ids inside the previous_assignments queryset? Not sure if this isn't the best approach, or if I am just missing how to move past this step.

Edit: It occurs to me I could populate an empty set with Tasks by looping through those Assignment objects and then use an __in exclude argument like above... Any better approaches than that?

Upvotes: 1

Views: 1672

Answers (1)

Alasdair
Alasdair

Reputation: 308839

In order to exclude with pk_in, you would need a list or queryset of task ids to exclude. For example you could do:

previous_assignments = Assignment.objects.filter(worker=worker).values_list('task_id')
assignable_tasks = Task.objects.exclude(pk__in=previous_assignments)

However you don't need to do this. You can use the double underscore notation to follow the relationship from assignment to worker:

assignable_tasks = Task.objects.exclude(assignment__worker=worker)

Note that you could use a many-to-many field instead, and Django will take care of creating the joining table for you:

class Task(models.Model):
    users = models.ManyToManyField(User)

In this case, your query becomes:

assignable_tasks = Task.objects.exclude(users=worker)

Upvotes: 1

Related Questions