views:

58

answers:

1

I'm new to Google Apps and I've been messing around with the hello world app that is listed on the google app site. Once I finished the app, I decided to try to expand on it. The first thing I added was a feature to allow the filtering of the guestbook posts by the user that submitted them.

All I have changed/added is simply a handler to the WSGIApplication and a new class for this handler. The model is the same, I'll post for reference:

class Greeting(db.Model):
    author = db.UserProperty()
    content = db.StringProperty(multiline = True)
    date = db.DateTimeProperty(auto_now_add=True)

Using the Django template I changed the line that displays the authors nickname from:

<b>{{ greeting.author.nickname }}</b> wrote:

to:

<a href="/authorposts/{{ greeting.author.user_id }}">
  {{ greeting.author.nickname }}
</a></b> wrote:

The issue I'm having is that inside my python code I cannot access "greeting.author.nickname", or any of the other properties, such as "user_id". However they are accessible from the Django template, as the code I listed above for the template works and correctly creates a link to the author as well as displaying the nickname.

I am using URL Mapping based on the authors (a UserProperty) property "user_id". I am trying to find a way that I can filter the datastore using the user_id as the criteria. I've tried directly applying a filter to the query, I've tried pulling all the records and then iterating through them and use an If...Else clause.

I know the value is store into the datastore, because the Django template shows it, what do I have to do to use it as filter criteria?

+1  A: 

When querying the Greeting model, you cannot filter on fields within Greeting.author (e.g., greeting.author.nickname). In SQL, this would be done by doing a join on the Greeting and User tables. However, in GAE you can only query properties directly included on the model you are querying.

Since author is a db.UserProperty, you can filter by user like this:

# fetch up to 10 greetings by the current user
user = users.get_current_user()
results = Greeting.all().filter('author =', user).fetch(10)

To filter on other fields within author, you would need to denormalize your Greeting model - i.e., add copies of fields in author which you want to be able to filter Greeting on. For example, if you wanted to filter by author.nickname, you would add an author_nickname field to your Greeting model (and keep its value up to date with author.nickname):

class Greeting(db.Model):
    author = db.UserProperty()
    author_nickname = db.StringProperty() # denormalization (copy of author.nickname)
    content = db.StringProperty(multiline = True)
    date = db.DateTimeProperty(auto_now_add=True)

If you add this sort of denormalization to your model, it might be helpful to use Nick Johnson's aetycoon library to make author_nickname update whenever author is updated (just so you don't have to manually enforce that relationship).

David Underhill
The issue I have with your first example is that I'm trying to filter using an user_id, however I am not logged in as that user. Is there a way I can create a user object with the id I'm trying to filter against?In regards to your second example, I have considered going down that route, and if thats the only method that works, then thats what I'll implement, and I will check out that library, as something tells me that if people have created libraries with the functionality of keeping the denormalized data consistent, its probably the only method at this point.
Timbermar
It sounds like denormalization is going to be required to get the functionality you want. You could also add `user_id` to the `Greeting` model.
David Underhill
Yeah, I think that is going to be the method I use, I've found nothing else that can give this functionality. Thanks!
Timbermar