Pregunta ¿Cómo puedo definir una propiedad única para un modelo en Google App Engine?


Necesito algunas propiedades para ser único. ¿Cómo puedo conseguir esto?

¿Hay algo como unique=True?

Estoy usando Google App Engine para Python.


32
2017-07-26 21:41


origen


Respuestas:


No hay una restricción incorporada para garantizar que un valor sea único. Puedes hacer esto sin embargo:

query = MyModel.all(keys_only=True).filter('unique_property', value_to_be_used)
entity = query.get()
if entity:
    raise Exception('unique_property must have a unique value!')

yo suelo keys_only=True porque mejorará ligeramente el rendimiento al no obtener los datos de la entidad.

Un método más eficiente sería usar un modelo separado sin campos cuyo nombre de clave se compone de nombre de propiedad + valor. Entonces podrías usar get_by_key_name para buscar uno o más de estos nombres de clave compuestos y si obtiene uno o más not-None valores, usted sabe que hay valores duplicados (y verificar qué valores no eran None, sabrá cuáles no fueron únicos.)


Como uno a uno mencionado en los comentarios, estos enfoques - por su primer aspecto, poner naturaleza posterior - corren el riesgo de problemas de concurrencia. Teóricamente, una entidad podría crearse justo después de la verificación de un valor existente, y luego el código después de la verificación se ejecutará, lo que generará valores duplicados. Para evitar esto, tendrá que usar transacciones: Transacciones: Google App Engine


Si está buscando verificar la singularidad en todas entidades con transacciones, tendrías que ponerlas todas en el mismo grupo usando el primer método, que sería muy ineficiente. Para transacciones, use el segundo método de esta manera:

class UniqueConstraint(db.Model):
    @classmethod
    def check(cls, model, **values):
        # Create a pseudo-key for use as an entity group.
        parent = db.Key.from_path(model.kind(), 'unique-values')

        # Build a list of key names to test.
        key_names = []
        for key in values:
            key_names.append('%s:%s' % (key, values[key]))

        def txn():
            result = cls.get_by_key_name(key_names, parent)
            for test in result:
                if test: return False
            for key_name in key_names:
                uc = cls(key_name=key_name, parent=parent)
                uc.put()
            return True

        return db.run_in_transaction(txn)

UniqueConstraint.check(...) asumirá que cada pareja clave / valor debe ser única para devolver el éxito. La transacción usará un solo grupo de entidades para cada tipo de modelo. De esta forma, la transacción es confiable para varios campos diferentes a la vez (para un solo campo, esto sería mucho más simple). Además, incluso si tiene campos con el mismo nombre en uno o más modelos, no entrarán en conflicto con El uno al otro.


21
2017-07-26 22:13



Google ha proporcionado una función para hacer eso:

http://code.google.com/appengine/docs/python/datastore/modelclass.html#Model_get_or_insert

Model.get_or_insert(key_name, **kwds)

Intenta obtener la entidad del tipo de modelo con el nombre de clave proporcionado. Si existe, get_or_insert () simplemente lo devuelve. Si no existe, se crea, almacena y devuelve una nueva entidad con el tipo, nombre y parámetros dados en kwds.

El get y el posterior (posible) put están envueltos en una transacción para asegurar la atomicidad. Esto significa que get_or_insert () nunca sobrescribirá una entidad existente e insertará una nueva entidad si y solo si no existe ninguna entidad con el tipo y nombre dados.

En otras palabras, get_or_insert () es equivalente a este código de Python:

def txn():
  entity = MyModel.get_by_key_name(key_name, parent=kwds.get('parent'))
  if entity is None:
    entity = MyModel(key_name=key_name, **kwds)
    entity.put()
  return entity
return db.run_in_transaction(txn)

Argumentos:

Nombre clave   El nombre para la clave de la entidad ** kwds   Argumentos de palabras clave para pasar al constructor de la clase de modelo si no existe una instancia con el nombre de clave especificado. El argumento principal es obligatorio si la entidad deseada tiene un padre.

Nota: get_or_insert () no acepta un objeto RPC.

El método devuelve una instancia de la clase de modelo que representa la entidad solicitada, si existió o si fue creado por el método. Al igual que con todas las operaciones del almacén de datos, este método puede generar un TransactionFailedError si la transacción no pudo completarse.


24
2018-04-29 08:44