【问题标题】:Dynamically create Resources for multiple django models in tastypie在美味派中为多个 django 模型动态创建资源
【发布时间】:2013-04-26 09:43:34
【问题描述】:

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

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

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

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

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

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

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

【问题讨论】:

    标签: python django tastypie


    【解决方案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))
    

    不幸的是,没有办法将内容注入资源的元类。你可以让它工作,但是当你开始添加资源时,你会发现解释器不会创建 class.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 用于加载模型和公开模型的逻辑。

    【讨论】:

      【解决方案2】:

      Resource“只是”一个 python 类,因此您可以简单地创建一个基础资源并在仅定义 querysetresource_name 元属性的情况下继承它。

      您也可以通过摆弄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' 是包含资源的模块的名称,但这是一种隐含的..

      【讨论】:

      • 谢谢,有道理。如果我想生成资源类以及它们的自定义查询集和名称,我正在考虑使用类似的东西: rclass= type(cls.__name__+'Resource', (ModelResource,), {'Meta': type('Meta ', (object,), {'queryset': cls.objects.all(), 'resource_name' : cls.__name__})})
      猜你喜欢
      • 2012-09-25
      • 1970-01-01
      • 1970-01-01
      • 2012-04-03
      • 2012-08-09
      • 1970-01-01
      • 2012-09-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多