问题描述
我正在尝试创建一个没有预定义模型的REST-ModelViewSet,但在注册路由器时需要一个模型。我需要这样才能动态地将模型添加到我的REST-API中,而无需配置任何新的视图集或序列化程序。
I'm trying to create a REST-ModelViewSet that has no model predefined, but takes a model when registered with the router. I need this to dynamically add models to my REST-API, without configuring any new viewsets or serializers.
我的想法是将 kwargs
中的模型传递到 __ init __
,但我不知道如何正确地做到这一点。这是我试过的:
My idea was to pass the model in the kwargs
of __init__
, but I can't figure out how to correctly do this. Here is what I tried:
//Viewset
class ThemeViewSet(viewsets.ModelViewSet):
def __init__(self, **kwargs):
self.model = kwargs['model']
self.serializer_class = None
super(ThemeViewSet, self).__init__(**kwargs)
def get_serializer_class(self):
if self.serializer_class is not None:
return self.serializer_class
class ThemeSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = self.model
self.serializer_class = ThemeSerializer
return self.serializer_class
//Router:
router = routers.DefaultRouter()
router.register(r'mytheme', ThemeViewSet(model=mytheme), base_name='mytheme')
现在,如果我尝试打印self.model
在 __ init __
,它正确显示< class'myapp.models.myth eme'>
,但Django仍然返回错误:
Now, if I try to print self.model
in __init__
, it correctly shows <class 'myapp.models.mytheme'>
in the console, but Django still returns an error:
AttributeError at /api/mytheme/
This method is available only on the view class.
此错误由 classonlymethod
引发 - 装饰。我真的不知道该做什么,有没有办法将模型传递给 __ init __
,还是有不同的方法可以尝试?
This error is raised by the classonlymethod
-decorator. I don't really know what to make of this, is there any way to pass the model to __init__
, or is there a different approach that I can try?
(我知道wq.db.rest有一个我想要的路由器,但是我不想使用wq,我没有尝试过tastypie,这样做会更容易/可能吗?)
(I know that wq.db.rest has a router that does what I want, but I don't want to use wq. I haven't tried tastypie, would that make it easier/possible?)
提前感谢
推荐答案
Django REST框架希望被传递到路由器,而不是视图实例。这是因为必须为每个请求创建实例,这样可以防止共享状态出现许多丑陋的问题,并且还遵循基于标准Django类的视图。
Django REST Framework expects that a ViewSet
class is passed into the router, not a view instance. This is because the instance has to be created for each request, which prevents a lot of ugly issues with shared state and also follows the standard Django class-based views.
您可以通过使用根据传入其中的模型创建自定义 ViewSet
类的方法来获得更好的运气:
You may have better luck with having a method that creates a customized ViewSet
class based on the model that is passed into it:
class ThemeViewSet(viewsets.ModelViewSet):
@classmethod
def create_custom(cls, **kwargs):
class CustomViewSet(cls):
model = kwargs["model"]
queryset = kwargs["model"].objects.all()
return CustomViewSet
请注意,我还为视图设置了 queryset
,而DRF自2.4发布以来,不再接受一个模型
。
Note that I'm also setting the queryset
for the view, and DRF no longer accepts just a model
since 2.4 was released.
每次调用新的类时,都会创建一个新类,并且模型将自动设置为传递给它的模型。在路由器注册时,您可以执行以下操作:
This will create a new class each time it is called, and the model will automatically be set to the model that is passed into it. When registering it with the router, you would do something like:
router.register(r'mytheme', ThemeViewSet.create_custom(model=mytheme), base_name='mytheme')
这样你仍然会传递一个 ViewSet
类到路由器,但它将为传入的模型进行自定义。您必须确保设置 base_name
,或者路由器将无法生成视图名称,最终会遇到错误。
This way you will still be passing a ViewSet
class to the router, but it will be customized for the model that is passed in. You must make sure to set the base_name
, or the router won't be able to generate the view names and you will eventually run into errors.
这篇关于Django REST框架 - 通过路由器将模型传递给ViewSet的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!