覆盖 Django (DRF) 序列化程序对象 GET
Override Django (DRF) Serializer object GET
我正在尝试将一些 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__'
需要 SQL 注入来请求特定版本的数据,因为我使用的是 MariaDB 版本控制表,但这无关紧要。如何覆盖从 CarSerializer
获取对象的方法?谢谢。
这是未经测试的,但我认为您想覆盖 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)
您可以在您的模型下定义方法来获取相关的汽车
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 = (...)
谢谢大家的回答,尽管我的解决方案不如@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
然后终于在DriverSerializer
class:
class DriverSerializer(serializers.ModelSerializer):
car = CarSerializer(asTime='2021-02-05 14:34:00')
class Meta:
model = Driver
fields = '__all__'
我正在尝试将一些 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__'
需要 SQL 注入来请求特定版本的数据,因为我使用的是 MariaDB 版本控制表,但这无关紧要。如何覆盖从 CarSerializer
获取对象的方法?谢谢。
这是未经测试的,但我认为您想覆盖 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)
您可以在您的模型下定义方法来获取相关的汽车
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 = (...)
谢谢大家的回答,尽管我的解决方案不如@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
然后终于在DriverSerializer
class:
class DriverSerializer(serializers.ModelSerializer):
car = CarSerializer(asTime='2021-02-05 14:34:00')
class Meta:
model = Driver
fields = '__all__'