views:

120

answers:

4

Hi,

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 better way to do this?

..fredrik

+1  A: 

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

tomlog
In must case you know if you want to create or update an entity. If want to create a new entity, you want to the creating to fail if an entity with the same name exist.
Dinoboff
+1  A: 

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.

Nick Johnson
If you tried to create a new entity with a key already in used doesn't GAE assume you try update the entity?
Dinoboff
Yes. You can avoid overwriting by using a transaction - eg, what Model.get_or_insert does.
Nick Johnson
So, basically, you can specify one unique property for an entity and it must be the key_name. Is this correct? If you wanted to ensure two or more properties were unique across all entities of a given kind, would there be a straight-forward way to do this?
Neal S.
A: 

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
RyanW
+1  A: 

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

Nicholas Lemay
Nicholas, don't you need to store the unique value in the key_name property? I think this leaves holes since you're querying and writing a distributed datastore and only the key_name property is guaranteed to be unique.
Neal S.