简体   繁体   中英

Django. How do I add a field to a query result?

I have a Room model and I want to add the is_member boolean field to a queryset with rooms. How can do this? I was thinking of using .annotate () , but that doesn't work for my task.

models.py

from django.db import models

class Room(models.Model):
    name = models.CharField(max_length=150)
    members = models.ManyToManyField(User, blank=True)

views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import RoomSerializer
from .models import Room

class RoomView(APIView):
    def get(self, request):
        rooms = Room.objects.all() # get all rooms
        user = request.user # get current user

        for room in rooms:
            members = room.members.all() # get members
            is_member = user in members # set boolean value
            room.is_member = is_member # set in room

        serializer = RoomSerializer(rooms, many=True)
        return Response(serializer.data)

serializers.py

from rest_framework import serializers
from .models import Room

class RoomSerializer(serializers.ModelSerializer)
    is_member = serializers.BooleanField(read_only=True)
    
    class Meta:
        model = Room
        fields = "__all__"
    

I solved this issue this way, but is there any other options to do it? Help me please

When you are using an M2M like this, you could use your own through model rather than have django do it automatically.

That gives you the ability to add your own fields to the relationship, or properties or customise the manager/queryset.

Docs for this are here; https://docs.djangoproject.com/en/3.1/topics/db/models/#extra-fields-on-many-to-many-relationships

So by querying the through model, you could establish if a user was a member of a given room.

A very rough example of a custom through model approach;


class Room(models.Model):
    users = models.ManyToManyField("User", through=ThroughModel)

class User(models.Model):
    text = models.TextField()

class ThroughModel(models.Model):
    room_id = models.ForeignKey(Room)
    user_id = models.ForeignKey(User)
    is_member = models.BooleanField()

# this will return a list of ThroughModel objects
ThroughModel.objects.filter(user=instance_of_user, is_member=True)

# this will return a list of A objects based on an extra field on the through table
Room.objects.filter(users__ThroughModel__is_member=True)

# keep in mind that limiting by one of the foreign keys on the through model is easier
Room.objects.filter(users=instance_of_user)

Can you try this. This will not add is_member in a queryset but i think you are looking for something like this.

#  Serializer
class RoomSerializer(serializers.ModelSerializer):
    is_member = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = Room
        fields = "__all__"

    def get_is_member(self, obj):
        user = self.context["request"].user
        if user in obj.members.all():
            return True
        return False

#  View
class RoomView(APIView):
    def get(self, request):
        rooms = Room.objects.prefetch_related("members").all()  # get all rooms
        serializer = RoomSerializer(rooms, context={"request": request}, many=True)
        return Response(serializer.data)

And you should get the desired response

[
    {
        "id": 1,
        "is_member": true,
        "name": "first",
        "members": [
            1
        ]
    },
    {
        "id": 2,
        "is_member": true,
        "name": "second",
        "members": [
            1,
            2
        ]
    }
]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM