首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >查询集返回响应自定义

查询集返回响应自定义
EN

Stack Overflow用户
提问于 2019-03-01 23:28:26
回答 3查看 2.8K关注 0票数 1

我是Django restframework的新手,我现在尝试的是返回带有外键的对象。

代码语言:javascript
复制
class User(models.Model):
    name = models.CharField(max_length=255,blank=True)
    date_created = models.DateTimeField(auto_now_add=True)
    date_modiefied = models.DateTimeField(auto_now=True)
    area = models.CharField(max_length=255,blank=True)
    uuid = models.CharField(max_length=255)
    home = models.CharField(max_length=255,blank=True)
    work = models.CharField(max_length=255,blank=True)
    mobileNo = models.CharField(max_length=255,blank=True)
    email = models.CharField(max_length=255,blank=True)
    appVersionCode = models.CharField(max_length=255,blank=True)
    photoUrl = models.CharField(max_length=255,blank=True)
    serverTime = models.CharField(max_length=255,blank=True)
    fcmTokenId = models.CharField(max_length=255,blank=True)
   def __str__(self):
    return self.name

class LocationData(models.Model):
   user = models.ForeignKey(
     User, related_name='user', on_delete=models.DO_NOTHING)
    source_id = models.CharField(max_length=255)
    latitude = models.CharField(max_length=255)
    longitude = models.CharField(max_length=255)
    speed = models.CharField(max_length=255)
    kms = models.CharField(max_length=255)
    date_created = models.DateTimeField(auto_now=True)
    date_modiefied = models.DateTimeField(auto



class UserSerializer(serializers.ModelSerializer):
  class Meta:
    model = User
    fields = '__all__'

class LocationDataSerializer(serializers.ModelSerializer): 

class Meta:
    model = LocationData
    fields = '__all__'
    depth = 1

我使用的是def get_queryset(self):

代码语言:javascript
复制
class SyncIndexLastDataViewSet(viewsets.ModelViewSet):
serializer_class = LocationDataSerializer

def get_queryset(self):

    userid = self.request.query_params.get('user_id', None)
    userExist = User.objects.filter(id=userid)
    if userExist.exists():
        # call the original 'list' to get the original response
        queryset = LocationData.objects.values('source_id').filter(user__id=userid).order_by('-source_id')[:1]
        lastSourceId = queryset[0]['source_id']
        response = {"collection": {"data": lastSourceId,"statusCode": status.HTTP_200_OK,"version":"1.0"}}
        json = JSONRenderer().render(response)
        # customize the response data
        if response is not None:
            return json
    else:
        # return response with this custom representation
        response = {"collection": {"data": "","statusCode":status.HTTP_404_NOT_FOUND,"version":"1.0","error":"Not found"}}
        return response

现在,结果在下面的响应中,它立即抛出这个错误

但我希望该查询集返回如下所示的值,因此我可以在android中读取这些键对的值

代码语言:javascript
复制
{ "collection": {
  "data": {
    "id": 31,
    "source_id": "55",
    "latitude": "24654",
    "longitude": "454654",     
    "date_created": "2019-02-08T17:10:09.318644Z",
    "date_modiefied": "2019-02-08T17:10:09.318714Z",
    "area": "54546",
    "user": {
        "id": 1,
        "name": "Dormy",
        "date_created": "1992-01-18T03:29:53.388000Z",
        "date_modiefied": "2018-02-19T05:17:00.164000Z",
        "serverTime": "",
        "fcmTokenId": ""
      }
  },
    "statusCode": 200,
    "version": "1.0"
 }

现在错误抛出

AttributeError:尝试获取序列化程序LocationDataSerializer上的字段source_id的值时获取了AttributeError。序列化程序字段的命名可能不正确,并且与int实例上的任何属性或键都不匹配。原始异常文本为:'int‘对象没有属性'source_id’。

谢谢!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-03-04 00:53:19

因为get_queryset不允许您自定义响应数据。我决定采用对我来说很重要的查询值。

用户-->修改为...api//1

代码语言:javascript
复制
 def retrieve(self, request, *args, **kwargs):
    """ userid = self.request.query_params.get('user_id', None) """

    userid = kwargs.get('pk')
    userExist = User.objects.filter(id=userid)
    if userExist.exists():
        # call the original 'list' to get the original response
        queryset =  LocationData.objects.values('source_id').filter(user__id=userid).order_by('-source_id')[:1]
        lastSourceId = queryset[0]['source_id']
        response = {"collection": {"data": lastSourceId,"statusCode": status.HTTP_200_OK,"version":"1.0"}}
        # customize the response data
        if response is not None:
            return Response(response)
    else:
        # return response with this custom representation
        response = {"collection": {"data": "","statusCode":status.HTTP_404_NOT_FOUND,"version":"1.0","error":"Not found"}}
        return response
票数 1
EN

Stack Overflow用户

发布于 2019-03-01 23:40:00

这个问题的答案取决于您所使用的视图类型,但底线是,您不是在get_queryset中执行此操作,而是在reguest类型的方法中执行此操作。

例如,如果您使用的是RetrieveAPIView,则应该覆盖RetrieveModelMixin中的retrieve方法,如下所示:

代码语言:javascript
复制
class MyAPIView(RetrieveAPIView):
    queryset = MyModel.objects.all()
    serializer_class = MySerializer

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        data = {
            "collection": {
                "data": serializer.data
            },
            "statusCode": 200,
            "version": "1.0"
        }
        return Response(data)

如果您正在使用其他东西,比如ListAPIView,那么您希望查看相关方法中使用了什么,并覆盖它来包装您的数据。

这里要意识到的主要事情是,它与获取查询集无关-这只是从数据库中获取数据。这是关于在发回响应时将数据转换为正确的格式。因此,这项工作应该在做出响应的时候完成。

票数 5
EN

Stack Overflow用户

发布于 2019-03-02 00:31:03

对于这个问题,有几种可能的解决方案。NDevox已经提到了如何重写retrive函数并获得预期的响应。但如果我们想要这样做,每个api端点的每个响应都会这样做,如果我们这样做,我们需要重写每个函数,那么它就相当麻烦,而且它的DRY,我们应该尽可能避免这种情况。引入中间件或重写Response的一种可能的方法是,我们可以获得对每个api端点的通用响应,而无需显式地重写每个功能。

可能的解决方案一

因为我们在这里使用的是DRF,所以我们可以添加我们自己的带有各种媒体类型的返回响应,比如application/json

首先,我们需要在settings.py中添加

代码语言:javascript
复制
REST_FRAMEWORK = {
    ...
    'DEFAULT_RENDERER_CLASSES': (
        'app_name.renderers.ApiRenderer',  # our own render middleware
    ),
    ...
}

在我们的自定义渲染中间件中

代码语言:javascript
复制
from rest_framework.renderers import BaseRenderer
from rest_framework.utils import json


class ApiRenderer(BaseRenderer):

    def render(self, data, accepted_media_type=None, renderer_context=None):
        our_response_dict = {
            'version': '1.0'
            'data': {},
            'message': '',
        }
        if data.get('data'):
            our_response_dict['data'] = data.get('data')
        if data.get('status'):
            our_response_dict['statusCode'] = data.get('status')
        if data.get('message'):
            our_response_dict['message'] = data.get('message')
        data = our_response_dict
        return json.dumps(data)

参考Link

可能的解决方案二

如果我们使用ModelViewset,那么还有另一种方法可以实现这一点。假设我们的Views.py如下所示

代码语言:javascript
复制
class A(serializer.ModelSerializer):
    ........

class B(serializer.ModelSerializer):
    ........


class C(serializer.ModelSerializer):
    ........

我们的目标是覆盖ModelViewset的to_representation函数并返回自定义结果。

代码语言:javascript
复制
from collections import OrderedDict

class OurParentViewset(serializer.ModelSerializer):

    ......
    def to_representation(self, instance):
        data = super(serializers.ModelSerializer, self).to_representation(instance)
        result = OrderedDict()
        result['data'] = data
        result['version'] = '1.0'
        result['statusCode'] = '2xx' # i am not fully sure how to customize this
        return result

    class A(OurParentViewset):
        ........

    class B(OurParentViewset):
        ........


    class C(OurParentViewset):
        ........
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54947665

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档