2010-02-10 90 views
2

我只是對此有所預感。但是如果我覺得我做錯了方式。我想要做的是將db.StringProperty()作爲唯一標識符。我有一個簡單的db.Model,屬性名稱和文件。如果我添加與db.Model中已有的相同「名稱」的另一個條目,我想更新它。使用db.StringProperty()作爲Google App Engine中的唯一標識符

由於知道的我看它有:

template = Templates.all().filter('name = ', name) 

檢查它是否是一個條目已:

if template.count() > 0: 

然後將其添加或更新。但是從我讀過的.count()在CPU使用上每個都很昂貴。

有沒有設置「名稱」屬性是唯一的,數據存儲會自動更新它或另一種更好的方式來做到這一點?

..fredrik

+1

即使計數()不計算昂貴,沒有全局事務,你就會有一個可能的競爭條件與「查詢,然後加如果沒有結果「解決方案。 – geoffspear 2010-02-10 16:07:16

回答

2

您無法在App Engine數據存儲中創建唯一屬性。您可以做的是爲您的模型指定一個關鍵名稱,該名稱保證是唯一的 - 有關詳細信息,請參見the docs

+0

如果您嘗試使用已使用的密鑰創建新實體,那麼GAE假設您嘗試更新實體? – Dinoboff 2010-02-18 02:46:01

+0

是的。您可以避免使用事務進行覆蓋 - 例如,Model.get_or_insert執行的操作。 – 2010-02-19 08:28:50

+0

因此,基本上,您可以爲實體指定一個唯一屬性,並且它必須是key_name。它是否正確?如果你想確保在給定種類的所有實體中有兩個或更多的屬性是唯一的,那麼是否有一種直接的方式來做到這一點? – 2010-08-13 21:14:11

1

你可以只是試圖讓你的實體和編輯它,如果沒有發現創建一個新:

template = Templates.gql('WHERE name = :1', name) 
if template is None: 
    template = Templates() 

# do your thing to set the entity's properties 

template.put() 

這樣,它會插入新的條目時WASN找不到,如果找到它,它會根據您所做的更改更新現有條目(請參閱文檔here)。

+0

必須知道您是否想要創建或更新實體。如果想創建一個新實體,如果存在一個具有相同名稱的實體,則希望創建失敗。 – Dinoboff 2010-02-18 02:49:13

0

我同意尼克。但是,如果你曾經想根據屬性來檢查模型/實體存在,get()方法是很方便的:

template = Templates.all().filter('name = ', name).get() 
if template is None: 
    # doesn't exist 
else: 
    # exists 
2

我有同樣的問題,用下面的答案最簡單的想出了一個:

class Car(db.Model): 
    name = db.StringProperty(required=True) 

    def __init__(self,*args, **kwargs): 
     super(Car, self).__init__(*args, **kwargs) 
     loadingAnExistingCar = ("key" in kwargs.keys() or "key_name" in kwargs.keys()) 
     if not loadingAnExistingCar: 
      self.__makeSureTheCarsNameIsUnique(kwargs['name']) 


    def __makeSureTheCarsNameIsUnique(self, name): 
     existingCarWithTheSameName = Car.GetByName(name) 
     if existingCarWithTheSameName: 
      raise UniqueConstraintValidationException("Car should be unique by name") 

    @staticmethod 
    def GetByName(name): 
     return Car.all().filter("name", name).get() 

重要的是不要先檢查我們是否首先加載現有實體。

對於完整的解決方案:http://nicholaslemay.blogspot.com/2010/07/app-engine-unique-constraint.html

+0

Nicholas,你不需要在key_name屬性中存儲唯一值嗎?我認爲這會留下漏洞,因爲您正在查詢和編寫分佈式數據存儲,並且只有key_name屬性保證是唯一的。 – 2010-08-13 21:11:53

0

我寫了一些代碼來做到這一點。它的想法是非常容易使用。所以你可以這樣做:

if register_property_value('User', 'username', 'sexy_bbw_vixen'): 
    return 'Successfully registered sexy_bbw_vixen as your username!' 
else: 
    return 'The username sexy_bbw_vixen is already in use.' 

這是代碼。有很多評論,但它實際上只有幾行字:

# This entity type is a registry. It doesn't hold any data, but 
# each entity is keyed to an Entity_type-Property_name-Property-value 
# this allows for a transaction to 'register' a property value. It returns 
# 'False' if the property value is already in use, and thus cannot be used 
# again. Or 'True' if the property value was not in use and was successfully 
# 'registered' 
class M_Property_Value_Register(db.Expando): 
    pass 

# This is the transaction. It returns 'False' if the value is already 
# in use, or 'True' if the property value was successfully registered. 
def _register_property_value_txn(in_key_name): 
    entity = M_Property_Value_Register.get_by_key_name(in_key_name) 
    if entity is not None: 
     return False 
    entity = M_Property_Value_Register(key_name=in_key_name) 
    entity.put() 
    return True 
# This is the function that is called by your code, it constructs a key value 
# from your Model-Property-Property-value trio and then runs a transaction 
# that attempts to register the new property value. It returns 'True' if the 
# value was successfully registered. Or 'False' if the value was already in use. 
def register_property_value(model_name, property_name, property_value): 
    key_name = model_name + '_' + property_name + '_' + property_value 
    return db.run_in_transaction(_register_property_value_txn, key_name)