2013-07-17 3 views
2

Я пытаюсь имитировать unique_together функции Джанго, но я не могу показаться, чтобы получить его прямомодели NDB: гарантировать уникальность в хранилище данных с помощью пользовательского KEY_NAME

class MyClass(ndb.Model): 
    name = 'name' 
    surname = 'surname' 
    phone = 'phone' 

    def get_unique_key(self): 
     return self.name + "|" + self.surname + "|" + self.phone 

«Да, довольно легко» НЕ

В соответствии с принятым ответом в this post просто присвоение параметра id в конструкторе obj было достаточно. Но я не хочу с этим справляться. В идеале я хотел бы сделать это:

object = MyClass() 
object = object.custom_populating_method(form.cleaned_data) 
object.id = object.get_unique_key() 
object.put() 

или даже лучше, место, что в _pre_put_hook, так что id будет установлен как последнее, что перед сохранением (и, возможно, сделать некоторые проверки, принуждая уникальность данных по хранилище данных).

Видимо, я был неправ. Единственный способ добиться этого путем взлома вида:

unique_id = "|" + form.cleaned_data['bla'] + "|" + form.cleaned_data ... 
object = MyClass(id=unique_id) 

который ужасно и совершенно неправильно (так как каждое изменение требований модели должно быть проверено также в представлениях). Кроме того, я бы сделал несколько уродливых звонков, чтобы получить некоторые связанные данные. Я потратил слишком много времени, возможно, на эту проблему, чтобы увидеть выход, и я действительно надеюсь, что у меня здесь что-то неясно, но я не могу найти хороший пример и правильную документацию по этому вопросу. Есть ли какие-либо намеки или опыт с чем-то похожим?

tl; dr: есть ли хороший способ достичь этого, не добавляя ненужный код в мои представления?

(Я «с помощью» Джанго и NDB игровой Модели на Datastore)

Благодаря

+0

Вы пытались реализовать свой собственный конструктор? – dragonx

+0

Я попытался реализовать свой собственный метод __init__ (без вызова супер конструктора) без успеха –

+0

Вы не хотите переопределять init, если вы действительно не знаете, что делаете. Используйте фабрику (метод класса) для создания объекта, создающего ключ, до создания объекта. См. Удар для примера –

ответ

2

Используйте конструктор или метод класса для создания экземпляра.

class MyClass(ndb.Model): 
    name = ndb.StringProperty() 
    surname = ndb.StringProperty() 
    phone = ndb.StringProperty() 

    @staticmethod 
    def get_unique_key(name,surname,phone): 
     return '|'.join((name,surname,phone)) 

    @classmethod 
    @transactional 
    def create_entity(cls,keyname,name,surname,phone): 
     key = ndb.Key(cls, cls.get_uniquekey()) 
     ent = key.get() 
     if ent: 
      raise SomeDuplicateError() 
     else: 
      ent = cls(key=key, name=name,surname=surname,phone=phone) 
      ent.put() 

newobj = MyClass.create_entity (SomeName, somesurname, somephone)

Делая это таким образом позволяет также обеспечить ключ уникален креатинфосфата ключ и Тринг, чтобы принести его первым.

+0

Это сделало это, спасибо! –

+0

Предположим, что позже пользовательские изменения телефона (просто для повторного использования примера, мой вариант использования немного отличается). Мы поместили() новый номер телефона. Но теперь ключ не отражает данные, хранящиеся на ndb. Кто-то пытается снова добавить те же самые значения с первого раза: (имя, фамилия, телефон).Он терпит неудачу, потому что эта комбинация использовалась раньше, но если вы ищете первый номер телефона, ничего не найдено. Чтобы обойти это, я подумал об удалении ключа и создании нового объекта obj, но я бы потерял ссылку, которую могут использовать другие модели. Любые идеи о том, как это сделать, все еще используют ключ для уникальности? – alfetopito

0

Я думаю, что вы можете это сделать, если вы назначаете всю key, а не только id:

object = MyClass() 
object = object.custom_populating_method(form.cleaned_data) 
object.key = ndb.Key(MyClass, object.get_unique_key()) 
object.put() 
Смежные вопросы