简体   繁体   中英

Python Google App Engine query inside transaction without ancestor?

Ok a little implementation problem I have enccountrered since I am migrating from SQL to noSQL HDR.

I have a model called page:

class Page(db.Model):
    url = db.StringProperty(required=True)
    title = db.StringProperty()
    enable_login = db.BooleanProperty(required=True, default=True)
    owner = db.ReferenceProperty(Person, collection_name = 'pages')
    date_created = db.DateTimeProperty(auto_now_add=True)
    date_edited = db.DateTimeProperty(auto_now=True)

Everytime a user registers, then a page is created with a unique url that is not used as the key_name for several reason that I am willing to discuss.

Inside a transaction:

unique_url=hashlib.md5(str(person.key())).hexdigest()
page = Page(key_name=unique_url,parent=person, owner=person, title="Home page", name=person.nick_name, url=unique_url)

Now my problem arises when a user tries to update his page url. The user is only allowed to change his page url only once. The user POSTS a new page url, then the server checks if that url exists and if not updates the user page.

Again inside a transaction due to the fact that I dont want any duplicate urls:

def validate_page_properties(self, page):
  if not re.match("\A[A-Za-z]+\Z", page.url) or len(page.url) < 4 or len(page.url) > 20:
    return False
  page = Page.all().filter("url =",page.url).get()

Error:

Only ancestor queries are allowed inside transactions.

How can I overcome this implementation error?

I tried setting the url as the the key_name since it's unique (enforced) but I still need the complete key due to the fact the the parent of every page is the user. I can change to pages not having a parent, but that could later create a problem again with transactions that I might need.

Any suggestions? Am I missing something here?

First you should understand GAE transactions and what can be done within transaction .

In your case you already set a person to be parent of page, so you should only set this in the query:

 page = Page.all().ancestor(person).filter("url =",page.url).get()

Update: you can not use a person-scoped transaction and at the same time check for globally unique user-generated string. Either you have a string wich is person-unique (= nonsense) or scope must be global. You could achieve this by:

  1. Using global parent - having a single entity UniqueUrlParent that is a parent to all user submitted Urls. This then becomes a bottleneck as writes are a limit to 5writes/s per entity group (which you only have a global one).
  2. Use Urls as keys - but you said you do not want to do that. Care to elaborate why not? You could use some kind of two way hash to not make this human readable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM