139

I'm writing a ToDo list app to help myself get started with Python. The app is running on GAE and I'm storing todo items in the Data Store. I want to display everyone's items to them, and them alone. The problem is that the app currently displays all items to all users, so I can see what you write, and you see what I write. I thought casting my todo.author object to a string and seeing if it matches the user's name would be a good start, but I can't figure out how to do that.

This is what I have in my main.py

... 
user = users.get_current_user()

if user:
    nickname = user.nickname()
    todos = Todo.all()
    template_values = {'nickname':nickname, 'todos':todos}
...

def post(self):

    todo = Todo()
    todo.author = users.get_current_user()
    todo.item = self.request.get("item")
    todo.completed = False

    todo.put()      
    self.redirect('/')

In my index.html I had this originally:

<input type="text" name="item" class="form-prop" placeholder="What needs to be done?" required/>
...
 <ul>
{% for todo in todos %}
  <input type="checkbox"> {{todo.item}} <hr />
{% endfor %}
</ul>

but I'd like to display items only to the user who created them. I thought of trying

{% for todo in todos %}
    {% ifequal todo.author nickname %}
  <input type="checkbox"> {{todo.item}} <hr />
    {% endifequal %}
{% endfor %}

to no avail. The list turns up blank. I assumed it is because todo.author is not a string. Can I read the value out as a string, or can I cast the object to String?

Thanks!

Edit: Here is my Todo class

class Todo(db.Model):
    author = db.UserProperty()
    item = db.StringProperty()
    completed = db.BooleanProperty()
    date = db.DateTimeProperty(auto_now_add=True)

Will changing my author to a StringProperty effect anything negatively? Maybe I can forgo casting altogether.

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Amru E.
  • 2,008
  • 3
  • 17
  • 23

6 Answers6

140

In python, the str() method is similar to the toString() method in other languages. It is called passing the object to convert to a string as a parameter. Internally it calls the __str__() method of the parameter object to get its string representation.

In this case, however, you are comparing a UserProperty author from the database, which is of type users.User with the nickname string. You will want to compare the nickname property of the author instead with todo.author.nickname in your template.

Jeff Lockhart
  • 5,379
  • 4
  • 36
  • 51
  • Thanks for the answer. I'm getting the following error when trying str(todo.author) in the template: `TemplateSyntaxError: Could not parse the remainder: '(todo.author)' from 'str(todo.author)'` any ideas? – Amru E. May 27 '13 at 08:07
  • 1
    Try putting quotes around `'str(todo.author)'` like so. I'm not experienced with Django templates, but it seems its parsing mechanism is getting hung up at the parenthesis after the `str` function name. Or you might rather get the string property of the author, possibly something like `todo.author.nickname`, without the need for the `str()` call. – Jeff Lockhart May 27 '13 at 08:53
  • I finally got it to work! I used todo.author.nickname in my if statement and checked if that value matched the nickname of the current user. Please edit your answer to include that so I can accept it. – Amru E. May 27 '13 at 09:03
80

In Python we can use the __str__() method.

We can override it in our class like this:

class User: 
    def __init__(self):
        self.firstName = ''
        self.lastName = ''
        ...
        
    def __str__(self):
        return self.firstName + " " + self.lastName

and when running

print(user)

it will call the function __str__(self) and print the firstName and lastName

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Amirouche Zeggagh
  • 3,428
  • 1
  • 25
  • 22
7

str() is the equivalent.

However you should be filtering your query. At the moment your query is all() Todo's.

todos = Todo.all().filter('author = ', users.get_current_user().nickname()) 

or

todos = Todo.all().filter('author = ', users.get_current_user())

depending on what you are defining author as in the Todo model. A StringProperty or UserProperty.

Note nickname is a method. You are passing the method and not the result in template values.

simeg
  • 1,889
  • 2
  • 26
  • 34
Tim Hoffman
  • 12,976
  • 1
  • 17
  • 29
  • Thanks for reply! I will go ahead and try to implement the filter now. I'm a bit confused about nickname though. I have played around with it before and I was able to manipulate it like any other string and send it through the template value just fine. Am I missing something? Oh and author is a UserProperty. I'll add that to my original question. – Amru E. May 27 '13 at 07:47
  • I don't use django templates, so I don't know what they will do. Some templating systems will automatically call callables (nickname()) – Tim Hoffman May 27 '13 at 08:13
  • Do you mind briefly explaining what the filter would do? I am not sure what the actual function of my todos = Todo.all() is. – Amru E. May 27 '13 at 08:18
  • As you can see from the exmaple code, filter is a query argument, specifically author property = some value. You really shoudl spend some time reading the docs, it will save you a lot of time. https://developers.google.com/appengine/docs/python/datastore/ talks about the datastore and how to get/put and query data. – Tim Hoffman May 27 '13 at 09:24
2

You should define the __unicode__ method on your model, and the template will call it automatically when you reference the instance.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
2

In function post():

todo.author = users.get_current_user()

So, to get str(todo.author), you need str(users.get_current_user()). What is returned by get_current_user() function ?

If it is an object, check does it contain a str()" function?

I think the error lies there.

sinhayash
  • 2,693
  • 4
  • 19
  • 51
  • users.get_current_user() returns a User object which has nickname() to provide a readable name for the user. I was having trouble getting the nickname correctly, but I figured it out. Thanks! – Amru E. May 27 '13 at 09:09
2

Another way is using the __dict__ special attribute, for example:

str(user.__dict__)

or

print(user.__dict__)

More information about special attributes here

Vitaly Olegovitch
  • 3,509
  • 6
  • 33
  • 49