1

我需要将多个现有的 django 模型暴露给tastepie。我掌握了创建 af ModelResource 并将其注册到 urls.py 的基础知识。但是,我想避免为每个 django 模型编写资源类,并且由于它们都需要以相同的方式工作,我希望以某种方式对其进行概括。

所以基本上我希望归档的是一组常规的 django 模型:

class ModelA:
  field1 = ...
  field2 = ...

class ModelB:
  field3 = ...
  field4 = ...

class ModelC:
  field8 = ...
  field9 = ...

然后自动让它们以 '/api/v1/modela/'、'/api/v1/modelb/' 和 '/api/v1/modelc/ 等形式暴露给美味派 API。

不是在寻找一个完整的解决方案,只是对一个好的方法的建议。

4

2 回答 2

1

AResource只是一个 python 类,所以你可以简单地创建一个基础资源并继承它,只定义了querysetresource_nameMeta 属性。

您可能也可以通过摆弄Resource类的__new__方法或创建自定义来自动命名classmethod,但我不确定这些努力是否会给您带来很多好处。

将类注册到 api 可以通过多种方式自动化,其中一种可能是:

for name, obj in inspect.getmembers(sys.modules['resources']):
    if inspect.isclass(obj):  # might want to add a few exclusions
        v1_api.register(obj())

其中'resources'是包含资源的模块的名称,但这是一种隐含的..

于 2013-05-02T09:59:16.150 回答
1

创建从models.Model派生的自定义基础模型。在该模型中添加一个没有对象的空 Resource 类并按照 Tastypie 手册中的说明进行操作:

https://django-tastypie.readthedocs.io/en/latest/non_orm_data_sources.html

从新创建的自定义模型中派生应用程序中的所有模型,您就拥有了。

为了让它工作,你需要一些魔法。我正在使用一个单独的类作为 ORM 和业务层(模型适配器)之间的中间件,但我会说应该可以不用它。

让我苦苦挣扎的是在apiResource的init中传递正确类的方法。

我结束了覆盖init并像这样注册资源:

v1_api.register(BusinessClientContact.apiResource(BusinessClientContact))

不幸的是,没有办法将内容注入到资源的元类中。你可以让它工作,但是当你开始添加资源时,你会发现解释器不会创建.Meta 和 self._meta 的单独实例,除非你没有对代码进行显式更改。后者使所有修改 _meta 结构的尝试都被动态破坏,因为您在同一个 _meta 实例上工作,而不管您的每个资源都是不同的实例。我使用的解决方法是在我想通过 api 公开的每个模型类中继承 apiResourceBase 类并手动配置 Meta 类。模型类中的代码如下所示:

class apiResource(SystemModelBase.apiResourceBase):
    class Meta:
        resource_name = 'client_contacts'
        #more stuff here

根据您的设计,您可以扩展本地化的 apiResource 以启用自定义视图和过滤器。

资源类本身的示例实现如下所示:

class apiResourceBase(Resource):        
    def __init__(self,f_modelClass):
        self.m_objMetaModel = f_modelClass.create_model_adapter()
        super(SystemModelBase.apiResource,self).__init__()

        #obj_create
        #obj_update
        #obj_delete_list
        #obj_delete
        #rollback

    def detail_uri_kwargs(self, bundle_or_obj):
        kwargs = {}
        if isinstance(bundle_or_obj, Bundle):
            kwargs['pk'] = bundle_or_obj.obj.id
        else:
            kwargs['pk'] = bundle_or_obj.id
        return kwargs
    def obj_get_list(self, bundle, **kwargs): 
        return self.get_object_list(bundle.request) 
    def get_object_list(self,request): 
        return self.m_objMetaModel.REST_IMPL.get_object_list(request)   
    def obj_get(self, bundle, **kwargs): 
        self.m_objMetaModel.load(kwargs['pk'],True)
        return self.m_objMetaModel.instance
    def dehydrate(self, bundle):
        return self.m_objMetaModel.REST_IMPL.dehydrate(bundle)

这里的实际实现(get_object_list 和 dehydrate)超出了范围,但它可能对某人有所帮助,所以我将添加它:

    def get_object_list(self,request):
        l_clientID =  request.GET['client']
        l_filterDict = {}
        l_filterDict['client_account__id']=l_clientID
        return self.query_filter(l_filterDict)
    def dehydrate(self,bundle):
        l_objInstance = bundle.obj
        l_apiDict = {}
        l_apiDict['resource_uri'] = bundle.data['resource_uri']
        l_apiDict['id']           = l_objInstance.id
        l_apiDict['name']         = l_objInstance.user_account.name
        l_apiDict['email']        = l_objInstance.user_account.email
        l_apiDict['phone']        = l_objInstance.user_account.phone
        l_apiDict['additional_contacts'] = l_objInstance.user_account.additional_contacts
        l_apiDict['is_active']           = l_objInstance.user_account.user.is_active
        bundle.data = l_apiDict
        return bundl

这是一个概念验证代码,在生产中,您几乎可以复制 Tastypie 用于加载模型并公开它们的逻辑。

于 2019-05-02T18:04:32.637 回答