2013-08-19 35 views
11

NDB模型包含兩個屬性:emailpassword。如何避免向數據庫中添加兩條具有相同記錄的記錄email?與關係數據庫一樣,NDB沒有屬性的UNIQUE選項。維護NDB數據庫中的特性的唯一性

檢查新email是不是在數據庫中添加—不會滿足我面前,因爲有兩個平行的過程既可以同時做檢查和每添加相同email

我不確定交易是否可以在這裏幫助,在閱讀了一些手冊之後,我在這個印象之下。也許同步交易?這是否意味着一次一個?

回答

6

通過電子郵件創建實體的密鑰,然後使用get_or_insert來檢查是否存在。

Also read about keys , entities.models

#ADD 
key_a = ndb.Key(Person, email); 
person = Person(key=key_a) 
person.put() 

#Insert unique  
a = Person.get_or_insert(email) 

,或者如果你想只檢查

#ADD 
key_a = ndb.Key(Person, email); 
person = Person(key=key_a) 
person.put() 

#Check if it's added 
new_key_a =ndb.Key(Person, email); 
a = new_key_a.get() 
if a is not None: 
    return 

小心。更改電子郵件將非常困難(需要創建新條目並將所有條目複製到新父代)。

因此,您可能需要將電子郵件存儲在另一個實體中,並讓該用戶成爲其父項。

另一種方法是使用事務並檢查電子郵件屬性。交易的工作方式:首先,提交是第一個獲勝。一個概念,這意味着如果2個用戶檢查電子郵件只有第一個(幸運)將成功,因此您的數據將是一致的。

+0

使用get_or_insert()我不會肯定的:無論是我添加一個新的記錄或我已經得到了現有的。 – Graduate

+1

改變電子郵件將是痛苦的** ...或更好..不可能:)所以對於電子郵件它不是一個好的解決方案。 – Lipis

+0

@研究生是應該''key_a'固定的。 –

4

也許你正在尋找webapp2-authentication模塊,它可以爲你處理。它可以像這樣導入import webapp2_extras.appengine.auth.models。查看here的完整示例。

2

我也遇到了這個問題,上述解決方案並沒有解決我的問題:

  • 使其成爲一個關鍵是在我的情況不能接受(我需要的特性,在未來多變)
  • 在電子郵件屬性上使用交易不起作用AFAIK(您無法對交易中的非密鑰名稱進行查詢,因此您無法檢查電子郵件是否已存在)。

我最終創建了一個不帶屬性的單獨模型,並將唯一屬性(電子郵件地址)作爲鍵名稱。在主模型中,我存儲對電子郵件模型的引用(而不是將電子郵件存儲爲字符串)。然後,我可以通過按鍵查找電子郵件來查看「change_email」事務,以檢查唯一性。

0

這是我遇到的情況,我決定使用@ Remko的解決方案。使用給定的電子郵件檢查現有實體的主要問題是潛在的競爭條件,如op所述。我添加了一個單獨的模型,它使用電子郵件地址作爲密鑰並具有一個包含令牌的屬性。通過使用get_or_insert,可以根據傳入的令牌檢查返回的實體令牌,如果匹配,則插入該模型。

import os 
from google.appengine.ext import ndb 

class UniqueEmail(ndb.Model): 
    token = ndb.StringProperty() 

class User(ndb.Model): 
    email = ndb.KeyProperty(kind=UniqueEmail, required=True) 
    password = ndb.StringProperty(required=True) 

def create_user(email, password): 
    token = os.urandom(24) 
    unique_email = UniqueEmail.get_or_insert(email, 
              token=token) 

    if token == unique_email.token: 
     # If the tokens match, that means a UniqueEmail entity 
     # was inserted by this process. 
     # Code to create User goes here. 
    # The tokens do not match, therefore the UniqueEmail entity 
    # was retrieved, so the email is already in use. 
    raise ValueError('That user already exists.')