代码之家  ›  专栏  ›  技术社区  ›  fredrik

使用db.stringproperty()作为Google应用程序引擎中的唯一标识符

  •  2
  • fredrik  · 技术社区  · 14 年前

    我只是有预感。但如果我觉得我做错事了。我要做的是将db.StringProperty()作为唯一标识符。我有一个简单的db.model,带有属性名和文件。如果我添加的另一个条目与db.model中已有的条目具有相同的“名称”,我想更新这个条目。

    据我所知,我查了一下:

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

    检查它是否已经是一个条目:

    if template.count() > 0:
    

    然后添加或更新它。但是从我读到的内容来看,count()在CPU使用上是非常昂贵的。

    是否可以将“name”属性设置为唯一,并且数据存储将自动更新它,或者用另一种更好的方法进行更新?

    弗雷德里克

    6 回复  |  直到 12 年前
        1
  •  2
  •   Nick Johnson David Cournapeau    14 年前

    不能在应用程序引擎数据存储中使属性唯一。相反,您可以为您的模型指定一个保证是唯一的键名-请参见 the docs 详情。

        2
  •  2
  •   Nicholas Lemay    14 年前

    我也遇到了同样的问题,并提出了以下最简单的答案:

    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

        3
  •  1
  •   Tom van Enckevort    14 年前

    您可以尝试获取实体并对其进行编辑,如果找不到,请创建一个新实体:

    template = Templates.gql('WHERE name = :1', name)
    if template is None:
      template = Templates()
    
    # do your thing to set the entity's properties
    
    template.put()
    

    这样,当找不到新条目时,它将插入新条目;如果找到新条目,它将使用您所做的更改更新现有条目(参见文档 here )

        4
  •  1
  •   moraes    13 年前

    另一种解决方案是创建一个模型来存储唯一的值,并使用 Model.property_name.value 作为键。只有在创建该值时,才能保存实际模型。此解决方案描述如下(带代码):

    http://squeeville.com/2009/01/30/add-a-unique-constraint-to-google-app-engine/

        5
  •  0
  •   RyanW    14 年前

    我同意尼克的看法。但是,如果您确实希望基于属性检查模型/实体的存在,那么get()方法很方便:

    template = Templates.all().filter('name = ', name).get()
    if template is None:
      # doesn't exist
    else:
      # exists
    
        6
  •  0
  •   Chris Dutrow    12 年前

    我写了一些代码来做这个。它的想法是非常容易使用。所以你可以这样做:

    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 )