J'ai besoin de propriétés uniques. Comment puis-je atteindre cet objectif?
Y a-t-il quelque chose comme unique=True
?
J'utilise Google App Engine pour Python.
J'ai besoin de propriétés uniques. Comment puis-je atteindre cet objectif?
Y a-t-il quelque chose comme unique=True
?
J'utilise Google App Engine pour Python.
Google a fourni une fonction pour faire ça:
http://code.google.com/appengine/docs/python/datastore/modelclass.html#Model_get_or_insert
Model.get_or_insert(key_name, **kwds)
Des tentatives pour obtenir l'entité du modèle du genre avec le nom de la clé. Si elle existe, get_or_insert() renvoie simplement il. S'il n'existe pas, une nouvelle entité, selon le type, le nom et les paramètres dans kwds est créée, stockée, et s'en retourna.
Le get et suivantes (possible) de mettre sont enveloppés dans une transaction pour garantir l'atomicité. Sat signifie que get_or_insert() ne sera jamais remplacer une entité existante, et insérez-en une nouvelle entité si et seulement si aucune entité avec le type et le nom existe.
En d'autres termes, get_or_insert() est équivalent à ce code 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)
Arguments:
key_name Le nom de la clé de l'entité **kwds Mot-clé arguments à passer au modèle du constructeur de la classe si une instance avec le nom de la clé n'existe pas. L'argument parent est nécessaire si l'entité dispose d'un parent.
Remarque: get_or_insert() n'accepte pas un objet RPC.
La méthode retourne une instance de la classe du modèle que représente l'entité demandée, si elle a existé ou a été créé par la méthode. Comme avec tous les magasin de données, cette méthode peut lever une TransactionFailedError si la transaction n'a pas pu être terminée.
Il n'y a pas de contrainte pour s'assurer de la valeur est unique. Vous pouvez faire cela, cependant:
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!')
J'utilise keys_only=True
parce que ça va améliorer les performances légèrement de ne pas récupérer les données de l'entité.
La méthode la plus efficace serait d'utiliser un modèle distinct avec pas de champs dont le nom est composé du nom de la propriété de + de valeur. Ensuite, vous pouvez utiliser get_by_key_name
pour aller chercher un ou plusieurs de ces composites noms de clé et si vous obtenez un ou plusieurs non-None
valeurs, vous savez il y a des valeurs en double (et vérification des valeurs qui n'ont pas été None
, vous savez ceux qui n'étaient pas uniques.)
Comme onebyone mentionné dans les commentaires, ces approches par la première, mettre plus tard la nature de courir le risque des problèmes de concurrence. Théoriquement, une entité pourrait être créée juste après la vérification d'une valeur existante, puis le code après le check exécute tout de même, conduisant à des valeurs en double. Pour éviter cela, vous devrez utiliser des transactions: les Transactions - Google App Engine
Si vous êtes à la recherche pour vérifier l'unicité à travers toutes les entités avec les transactions, vous devez mettre tous dans le même groupe à l'aide de la première méthode, qui serait très inefficace. Pour les transactions, utilisez la seconde méthode comme ceci:
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(...)
supposerons que chaque paire clé/valeur doit être unique pour retourner succès. La transaction permettra d'utiliser un seul groupe d'entités pour chaque modèle du genre. De cette manière, la transaction est fiable pour plusieurs domaines à la fois (pour un seul domaine, ce serait beaucoup plus simple.) Aussi, même si vous avez les champs portant le même nom dans un ou plusieurs modèles, ils ne seront pas en conflit les uns avec les autres.
Pour tester cela, accédez à l'URL suivante (ignorer le nom de l'application, j'ai juste utilisé un de rechange =):
Notez que si vous allez sur une actualisation de la frénésie, vous pourriez être en mesure d'obtenir des non-valeurs uniques dans les "Données dans la banque de données" à la liste. Cela est dû à la façon dont la banque de données est vidé en haut du script ( UniqueConstraint
modèles sont supprimés dans un thread, tandis qu'un autre thread est en train d'essayer d'insérer plus de MyModel
modèles.) Le test est juste pour montrer comment cela fonctionne. N'hésitez pas à écrire un bon scénario de test, cependant.
Pour voir la source de l'application de test, rendez-vous ici:
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.