【问题标题】:Django Tastypie : How to initiate a variable every time an api call is made?Django Tastypie:每次调用 api 时如何启动一个变量?
【发布时间】:2012-11-07 07:39:58
【问题描述】:

我有两个模型:

class Category(models.Model):
    name = models.CharField(max_length=50)

class SubCategory(models.Model):
    sex =  models.CharField(choices=SEX, blank=True, max_length=5) 
    name = models.TextField(blank=True) 
    category = models.ForeignKey(Category) 
    def __unicode__(self):
        return u'%s' % (self.name)

我正在使用tastepie 创建一个api,它以JSON 格式返回“SubCategory”对象。我想在每个结果集中添加一个自定义字段“start_counter_of_category”,其中包含类别 ID 更改的子类别的计数器(在“category_id”字段上排序时)

算法相当简单,在“脱水”函数中是这样的:

API_SKU_VARS = {
    'COUNTER'       : 1,
    'FIRST_ELEMENT' : 1,
    'PREV_CATEGORY' : 1
}


class SubCategoryResource(ModelResource):
    start_counter_of_category = fields.IntegerField(readonly=True)
    category = fields.ForeignKey(CategoryResource,'category')
    class Meta:
        queryset = SubCategory.objects.all()
        resource_name = 'subcategory'
        filtering = {
            'id' : ALL,
            'name' : ALL,
            'category': ALL_WITH_RELATIONS,
        }
        ordering = ['id','name','category']
        serializer = Serializer(formats=['json'])
    def dehydrate(self, bundle):
        if API_SKU_VARS['PREV_CATEGORY']  != bundle.data['category']: #if the category of the current bundle is not equal to the category of the previous bundle, we update the ['PREV_CATEGORY'] 
            API_SKU_VARS['FIRST_ELEMENT']=API_SKU_VARS['COUNTER'] #update the ['FIRST_ELEMENT'] with the counter of the current bundle
            API_SKU_VARS['PREV_CATEGORY'] = bundle.data['category']
        API_SKU_VARS['COUNTER'] = API_SKU_VARS['COUNTER']+1 #for every bundle passed, we update the counter
        bundle.data['start_counter_of_category']=API_SKU_VARS['FIRST_ELEMENT']
        return bundle.data
    serializer = Serializer(formats=['json'])

它在我启动服务器后的第一次运行时完美运行。可以预见的问题当然是我第二次调用 api 时,变量保留了它们在上次运行中的值。

任何想法如何在每次调用 api 时重新启动变量?

解决方案:

重新初始化变量

  • build_filters 如果调用的 api 是过滤 API
  • get_detail 如果调用的 api 是详细信息 API

示例(以我为例):

def build_filters(self, filters=None):
        if filters is None:
            filters = {}
        orm_filters = super(SubCategoryResource, self).build_filters(filters) #get the required response using the function's behavior from the super class
        self.API_SKU_VARS = {
            'PREV_CATEGORY':1,
            'COUNTER':1,
            'FIRST_ELEMENT':1,
        }
        return orm_filters

(如果您想将任何自定义逻辑应用到 API 响应中,这些函数将被覆盖)

更好、最明显的解决方案

重新实例化 init 函数中的变量,如下所示:

def __init__(self,api_name=None):
    self.API_SKU_VARS = {.....}
    super(SKUResource,self).__init__(api_name)

【问题讨论】:

  • 全局变量是糟糕的设计,特别是对于像 Python 这样具有良好命名空间的语言。
  • @PauloScardine 可能我的问题有点不对,我不希望变量是全局的。每次调用 API 时,我都需要重新初始化变量的值。
  • 如果您不希望变量是全局的,请不要在全局范围内定义它。找出代表正确事物并具有正确生命周期的对象(它可能是 SubCategoryResource 实例),并创建 API_SKU_VARS 作为该对象的成员(例如,通过在 __init__ 方法中设置 self.API_SKU_VARS)。跨度>

标签: python django api rest tastypie


【解决方案1】:

是的,您可以通过在每次调用开始时运行此代码来重新初始化(而不是“重新初始化”)变量:

API_SKU_VARS['COUNTER'] = 1
API_SKU_VARS['PREV_CATEGORY'] = 1
API_SKU_VARS['FIRST_ELEMENT'] = 1

但这是个坏主意。为什么这个变量首先是全局的?全局变量的全部意义在于它由模块中的所有对象共享,并且在模块的生命周期中存在。如果您想要单个 API 调用本地的东西并且在该调用的整个生命周期内都存在,那么让它成为具有这些特征的东西的成员。初始化成员作为初始化适当对象的一部分。那么就不需要重新初始化了。

看看为什么这是一个坏主意:如果两个客户端同时连接并且都进行相同的 API 调用会发生什么?

【讨论】:

  • 感谢您的回答。最后提出了非常有效的怀疑。是的,这是一个大问题。但是,我目前的情况不需要并发。在并发用户的情况下,知道如何有效地做到这一点仍然会很棒。谈到变量的重新初始化,这是我无法在tastepie模块中明确指出的重新初始化的位置。尝试在 resources.py 文件中执行此操作,但不起作用。
  • 如果你不想要并发,那你为什么要写一个 Web 服务呢?为什么不直接编写一个在本地运行的脚本,抛开所有不必要的复杂性呢?几乎可以肯定的是,任何必须上网的东西都必须处理并发。无论如何,有效处理成员变量的方法是使它们成为成员变量,而不是试图用全局变量来伪造它们。但是效率在这里只是一个副作用;以正确方式执行此操作的原因不是它快一点,而是它确实有效。
猜你喜欢
  • 1970-01-01
  • 2013-01-09
  • 2019-03-09
  • 1970-01-01
  • 1970-01-01
  • 2013-03-09
  • 2021-01-03
  • 2023-02-17
  • 1970-01-01
相关资源
最近更新 更多