开发者

Use a db.StringProperty() as unique identifier in Google App Engine

I just have a hunch about this. But if feels like I'm doing it the wrong way. What I want to do is to have a db.StringProperty() as a unique identifier. I have a simple db.Model, with property name and file. If I add another entry with the same "name" as one already in the db.Model I want to update this.

As of know I look it up with:

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

Check if it's one entry already:

if template.count() > 0:

Then add it or update it. But from what I've read .count() is every expensive in CPU usage.

Is there away to set the "name" property to be unique and the datastore will automatic update it or another bette开发者_运维技巧r way to do this?

..fredrik


You can't make a property unique in the App Engine datastore. What you can do instead is to specify a key name for your model, which is guaranteed to be unique - see the docs for details.


I was having the same problem and came up with the following answer as the simplest one :

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()

It's important to not that I first check if we are loading an existing entity first.

For the complete solution : http://nicholaslemay.blogspot.com/2010/07/app-engine-unique-constraint.html


You can just try to get your entity and edit it, and if not found create a new one:

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

# do your thing to set the entity's properties

template.put()

That way it will insert a new entry when it wasn't found, and if it was found it will update the existing entry with the changes you made (see documentation here).


An alternative solution is to create a model to store the unique values, and store it transationally using a combination of Model.property_name.value as key. Only if that value is created you save your actual model. This solution is described (with code) here:

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


I agree with Nick. But, if you do ever want to check for model/entity existence based on a property, the get() method is handy:

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


I wrote some code to do this. The idea for it is to be pretty easy to use. So you can do this:

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 is the code. There are a lot of comments, but its actually only a few lines:

# 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 )
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜