2011-01-18 13 views
18

En Google App Engine, existe una propiedad de lista que le permite mantener una lista (matriz) de elementos. También puede especificar el tipo de elemento que se retiene, por ejemplo, cadena, entero o lo que sea.Lista de referencias en Google App Engine para Python

Google App Engine también le permite tener una propiedad ReferenceProperty. Una propiedad de referencia "contiene" una referencia a otra entidad del modelo de Google App Engine. Si accede a ReferenceProperty, recuperará automáticamente la entidad real a la que apunta la referencia. Esto es conveniente, ya que es mejor obtener la clave, y luego obtener la entidad para dicha clave.

Sin embargo, no veo nada como ListReferenceProperty (o ReferenceListProperty). Me gustaría tener una lista de referencias a otras entidades, que se resolvería automáticamente cuando intente acceder a elementos dentro de la lista. Lo más parecido que puedo conseguir es mantener una lista de objetos db.Key. Puedo usar estas claves para luego recuperar manualmente sus entidades asociadas del servidor.

¿Hay alguna buena solución para esto? Básicamente, me gustaría tener la capacidad de tener una colección de referencias (autorreferenciales) a otras entidades. Casi puedo llegar al tener una colección de claves para otras entidades, pero me gustaría que "sepa" que estos son elementos clave, y que podría desreferenciarlos como un servicio para mí.

Gracias

Respuesta

13

Paso uno:

Uso db.ListProperty (db.Key) para crear la relación. Desea que ListProp esté en la Entidad que tendrá menos referencias en la relación Muchos a Muchos. Esto también le dará una referencia posterior. Entonces:

class Spam 
    prop1 = db.String 
    eggs = db.List 

class Eggs 
    prop1 = db.string 
    @property 
    def spams(self): 
    return Spam.all().filter('eggs', self.key()) 

Esto proporciona referencias en ambos sentidos.

Paso dos:

crear un método utlility que derefrences propiedades.

def prefetch_refprops(entities, *props): 
    """Dereference Reference Properties to reduce Gets. See: 
    http://blog.notdot.net/2010/01/ReferenceProperty-prefetching-in-App-Engine 
    """ 
    fields = [(entity, prop) for entity in entities for prop in props] 
    ref_keys = [prop.get_value_for_datastore(x) for x, prop in fields] 
    ref_entities = dict((x.key(), x) for x in db.get(set(ref_keys))) 
    for (entity, prop), ref_key in zip(fields, ref_keys): 
     prop.__set__(entity, ref_entities[ref_key]) 
    return entities 

uso sería:

derefrenced_spams = prefetch_refprops(Spams, models.Spam.eggs)  
+0

Stephen ¿Usted intentó esto? Uso este método todo el tiempo y fue sugerido originalmente por las personas que comparten el IRC de Google App Engine. –

+0

Disculpas, intentaré esto apenas salga del bucle iterativo actual. Gracias por su respuesta. –

+0

Sí, es algo. Quiero decir, sería genial si fuera una propiedad real que entendiera que era una lista de referencias y todo, pero aún así. Esta es la mejor respuesta que he visto hasta ahora. –

6

Tienes razón, no hay construido en ReferenceListProperty. Sería posible escribir uno usted mismo - las subclases de propiedades personalizadas son generalmente bastante fáciles - pero hacerlo bien es más difícil de lo que pensaría, cuando se trata de hacer referencia y almacenar en caché una lista de referencias.

Sin embargo, puede usar un db.ListProperty(db.Key), que le permite almacenar una lista de claves. Luego, puede cargarlos individualmente o todos a la vez mediante una operación por lotes db.get(). Esto requiere que hagas el paso de resolución tú solo, pero también te da más control sobre cuándo desreferencia entidades.