J. Hesters
J. Hesters

Reputation: 14824

Django 1.11 querysets: Get all objects (model instances) of a relationship set

If have a model for companies. These companies have an attribute employment_set, because workers are assigned to companies via the employment relation. How can I query all employees for a given company? The model for the employements look like this:

class Employment(
    SoftDeletableModel,
    TimeStampedModel,
    models.Model
):
    company = models.ForeignKey(Company, on_delete=models.CASCADE)
    employee = models.ForeignKey(UserWorkerProfile)
    employed_by = models.ForeignKey(UserOwnerProfile)

I tried using company.employment_set.values("employee"), but this returns a strange activatorquery set. Is there a way to return the normal queryset? Or is values() already the correct method?

Edit: To eloborate a little more: I want to end up with a queryset containing all the UserWorkerprofile model instances.

In the documentation for values() it says:

Returns a QuerySet that returns dictionaries, rather than model instances, when used as an iterable.

and I want exactly a queryset of model instances.

Upvotes: 2

Views: 2067

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477794

Based on your comment, you want all UserWorkerProfiles that have a (there can be zero, one or more) related Employment instances an Employment instance that has as Company (every Employment has exactly one company), a given company.

We can query such UserWorkingProfiles with the following query:

UserWorkingProfile.objects.filter(employment__company=some_comany)

So this queryset will return all UserWorkingProfiles for which there exists an Employment instance that links to the given company some_company and that UserWorkingProfile.

In Django one uses two consecutive underscores to look "through" a relation (this can be used in bidirectionally, note that two consecitive underscores are used for other things than looking through relations).

We thus wrote a query that looks, more or less like:

SELECT `userworkingprofile`.*
FROM `userworkingprofile`
JOIN `employment` ON `employment`.`employee_id` = `userworkingprofile`.`id`
WHERE `employment`.`company_id` = 123

With 123 in reality the pk of some_company.

Note that it is possible that the same UserWorkingProfile occurs multiple times in this queryset, if the employee has worked several times for some_company.

If you want every UserWorkingProfile to occur at most once, you should add .distinct() to it:

UserWorkingProfile.objects.filter(employment__company=some_comany).distinct()

Although Django indeed defines a object manager named employment_set on a Company instance, as far as I know you can not "combine" two such managers (so some_company.employment_set.employee will not work).

Upvotes: 2

Related Questions