Potrzebuję niektórych właściwości, żeby były wyjątkowe. Jak mogę to osiągnąć?Jak zdefiniować unikalną właściwość modelu w Google App Engine?
Czy jest coś takiego jak unique=True
?
Używam Google App Engine do Pythona.
Potrzebuję niektórych właściwości, żeby były wyjątkowe. Jak mogę to osiągnąć?Jak zdefiniować unikalną właściwość modelu w Google App Engine?
Czy jest coś takiego jak unique=True
?
Używam Google App Engine do Pythona.
Nie ma wbudowanego ograniczenia, aby upewnić się, że wartość jest unikalna. Można to zrobić, jednakże:
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!')
używam keys_only=True
ponieważ będzie to poprawić wydajność nieco przez nie pobierania danych dla jednostki.
Bardziej wydajną metodą byłoby użycie oddzielnego modelu bez pól, których nazwa klucza składa się z nazwy i wartości właściwości. Następnie można użyć get_by_key_name
, aby pobrać jedną lub więcej nazw tych złożonych kluczy, a jeśli otrzymasz jedną lub więcej wartości nie-None
, wiesz, że są zduplikowane wartości (i sprawdzanie, które wartości nie były None
, będziesz wiedzieć, które nie były wyjątkowy.)
Jak onebyone wspomniano w komentarzach, tych podejść – przez ich dostać pierwsze, wprowadzone później natury – uruchomić problemy współbieżności ryzyka. Teoretycznie można utworzyć encję tuż po sprawdzeniu istniejącej wartości, a następnie kod po sprawdzeniu będzie nadal wykonywany, prowadząc do powielenia wartości. Aby temu zapobiec, trzeba będzie użyć transakcji: Transactions - Google App Engine
Jeśli szukasz, aby sprawdzić wyjątkowość całej wszystkie podmioty z transakcji, trzeba by umieścić je wszystkie w tej samej grupie stosującej pierwsza metoda, która byłaby bardzo nieefektywna. W przypadku transakcji, należy użyć drugiej metody tak:
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(...)
zakłada, że każda para pojedynczy klucz/wartość musi być unikalna, aby powrócić sukces. Transakcja będzie korzystać z pojedynczej grupy jednostek dla każdego typu modelu. W ten sposób transakcja jest niezawodna dla kilku różnych pól jednocześnie (dla tylko jednego pola byłoby to znacznie prostsze). Nawet, jeśli masz pola o tej samej nazwie w jednym lub większej liczbie modeli, nie będą one w konflikcie z wzajemnie.
Możliwe jest umieszczenie ich w transakcjach, ale zostawiam to OP. – Blixt
@onebyone: Zaktualizowałem swój post z kodem, aby pokazać, co miałem na myśli w przypadku drugiej metody. Używa bardzo szerokich grup encji, ale mam nadzieję, że nie robi więcej niż pięć wstawiania "put" na sekundę na model. – Blixt
Czy dobrze rozumiem, że ten tworzy grupę encji dla każdej klasy, ograniczając prędkość wstawiania z prędkością jednej sekundy? Czy wprowadziłaby jakąkolwiek niespójność, aby sprawić, że wartość mieszająca wszystkich sprawdzanych właściwości zostanie dodana jako ciąg do "unikalnych wartości", tworząc w ten sposób wiele grup encji? – petr
Google ma funkcję pod warunkiem, aby to zrobić:
http://code.google.com/appengine/docs/python/datastore/modelclass.html#Model_get_or_insert
Model.get_or_insert(key_name, **kwds)
próbach uzyskania podmiot o rodzaju modelki o podanej nazwie klucza. Jeśli istnieje, get_or_insert() po prostu go zwraca. Jeśli nie istnieje, tworzona jest, przechowywana i zwracana nowa encja o danym rodzaju, nazwie i parametrach w kwds.
Zdobądź i kolejne (możliwe) put są zawijane w transakcji w celu zapewnienia atomowości. Oznacza to, że funkcja get_or_insert() nigdy nie nadpisze istniejącej jednostki i wstawi nową jednostkę wtedy i tylko wtedy, gdy nie istnieje żadna jednostka o podanym rodzaju i nazwie.
Innymi słowy, get_or_insert() jest równoznaczne z tym kodzie Pythona:
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)
argumentami:
KEY_NAME Nazwa klucza podmiotu ** kwds Złożone argumenty przekazać do konstruktora klasy modelu, jeśli instancja o podanej nazwie klucza nie istnieje. Argument macierzysty jest wymagany, jeśli pożądana jednostka ma element nadrzędny.
Uwaga: get_or_insert() nie przyjmuje obiektu RPC.
Metoda zwraca wystąpienie klasy modelu, która reprezentuje żądaną jednostkę, niezależnie od tego, czy istniała, czy została utworzona za pomocą metody. Podobnie jak w przypadku wszystkich operacji składowania danych, ta metoda może wywołać błąd TransactionFailedError, jeśli transakcji nie można ukończyć.
Blixt, edycja, aby tytuł twierdził, że silnik aplikacji jest dobry, ponieważ wiele pytań dotyczących mechanizmu aplikacji jest agnostycznych, ale gdzieś na to pytanie należy wspomnieć, że plakat jest zainteresowany pythonową odpowiedzą, a nie java. –
Masz rację. Zastanowiłem się też nad dodaniem go wcześniej, ale uznałem, że rozwiązanie Javy również wskaże OP w dobrym kierunku. Ale przypuszczam, że wersje GAE w języku Java i Python są na tyle różne, aby było to pytanie specyficzne dla Pythona. – Blixt