djangodjango-serializer

How to Query If An Instance Exists Within A Many-To-Many Field On Django Queryset


Here are simplified model definitions

class Resource(models.Model):
    name = models.CharField(max_length=100, unique=True)

class Location(models.Model):
    name = models.CharField(max_length=100, unique=True)
    resources = models.ManyToManyField(Resource)

And I want to know for one type of Resource, the existence on each Location. So the json data I want is like

[
    {
        "id": 1,
        "name": "loaction_A",
        "resource": true
    }, 
    {
        "id": 2
        "name": "location_B",
        "resource": false
    },
    ...
]

I tried following view function but obviously got wrong results.

def resource_view(request, res_id):
    res = get_object_or_404(Resource, pk=res_id)
    locations = Location.objects.values('id', 'name')\
        .annotate(resource=Q(resources=res))
    return JsonResponce({'locations': list(locations)})

I know I need something like below (in SQL)

select
    app_location.*,
    1 in (
        select resource_id
        from app_location_resources
        where location_id = app_location.id
    ) as resource
from app_location

How should I construct the queryset?


Solution

  • A slightly more efficient way could be:

    from django.db.models import Exists, OuterRef
    
    locations = Location.objects.annotate(
        resource=Exists(
            Location.resources.through.objects.filter(
                location_id=OuterRef('pk'), resource_id=res_id
            )
        )
    )

    I would however advise to user a proper serializer like in the Django REST framework and perhaps use the Django REST framework: the serializer can then work bi-directional and for example makes it possible to render data in a comma-separated value (.csv) format.