2011-09-27 15 views
6

En Appengine, intento que el valor de una propiedad se calcule automáticamente y se almacene con el objeto.¿Cómo sobrescribir el método put() en un modelo de motor de aplicación python?

Tengo una clase, Rectángulo, y tiene un ancho, alto y área. Obviamente, el área es una función de ancho y alto, pero quiero que sea una propiedad porque quiero usarlo para clasificar. Así que trato de modificar la función put() para colarse al área en el almacenamiento del rectángulo de este modo:

class Rectangle(db.Model): 
    width = db.IntegerProperty() 
    height = db.IntegerProperty() 
    area = db.IntegerProperty() 

    def put(self, **kwargs): 
     self.area = self.width * self.height 
     super(Rectangle, self).put(**kwargs) 

Esto funciona cuando invoco put() en el objeto Área directa:

re1 = Rectangle(width=10, height=10) 
re1.put() 
print re1.area  # >> 10 

Pero cuando Yo uso db.put() (por ejemplo, para guardar muchos de ellos a la vez), esto se rompe.

re2 = Rectangle(width=5, height=5) 
db.put(re2) 
print re2.area  # >> None 

¿Cuál es la forma correcta de 'escabullirse' en el valor calculado?

+0

¿Qué obtienes si recoges el artículo de la base de datos? es el area calculada? – rocksportrocker

+0

Revisé el almacén de datos y dice lo mismo; '10' para el primer rectángulo y' None' para el segundo. – Paul

+1

Sospecho que 'db.put()' nunca llama al método individual 'put()' en los objetos, probablemente los inspecciona en busca de propiedades de base de datos y crea instrucciones de inserción masiva. Si configura el área en '__init__' en lugar de' put', ¿qué ocurre? – larsks

Respuesta

7

No anule la puesta: como observa, es frágil y no se invoca si llama al db.put en lugar de la función de poner del modelo.

Afortunadamente, App Engine proporciona una ComputedProperty que hace que su caso de uso muy fácil:

class Rectangle(db.Model): 
    width = db.IntegerProperty() 
    height = db.IntegerProperty() 

    @db.ComputedProperty 
    def area(self): 
     return self.width * self.height 
+0

¡Gracias, eso funciona como un encanto! – Paul

1

Estoy de acuerdo que ComputedProperty es el camino a seguir para el escenario específico descrito. Sin embargo, aún podría ser útil sobrecargar la función put. Por ejemplo, empleamos el siguiente código para realizar un seguimiento de todas las personas que llaman que están emitiendo escrituras en el almacén de datos para que podamos depurar fácilmente los picos en las escrituras.

from google.appengine.ext import db 

_orig_db_put_async = db.put_async 
_orig_db_model_put = db.Model.put 

def _new_db_put_async(models, *args, **kwargs): 
    """Instrumented version of db.put_async (which db.put also calls).""" 
    retval = _orig_db_put_async(models, *args, **kwargs) 
    msg = ['query: %s' % _get_caller()] 
    # 'models' can be either a single model instance, or a list of them. 
    try: 
     for model in models: 
      msg.append(model.__class__.__name__ + '.<db.put>') 
    except TypeError: 
     msg.append(models.__class__.__name__ + '.<db.put>') 
    instance_cache.increment(' -- '.join(msg)) 
    return retval 


def _new_db_model_put(self, *args, **kwargs): 
    """Like entity.put() but stores put-stats in the instance cache.""" 
    retval = _orig_db_model_put(self, *args, **kwargs) 
    msg = ['query: %s' % _get_caller()] 
    msg.append(self.__class__.__name__ + '.<put>') 
    instance_cache.increment(' -- '.join(msg)) 
    return retval 

Este código mantiene un recuento de los cuales están emitiendo codepaths escribe en Memcache y luego de vez en cuando vuelca a los registros. Las líneas de registro tienen el siguiente aspecto:

3041: activity_summary.py:312 -- UserData.<put>

Dónde 3041 es el número de veces que se alinean 312 de activity_summary.py emitió un UserData.put().

Cuestiones relacionadas