celery task и customize decorator

Я работаю над проектом с использованием джанго и сельдерея (django-celery). Наша команда решила обернуть весь код доступа к данным в (app-name) /manager.py (НЕ переносить в Managers, как django ), и позволить коду (app-name) ) /task.py занимается только сборкой и выполнением задач с сельдереем (так что у нас нет зависимости ORM от django на этом уровне).

В моем manager.py у меня есть что-то вроде этого:

def get_tag(tag_name):
    ctype = ContentType.objects.get_for_model(Photo)
    try:
        tag = Tag.objects.get(name=tag_name)
    except ObjectDoesNotExist:
        return Tag.objects.none()
    return tag

def get_tagged_photos(tag):
    ctype = ContentType.objects.get_for_model(Photo)
    return TaggedItem.objects.filter(content_type__pk=ctype.pk, tag__pk=tag.pk)

def get_tagged_photos_count(tag):
    return get_tagged_photos(tag).count()

В моем task.py мне нравится объединять их в задачи (затем, возможно, использовать эти задачи для выполнения более сложных задач), поэтому я пишу этот декоратор:

import manager #the module within same app containing data access functions

class mfunc_to_task(object):
    def __init__(mfunc_type='get'):
        self.mfunc_type = mfunc_type

    def __call__(self, f):
        def wrapper_f(*args, **kwargs):
            callback = kwargs.pop('callback', None)

            mfunc = getattr(manager, f.__name__)

            result = mfunc(*args, **kwargs)
            if callback:
                if self.mfunc_type == 'get':
                    subtask(callback).delay(result)
                elif self.mfunc_type == 'get_or_create':
                    subtask(callback).delay(result[0])
                else:
                    subtask(callback).delay()
            return result            

        return wrapper_f

затем (все еще в task.py ):

#@task
@mfunc_to_task()
def get_tag():
    pass

#@task
@mfunc_to_task()
def get_tagged_photos():
    pass

#@task
@mfunc_to_task()
def get_tagged_photos_count():
    pass

Все нормально работает без @task . Но после применения декоратора @task (вверху, как указано в документации по сельдерею), все просто начинает разваливаться. Очевидно, каждый раз, когда вызывается mfunc_to_task .__ call __ , та же функция task.get_tag передается как f . Так что я каждый раз получал один и тот же wrapper_f , и теперь единственное, что я делаю, это получаю единственный тег.

Я новичок в декораторах. Кто-нибудь может помочь мне понять, что здесь пошло не так, или указать другие способы решения задачи? Мне очень не нравится писать один и тот же код переноса задач для всех моих функций доступа к данным.

15
задан warvariuc 30 October 2015 в 13:48
поделиться