Given a bunch of graphical maps, I need to query which maps a user has access to, either because he owns the map or because he has been granted 'membership' of it.
There is a Map_desc (Map description) model, and for each object in Map_desc, potentially many Mapmembership objects.
Because it will later be fed to ModelChoiceFields in templates, I need a single QuerySet that will return all the Map_desc objects that have related Mapmembership objects, plus all the Map_desc objects that have 'owner' set to the current user.
It's a simple join, but surprisingly difficult to pull off in Django.
models.py (simplified)
class Map_desc(models.Model):
owner = models.ForeignKey(User, null=False, on_delete=models.CASCADE)
class Mapmember(models.Model):
member = models.ForeignKey(User, null=False, on_delete=models.CASCADE)
ofmap = models.ForeignKey(Map_desc, null=False, on_delete=models.CASCADE)
What I tried first that didn't work (in semi-pseudo code):
shared = Map_desc.objects.filter(id=mapmember_set.ofmap)
then a second query to get the Maps owned:
owned = Map_desc.objects.filter(owner=thisUser)
and tying them together with
accessiblemaps = chain(shared,owned)
The problem is that because there are multiple Map_desc objects, mapmember_set is not actually available. It does work if you limit the query to just one Map_desc, using .first(), and this is what all the tutorials and SO questions I've found do.
So I came up with the following solution, which does work, but I'm wondering if there are more efficient ways, or just different ways that would help me understand how the ORM is meant to be used for Joins involving multiple "parent object" rows.
views.py
from django.db.models import Q
def all_accessible_maps(request, thisUser):
# Returns maps thisUser has access to, whether owned or as a 'member'
try:
sharedmaps = Mapmember.objects.filter(member=thisUser).values_list('ofmap')
allaccessible = Map_desc.objects.filter(Q(id__in=sharedmaps) | Q(owner=thisUser))
except:
raise
all_accessible_maps.alters_data = True