Assuming the following models showing only the relevant porytions
class PlantProfile(Base):
latin_name = models.CharField(max_length=75, unique=True)
english_name = models.CharField(max_length=75, blank=True)
french_name = models.CharField(max_length=75, blank=True)
class ProjectUser(AbstractUser):
plants = models.ManyToManyField(PlantProfile, through="PlantCollection")
class PlantCollection(models.Model):
owner = models.ForeignKey(ProjectUser, on_delete=models.CASCADE)
plants = models.ForeignKey(PlantProfile, on_delete=models.CASCADE)
details = models.CharField(max_length=125, blank=True)
class Meta:
constraints = [
models.UniqueConstraint(name="unique_plant_owner", fields=["owner", "plants"]),
]
How can I query PlantProfile and get the owner (or a boolean) assuming that the current logged in user has the plant in his collection (bool True). I am not sure if I make myself clear.
Output would be 4 fields : latin_name, french_name, english_name, owner
owner would be either true or false. True if plant is part of the collection of the user
I’m sorry, I’m not sure I’m understanding what you’re asking for here.
Are you asking for a list of all PlantProfile
, with a field indicating whether the current user is related to each instance?
Or are you only looking for a list containing those PlantProfile
where the ProjectUser
is related to it?
I am asking for a list of all PlantProfile
that would include the field owner in a column.
Maybe the image will help. It shows a list of all the plants (PlantProfile). If a plant is in the PlantCollection of the current user, then in the last column (My Plant) indicate True.
You’re still asking for two different things here.
Do you want a column containing the owner(s), or do you want the indicator showing whether the requesting user is related? (These are two different queries.)
Sorry Ken, I did not realize it was 2 different queries. I want the indicator showing whether the requesting user is related.
But I would be curious to know how the two queries differ.
The best I can do for now is using this strategy within the template, but I am not convinced it’s the most efficient way.
{% for item in object_list %}
...
<td>
{% for i in item.plantcollection_set.all %}
{% if i.owner == request.user %}Yes{% endif %}
{% endfor %}
</td>
...
{% endfor %}
No, that’s not particularly good - it doesn’t scale well.
The best I’ve been able to come up with so far is this:
plant_profile_query = PlantProfile.objects.annotate(is_owner =
Coalesce(
Subquery(
PlantCollection.objects.filter(
owner=request.user, plants=OuterRef('pk')
).annotate(owns=Value('Yes')).values('owns')
), Value('No')
)
)
If a PlantCollection
exists relating a PlantProfile
with a ProjectUser
, the filter in the subquery will return the value “Yes”. If the filter fails to find a match, the Coalesce
function will return the value “No”.
The is_owner
annotated attribute will then have either “Yes” or “No” for each instance of PlantProfile
.
1 Like
YES!! That’s pretty awesome. It works