【问题标题】:Override Django (DRF) Serializer object GET覆盖 Django (DRF) 序列化程序对象 GET
【发布时间】:2021-05-09 19:16:13
【问题描述】:

我正在尝试将一些 raw sql“注入”到我的 DRF 嵌套序列化程序中:

# SERIALIZERS

class CarSerializer(serializers.ModelSerializer):

    class Meta:
        model = Car
        fields = '__all__'

class DriverSerializer(serializers.ModelSerializer):
    car = CarSerializer()   # <--- here I don't want to get the Car object but rather inject a raw sql.

    class Meta:
        model = Driver
        fields = '__all__'

由于我使用的是 MariaDB 版本控制表,因此需要 SQL 注入来请求特定版本的数据,但这无关紧要。如何覆盖从CarSerializer 获取对象的方法?谢谢。

【问题讨论】:

    标签: django django-rest-framework django-serializer


    【解决方案1】:

    这是未经测试的,但我认为您想覆盖 DriverSerializer 中的 __init__,然后通过 data 加载原始 SQL 的结果,如下所示:

    class DriverSerializer(serializers.ModelSerializer):
         [...]
         def __init__(self, *args, **kwargs):
              super(DriverSerializer, self).__init__(*args, **kwargs)
              name_map = {'column_1': 'obj_attr_1', 'column_2': 'obj_attr_1', 'pk': 'id'}
              raw = Car.objects.raw('SELECT ... FROM ...', translations=name_map)
              data = {k: getattr(raw[0], k) for k in name_map.keys()}
              self.car = CarSerializer(data=data)
    

    【讨论】:

    【解决方案2】:

    你可以在你的模型下定义方法来获取相关的 Car

    class Car(models.Model):
    
        def current_car(self):
            return Car.objects.raw('SELECT ... FROM ...')[0]
    

    然后在序列化器中你可以重用下面的方法

    class DriverSerializer(serializers.ModelSerializer):
        car = CarSerializer(source="current_car")
    
        class Meta:
            model = Driver
            fields = (...)
    

    【讨论】:

    • 嗨@iklinac 我可以将参数传递给current_car 方法吗?就像我要获取的汽车版本的时间戳一样
    • 这个时间戳是从哪里来的,是现在吗?
    • 在我的情况下来自另一个序列化程序。假设它来自DriverSerializer
    【解决方案3】:

    感谢大家的回答,尽管我的解决方案不如@yvesonline 和@iklinak 建议的那样干净,但我设法使它工作:

    我首先查看了关于覆盖序列化程序的官方 DRF 文档:https://www.django-rest-framework.org/api-guide/serializers/#overriding-serialization-and-deserialization-behavior

    我特别感兴趣的是方法的覆盖:.to_representation(self, instance),它控制从数据库中获取对象:

    from datetime import datetime as dt
    from collections import OrderedDict
    from rest_framework.relations import PKOnlyObject
    from rest_framework.fields import SkipField, empty
    
        def __init__(
                self, instance=None, data=empty, asTime=str(dt.now()), **kwargs):
            self.asTime = asTime
            self.instance = instance
            if data is not empty:
                self.initial_data = data
            self.partial = kwargs.pop('partial', False)
            self._context = kwargs.pop('context', {})
            kwargs.pop('many', None)
            super().__init__(**kwargs)
    
        def to_representation(self, instance):
            # substitute instance with my raw query
            # WARNING: self.asTime is a custom variable, check the
            # __init__ method above!
    
            instance = Car.objects.raw(
                '''
                        select * from db_car
                        for system_time as of timestamp %s
                        where id=%s;
                    ''', [self.asTime, instance.id])[0]
    
            ret = OrderedDict()
            fields = self._readable_fields
    
            for field in fields:
                try:
                    attribute = field.get_attribute(instance)
                except SkipField:
                    continue
    
                check_for_none = attribute.pk if isinstance(
                    attribute, PKOnlyObject) else attribute
                if check_for_none is None:
                    ret[field.field_name] = None
                else:
                    ret[field.field_name] = field.to_representation(attribute)
    
            return ret
    

    您可以在这里找到原始代码:https://github.com/encode/django-rest-framework/blob/19655edbf782aa1fbdd7f8cd56ff9e0b7786ad3c/rest_framework/serializers.py#L335

    然后终于在DriverSerializer类中:

    class DriverSerializer(serializers.ModelSerializer):
        car = CarSerializer(asTime='2021-02-05 14:34:00')
    
        class Meta:
            model = Driver
            fields = '__all__'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-30
      • 1970-01-01
      • 1970-01-01
      • 2019-11-20
      • 1970-01-01
      相关资源
      最近更新 更多