2010-09-11 8 views
0

Je souhaite implémenter une classe de modèle de base VersionedModel simple pour mon application de moteur d'application. Je cherche un motif qui n'implique pas explicitement le choix des champs à copier. J'essaie quelque chose comme ça, mais c'est pour hacky à mon goût et je n'ai pas encore testé dans l'environnement de production.Comment faire une copie superficielle d'une instance de modèle de moteur d'application pour créer une nouvelle instance?

class VersionedModel(BaseModel): 
    is_history_copy  = db.BooleanProperty(default=False) 
    version    = db.IntegerProperty() 
    created    = db.DateTimeProperty(auto_now_add=True) 
    edited    = db.DateTimeProperty() 
    user    = db.UserProperty(auto_current_user=True) 

    def put(self, **kwargs): 
     if self.is_history_copy: 
      if self.is_saved(): 
       raise Exception, "History copies of %s are not allowed to change" % type(self).__name__ 
      return super(VersionedModel, self).put(**kwargs) 
     if self.version is None: 
      self.version = 1 
     else: 
      self.version = self.version +1 
     self.edited = datetime.now() # auto_now would also affect copies making them out of sync 
     history_copy = copy.copy(self) 
     history_copy.is_history_copy = True 
     history_copy._key = None 
     history_copy._key_name = None 
     history_copy._entity = None 
     history_copy._parent = self 
     def tx(): 
      result = super(VersionedModel, self).put(**kwargs) 
      history_copy._parent_key = self.key() 
      history_copy.put() 
      return result 
     return db.run_in_transaction(tx) 

Est-ce que quelqu'un a une solution de nettoyage plus simple pour conserver l'historique des versions pour les modèles de moteurs d'applications?

EDIT: Déplacé copy sur tx. Thx @Adam Crossland pour la suggestion.

+0

Je suppose que vous créez la copie à l'intérieur d'une transaction, car il est possible que plusieurs demandes peut tenter de versionner la même entité simultanément, ce qui entraîne une condition de concurrence, oui? –

+0

Des copies sont créées pour chaque sauvegarde, même la première ... et je dois avoir une clé de modèle originale pour enregistrer une copie enfant, j'ai eu du mal à faire fonctionner ça, c'était une première qui marchait. Je suppose que cela peut être optimisé. Je n'ai pas pensé jusque-là, pour protéger les versions contre les conditions de course, dans mon cas simple je peux vivre avec quelques versions avec le même numéro. –

Répondre

2

Jetez un oeil à la méthode statique properties sur les classes Model. Avec cela, vous pouvez obtenir une liste des propriétés, et l'utiliser pour obtenir leurs valeurs, quelque chose comme ceci:

@classmethod 
    def clone(cls, other, **kwargs): 
    """Clones another entity.""" 
    klass = other.__class__ 
    properties = other.properties().items() 
    kwargs.update((k, p.__get__(other, klass)) for k, p in properties) 
    return cls(**kwargs) 
Questions connexes