Django - 使用models.py覆盖get_or_create

时间:2009-08-19 22:48:56

标签: django django-models

我有一个类要在其中覆盖get_or_create方法。基本上如果我的班级没有存储我想要的答案,那么就会做一些过程来得到答案而且没有提供。该方法实际上是get_or_retrieve方法。所以这是班级:

class P4User(models.Model):
  user      = models.CharField(max_length=100, primary_key=True)
  fullname  = models.CharField(max_length=256)
  email     = models.EmailField()
  access    = models.DateField(auto_now_add=True)
  update    = models.DateField(auto_now_add=True)

  @classmethod
  def get_or_retrieve(self, username, auto_now_add=False):
    try:
        return self.get(user=username), False
    except self.model.DoesNotExist:
        import P4
        import datetime
        from django.db import connection, transaction, IntegrityError
        p4 = P4.P4().connect()
        kwargs = p4.run(("user", "-o", username))[0]
        p4.disconnect()
        params = dict( [(k.lower(),v) for k, v in kwargs.items()])        
        obj = self.model(**params)
        sid = transaction.savepoint()
        obj.save(force_insert=True)
        transaction.savepoint_commit(sid)
        return obj, True
    except IntegrityError, e:
        transaction.savepoint_rollback(sid)
        try:
            return self.get(**kwargs), False
        except self.model.DoesNotExist:
            raise e

  def __unicode__(self):
    return str(self.user) 

现在我完全承认我已经使用db / models / query.py作为我的起点。我的问题是这一行。

obj = self.model(**params)

我能够获得参数但我还没有定义self.model。我不明白它需要什么,并且直觉上不应该明白应该是什么价值。即使回头看查询。我也无法解决这个问题。谁可以给我解释一下这个?我真的很想理解它并修复我的代码。

由于

3 个答案:

答案 0 :(得分:6)

get_or_createManager方法,您可以通过model.objects访问它 - 它是具有属性model的经理类。因此,最简单的方法是创建自定义管理器并将方法放在那里。

但是,现在修复代码很容易。 self.model只是类名 - 该行只是用给定的参数实例化类。所以你可以做到

obj = P4User(**params)

虽然如果你继承了模型,这会中断。

答案 1 :(得分:4)

丹尼尔在他的建议中正确使用了经理类。这就是我最终的目标。

# Managers

class P4Manager(models.Manager):
  def p4_run_command(self, command):
    """Runs a basic perforce command and return the values"""
    p4 = P4.P4()
    p4.connect()
    values = p4.run(command)
    p4.disconnect()
    return self.__unify_key_values__(values)

  def __unify_key_values__(self, args):
    """Unified method to clean up the lack of standard returns from p4 api"""
    final = []
    for item in args:
      params = dict( [(k.lower(),v) for k, v in item.items()])
      results = {}
      for k, v in params.items():
        if k in ['password', ]: continue
        if k in ["access", "update"]:
          v = datetime.datetime.strptime(v, "%Y/%m/%d %H:%M:%S") 
        results[k]=v
      final.append(results)
    return final

  def __get_or_retrieve_singleton__(self, **kwargs):
    """This little sucker will retrieve a key if the server doesn't have it.
       In short this will go out to a perforce server and attempt to get a
       key if it doesn't exist.    
    """
    assert len(kwargs.keys())==2, \
            'get_or_retrieve() must be passed at one keyword argument'
    callback = kwargs.pop('callback', None)
    try:      
      return self.get(**kwargs), False
    except self.model.DoesNotExist:
      params = self.p4_run_command((kwargs.keys()[0], "-o", kwargs.values()))
      if callback:
        params = callback(*params)
      obj = self.model(**params)
      sid = transaction.savepoint()
      obj.save(force_insert=True)
      transaction.savepoint_commit(sid)
      return obj, True
    except IntegrityError, e:
      transaction.savepoint_rollback(sid)
      try:
        return self.get(**kwargs), False
      except self.model.DoesNotExist:
        raise e

class P4UserManager(P4Manager):
  """
  A Generic User Manager which adds a retrieve functionality
  """
  def get_or_retrieve(self, user):
    kwargs = { 'callback' : self.__userProcess__ ,
               'user': user }
    return self.__get_or_retrieve_singleton__(**kwargs)

  def __userProcess__(self, *args):
    args = args[0]
    if not args.has_key('access'):
      raise self.model.DoesNotExist()
    return args

# Models

class P4User(models.Model):
  """This simply expands out 'p4 users' """
  user      = models.CharField(max_length=100, primary_key=True)
  fullname  = models.CharField(max_length=256)
  email     = models.EmailField()
  access    = models.DateField(auto_now_add=True)
  update    = models.DateField(auto_now_add=True)
  objects   = P4UserManager()

  def __unicode__(self):
    return str(self.user) 

我希望其他人找到这个有用的

答案 2 :(得分:0)

使用 self 代替 self.model

您要复制的代码是Queryset类的方法。在那里, self.model 是要使用其查询集的模型。你的方法是模型本身的类方法。