title: celery task and customize decorator
body: <p>I'm working on a project using django and celery(django-celery). Our team decided to wrap all data access code within <code>(app-name)/manager.py</code>(NOT wrap into Managers like the <code>django</code> way), and let code in (app-name)/task.py only dealing with assemble and perform tasks with celery(so we don't have django ORM dependency in this layer).</p>
  
  <p>In my <code>manager.py</code>, I have something like this:</p>
  
  <pre><code>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()
  </code></pre>
  
  <p>In my task.py, I like to wrap them into tasks (then maybe use these tasks to do more complicated tasks), so I write this decorator:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>then (still in <code>task.py</code>):</p>
  
  <pre><code>#@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
  </code></pre>
  
  <p>Things work fine without <code>@task</code>.
  But, after applying that <code>@task</code> decorator(to the top as celery documentation instructed), things just start to fall apart. Apparently, every time the <code>mfunc_to_task.__call__</code> gets called, the same <code>task.get_tag</code> function gets passed as <code>f</code>. So I ended up with the same <code>wrapper_f</code> every time, and now the only thing I cat do is to get a single tag.</p>
  
  <p>I'm new to decorators. Any one can help me understand what went wrong here, or point out other ways to achieve the task? I really hate to write the same task wrap code for every of my data access functions.</p>