当我在django-rest0-framework中创建一个基于ModelSerializer的Serializer时,我将不得不在Meta类中传递模型:
class ClientSerializer(ModelSerializer):
class Meta:
model = Client
我想创建一个通用序列化程序,它基于URL动态地包含模型。
我的设置包括urls.py和viewset:
urls.py:
url(r'^api/v1/general/(?P<model>\w+)', kernel_api_views.GeneralViewSet.as_view({'get':'list'}))
和views.py:
class GeneralViewSet(viewsets.ModelViewSet):
def get_queryset(self):
# Dynamically get the model class from myapp.models
queryset = getattr(myapp.models, model).objects.all()
return queryset
def get_serializer_class(self):
return getattr(myapp.serializers, self.kwargs['model']+'Serializer')
关注:http://127.0.0.1:8000/api/v1/general/Client将Client.objects.all()作为queryset,将ClientSerializer类作为序列化程序
问题:我怎样才能这样做,以便我可以打电话给GeneralSerializer&#39;并动态分配模型?
答案 0 :(得分:12)
您可以通过以下方式完成此操作:
serializers.py
class GeneralSerializer(serializers.ModelSerializer):
class Meta:
model = None
<强> views.py 强>
class GeneralViewSet(viewsets.ModelViewSet):
def get_queryset(self):
model = self.kwargs.get('model')
return model.objects.all()
def get_serializer_class(self):
GeneralSerializer.Meta.model = self.kwargs.get('model')
return GeneralSerializer
在serializers.py
中,我们将GeneralSerializer
model
Meta
定义为None
model
。我们会在致电get_serializer_class()
时覆盖views.py
值。
然后在我们的GeneralViewSet
文件中,我们定义get_queryset()
,其中get_serializer_class()
和get_queryset()
被覆盖。
在model
中,我们从kwargs
获取get_serializer_class()
的值并返回该查询集。
在model
中,我们将GeneralSerializer
的{{1}}值设置为从kwargs
获取的值,然后返回GeneralSerializer
。
答案 1 :(得分:4)
到目前为止,我知道如果使用模型序列化程序,则无法创建通用序列化程序,但是您可以使用基类获取相同的解决方案,并从该基类派生所有模型。实现返回序列化程序的方法,然后使用该方法生成动态序列化程序。我在过去的两年里使用这种技术,对我来说工作得非常好 -
class BaseModel(models.Model):
class Meta:
abstract = True # define abstract so that it does not cause any problem with model hierarchy in database
@classmethod
def get_serializer(cls):
class BaseSerializer(serializers.ModelSerializer):
class Meta:
model = cls # this is the main trick here, this is how I tell the serializer about the model class
return BaseSerializer #return the class object so we can use this serializer
现在从中推导出你的模型 -
class Derived1(BaseModel):
pass
class Derived2(BaseModel):
pass
如果要覆盖序列化程序,那么只需在您需要的那个中执行。例如 -
class DerivedOverride(BaseModel):
@classmethod
def get_serializer(cls):
super_serializer = BaseModel.get_serializer() # this important to not to break the serializing hierarchy
class BaseSerializer(super_serializer):
class Meta:
model = cls # this is the main trick here, this is how I tell the serializer about the model class
return BaseSerializer
多数民众赞成,现在每个类都有自己的动态序列化器,但我们只是在一个地方定义它。
现在在视图集中使用序列化程序 -
class Derive1ViewSet(ModelViewSet):
serializer_class = Derived1.get_serializer()
class Derive2ViewSet(ModelViewSet):
serializer_class = Derived2.get_serializer()
然后继续。
答案 2 :(得分:2)
以Rahul的答案为基础,这对我有用:
urls.py
url(r'^api/(?P<app_label>\w+)/(?P<model_name>\w+)', GeneralViewSet.as_view({'get': 'list'}))
serializers.py
from rest_framework import serializers
class GeneralSerializer(serializers.ModelSerializer):
class Meta:
model = None
views.py
from django.apps import apps
class GeneralViewSet(viewsets.ModelViewSet):
@property
def model(self):
return apps.get_model(app_label=str(self.kwargs['app_label']), model_name=str(self.kwargs['model_name']))
def get_queryset(self):
model = self.model
return model.objects.all()
def get_serializer_class(self):
GeneralSerializer.Meta.model = self.model
return GeneralSerializer
答案 3 :(得分:1)
除了@Rahul和@btal外,我们还可以在ModelSerializer
上使用装饰器模式,以防万一我们想使用APIView
。
def getGenericSerializer(model_arg):
class GenericSerializer(serializers.ModelSerializer):
class Meta:
model = model_arg
fields = '__all__'
return GenericSerializer
并在APIView中像这样使用它:
class MyView(APIView):
def get(self, request, format=None):
#...
GenericSzl = getGenericSerializer(model)
serializer = GenericSzl(objs, many=True)
return Response(serializer.data)
希望这对不想使用ModelViewSet
的人有所帮助。
答案 4 :(得分:0)
在model
中创建没有Meta
的常规序列化器:
class GeneralModelSerializer(serializers.ModelSerializer):
...
在``:
中将model
添加到序列化程序
class GenericViewSet(viewsets.ModelViewSet):
def get_serializer_class(self):
serializer_class = GeneralModelSerializer
serializer_class.Meta.model = YourModel
return serializer_class
答案 5 :(得分:0)
我的解决方案:
创建带有或不带有模型的常规序列化器,在url中发送模型名称
插件:django-geojson == 2.12.0 django:2.0.6 python:3.6.7
api.py
from djgeojson.serializers import Serializer as GeoJSONSerializer
from django.http import HttpResponse
from django.db import connection
def to_geojson(request):
model = request.GET['model']
print(model)
lista = []
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM %s" % (model))
# to dict
lista = dictfetchall(cursor)
# Serialize
geo_lista = GeoJSONSerializer().serialize(lista)
return HttpResponse(geo_lista)
def dictfetchall(cursor):
"Return all rows from a cursor as a dict"
columns = [col[0] for col in cursor.description]
return [
dict(zip(columns, row))
for row in cursor.fetchall()
]
urls.py
url(r'^api/geo/', to_geojson, name='to_geojson')
我的网址来调用API: 在models.py中使用模型
http://127.0.0.1:8000/data/api/geo/?model=data_pointcloud
models.py中没有模型
http://127.0.0.1:8000/data/api/geo/?model="schema".table_name
答案 6 :(得分:0)
对于Django 3.0 +
from yourapp import models
class GeneralViewSet(viewsets.ModelViewSet):
def get_queryset(self):
model = self.kwargs.get('model')
return getattr(models, model).objects.all()
def get_serializer_class(self):
model = self.kwargs.get('model')
GeneralSerializer.Meta.model = getattr(models, model)
return GeneralSerializer