Queryset返回响应自定义

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (54)

我对Django的restframework很新,我现在正在尝试用foreignkey返回对象。

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):

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中的那些键对值

{ "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:尝试source_id在序列化程序上获取字段值时获得AttributeError LocationDataSerializer。序列化程序字段可能名称不正确,并且与int实例上的任何属性或键都不匹配。原始异常文本是:'int'对象没有属性'source_id'。

谢谢!

提问于
用户回答回答于

这个问题的答案取决于您使用的是哪种类型的视图,但最重要的是,您不会在get_querysetreguest类型的方法中执行此操作。

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

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的其他内容,那么您希望在相关方法中查看其使用的内容并覆盖它以包装您的数据。

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

用户回答回答于

在这里实现自定义渲染器似乎是一种方法。

您可以从您的Android客户端请求包含在Accept标题中的方式来识别渲染器的客户端。1 例如

Accept: application/json; android=true

然后使用JSONRenderer类创建一个渲染器,为您的Android客户端提供格式。

# ./formatters/android_format.py

from rest_framework.renderers import JSONRenderer, BaseRenderer
from django.http.multipartparser import parse_header

class AndroidV1FormatRenderer(BaseRenderer):
    media_type = 'application/json'
    format = 'json'

    json_renderer = JSONRenderer()

    def android(self, accepted_media_type):
        base_media_type, params = parse_header(accepted_media_type.encode('ascii'))
        return 'android' in params

    def render(self, data, accepted_media_type=None, renderer_context=None):
        response = renderer_context['response']
        android = self.android(accepted_media_type)
        if android:
            data = {
                "collection": {"data": data},
                "statusCode": response.status_code,
                "version": "1.0"
            }

        return json_renderer.render(
            wrapped_data, accepted_media_type, renderer_context)

然后可以在需要使用renderer_classes您的属性以这种方式格式化响应的地方使用它APIView2

扫码关注云+社区

领取腾讯云代金券