【问题标题】:Django: Make a GET Request to a URL that is advancedDjango:向高级 URL 发出 GET 请求
【发布时间】:2019-11-20 05:46:03
【问题描述】:

所以我有聊天室和消息。然后我有两个网址:/messages 和 /rooms。这些会显示您所有的房间和消息。也可以将消息分配给房间。因此,在 Room API 中,我将消息分配给了该房间。

假设房间名为“Room1”,消息是“嘿”、“哟”和“wassup”。如果我只向 /messages 发出请求,我将收到所有消息。假设只有两条消息分配给“Room1”,另一条消息分配给另一个未命名的房间。

我想要一种方法来发出获取请求,并且只将这两条消息分配给 'Room1 with id = 3' (localhost:8000/rooms/3/messages) 而不是:(localhost:8000/messages)。

这是我向 /rooms/3/ 发出获取请求时的示例

   {
    "id": 3,
    "name": "Room 1",
    "members": [
    {
        "id": 1,
        "username": "william"
    },
    {
        "id": 2,
        "username": "eric"
    },
    {
        "id": 3,
        "username": "ryan"
    }
  ],
  "messages": [
    {
        "id": 7,
        "content": "hej",
        "date": "2019-07-08",
        "sender": {
            "id": 1,
            "username": "william"
        }
    },
    {
        "id": 8,
        "content": "yoyo",
        "date": "2019-07-08",
        "sender": {
            "id": 2,
            "username": "eric"
        }
    },
    {
        "id": 9,
        "content": "tjo bror",
        "date": "2019-07-08",
        "sender": {
            "id": 3,
            "username": "ryan"
        }
    },
    {
        "id": 10,
        "content": "hej jag heter Eric och jag gar pa polhemskolan i lund och jag ar 17 ar gammal",
        "date": "2019-07-08",
        "sender": {
            "id": 2,
            "username": "eric"
        }
    },
    {
        "id": 11,
        "content": "vi vet hahah",
        "date": "2019-07-09",
        "sender": {
            "id": 1,
            "username": "william"
        }
    },
    {
        "id": 12,
        "content": "amen sluta",
        "date": "2019-07-09",
        "sender": {
            "id": 2,
            "username": "eric"
        }
    }
 ]
 }

如果我执行 rooms/3/messages,这就是我想要得到的回应:

       "messages": [
    {
        "id": 7,
        "content": "hej",
        "date": "2019-07-08",
        "sender": {
            "id": 1,
            "username": "william"
        }
    },
    {
        "id": 8,
        "content": "yoyo",
        "date": "2019-07-08",
        "sender": {
            "id": 2,
            "username": "eric"
        }
    },
    {
        "id": 9,
        "content": "tjo bror",
        "date": "2019-07-08",
        "sender": {
            "id": 3,
            "username": "ryan"
        }
    },
    {
        "id": 10,
        "content": "hej jag heter Eric och jag gar pa polhemskolan i lund och jag ar 17 ar gammal",
        "date": "2019-07-08",
        "sender": {
            "id": 2,
            "username": "eric"
        }
    },
    {
        "id": 11,
        "content": "vi vet hahah",
        "date": "2019-07-09",
        "sender": {
            "id": 1,
            "username": "william"
        }
    },
    {
        "id": 12,
        "content": "amen sluta",
        "date": "2019-07-09",
        "sender": {
            "id": 2,
            "username": "eric"
        }
    }
  ]
  }

Django 模型:

class UserProfile(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)

class Meta:
     verbose_name_plural = 'All Users'

def __str__(self):
     return self.user.username

@receiver(post_save, sender=User)
def create_user_data(sender, update_fields, created, instance, **kwargs):
if created:
    user = instance
    profile = UserProfile.objects.create(user=user)

class Message(models.Model):
    sender = models.ForeignKey(UserProfile, on_delete=models.CASCADE,  related_name="sendermessage")
    content = models.CharField(max_length=500)
    date = models.DateField(default=date.today)
    canview = models.ManyToManyField(UserProfile, blank=True, related_name="messagecanview")

class Meta:
    verbose_name_plural = 'Messages'

def __str__(self):
    return "{sender}".format(sender=self.sender)

class Room(models.Model):
    name = models.CharField(max_length=50)
    members = models.ManyToManyField(UserProfile, blank=True)
    messages = models.ManyToManyField(Message, blank=True)

class Meta:
    verbose_name_plural = 'Rooms'

def __str__(self):
    return "{name}".format(name=self.name)enter code here

Django 序列化器:

class UserProfileSerializer(serializers.ModelSerializer):
    username = serializers.CharField(source='user.username')
    class Meta:
        model = UserProfile
        fields = ('id', 'username')

class MessageSerializer(serializers.ModelSerializer):
    sender = UserProfileSerializer()
    class Meta:
        model = Message
        fields = ('id', 'content', 'date', 'sender')

class RoomSerializer(serializers.ModelSerializer):
    messages = MessageSerializer(many=True)
    members = UserProfileSerializer(many=True)
    class Meta:
        model = Room
        fields = ('id', 'name', 'members', 'messages')

Django 视图:

class UserProfileView(viewsets.ModelViewSet):
    http_method_names = ['get', 'post', 'put', 'delete', 'patch']
    queryset = UserProfile.objects.all()
    serializer_class = UserProfileSerializer

class MessageView(viewsets.ModelViewSet):
    http_method_names = ['get', 'post', 'put', 'delete', 'patch']
    queryset = Message.objects.all()
    serializer_class = MessageSerializer

class UserMessageView(MessageView):
def get_queryset(self):
    return Message.objects.filter(canview__user=self.request.user)

class RoomView(viewsets.ModelViewSet):
    http_method_names = ['get', 'post', 'put', 'delete', 'patch']
    queryset = Room.objects.all()
    serializer_class = RoomSerializer

class UserRoomView(RoomView):
def get_queryset(self):
    return Room.objects.filter(members__user=self.request.user)

Django 网址:

 router = routers.DefaultRouter()
 router.register('users', views.UserProfileView),
 router.register('rooms', views.UserRoomView),
 router.register('messages', views.UserMessageView),

urlpatterns = [
    path('', include(router.urls)),
]

【问题讨论】:

  • 你能写出一个例子吗? :)
  • 在我看来,localhost:8000/messagesMessage 资源的所在地,因此您应该对其进行过滤,而不是在房间下方创建路径。我会证明这一点的。

标签: django api django-models django-rest-framework django-views


【解决方案1】:

要将所有Messages 分配到一个房间,让我们:

安装 django-filter:

pip install django-filter

修改Room模型以指定related_name

class Room(models.Model):
    name = models.CharField(max_length=50)
    members = models.ManyToManyField(UserProfile, blank=True)
    messages = models.ManyToManyField(Message, blank=True, related_name='rooms')
    #                                                    ^^^^^^^^^^^^^^^^^^^^^^

rooms相关字段启用过滤:

import django_filters
import rest_framework.filters

[...]

class MessageView(viewsets.ModelViewSet):
    # vvvvvvvvvvv  I don't think this line is needed vvvvvvvvvvvvvv
    # http_method_names = ['get', 'post', 'put', 'delete', 'patch']
    queryset = Message.objects.all()
    serializer_class = MessageSerialize

    filter_backends = (
        django_filters.rest_framework.DjangoFilterBackend, 
        rest_framework.filters.OrderingFilter,
    )
    filter_fields = ['rooms']

然后,您可以使用GET 向该房间请求所有消息:

localhost:8000/messages/?rooms=3

评论问题:

您还需要公开Message 对象的sender 字段。目前是别名:

class MessageSerializer(serializers.ModelSerializer):
    #     vvvv                         vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    sender_obj = UserProfileSerializer(source='sender', read_only=True)
    class Meta:
        model = Message
        fields = ('id', 'content', 'date', 'sender', 'sender_obj')
        #                                          ^^^^^^^^^^^^^^

然后你可以POST/message 与数据{"content": "blah", "date": "2019-07-09","sender": 1}

【讨论】:

  • 糟糕。 filters 默认情况下不会从库中导出。将导入更改为import rest_framework.filters
  • 谢谢队友,但是当我向 url 发出 post 请求时,我得到 NOT NULL 约束失败:chat_message.sender_id
  • POST 是另一笔交易。看起来您需要 POST 上的有效 sender 字段。
  • 由于某种原因,这不起作用:"sender": {"username": "william"},注意这是一个多对多字段关系
  • 另外,如果我帮助了你,请点赞,然后接受我的回答。我会继续与您​​合作。
猜你喜欢
  • 2012-06-14
  • 1970-01-01
  • 1970-01-01
  • 2019-02-05
  • 1970-01-01
  • 1970-01-01
  • 2019-11-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多