Tornado PyMongo product wishlist I am writing a Tornado app in which a user can maintain his products wishlist. There are two collections, users and products. As the names imply, the users collections will contain users info and the products collections will contain the URLs.  

Typically a user document in users collection will contain the following fields:


email_id
name
tracked_products


The tracked_products here is a list which maintains the wishlist. It contains the ObjectId mapped to URLs in products collection. To make it clear, when two users add the same product URL, in their respective user documents instead of containing the URL, they will have the ObjectId of this URL, which is the ID of the URL in the products collection.

To find tracked_products of a specific user:

    search_user = user_db.find_one({'email_id': user_email})
    search_user['tracked_products']


above will return to me list of ObjectIds.

To add a product URL to the user's wishlist:

product_doc = product_db.find_one({'url': url})
if not product_doc:
    # code needs to be added here to get product name from url
    product_id = str(product_db.insert({'product_name': 'iPad', 'url': url})
else:
    product_id = product_doc['_id']
user_db.update({'email_id': user_email}, {'$addToSet': {'tracked_products': ObjectId(product_id)}})


The following is the code when user wants to remove a URL from his wishlist. Do note that he will send the ObjectId instead of the URL, he intends to remove. This may seem less intuitive. The user will actually never know the ObjectIds, but the page rendered to him which displays the wishlist, will make call when user wants to delete the URL (am I clear here?):

user_db.update({'email_id': user_email}, {'$pull': {'tracked_products': ObjectId(product_id)}})


And here is my actual Tornado app code. I am not using any templating as of now, will add that later. Also ignore the repeated user_db = self.application.db.users statement which is present in all handlers (which should not, may app can have this variable). And one more thing: I access the current logged in user's email ID every time by a cookie.

Is there any way to avoid this? Can I have some global variable which stores user email ID every time the user is logged in?

class ProductsDisplayHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self):
        user_email = self.get_secure_cookie('trakr')
        user_db = self.application.db.users
        search_user = user_db.find_one({'email_id': user_email})
        self.write(str(search_user.get('tracked_products', None)))


class ProductAddHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self, url):
        user_email = self.get_secure_cookie('trakr')
        user_db = self.application.db.users
        product_db = self.application.db.products
        product_doc = product_db.find_one({'url': url})
        if not product_doc:
            product_id = str(product_db.insert({'product_name': 'iPad', 'url': url}))
        else:
            product_id = product_doc['_id']
        user_db.update({'email_id': user_email}, {'$addToSet': {'tracked_products': ObjectId(product_id)}})


class ProductDelHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self, product_id):
        user_email = self.get_secure_cookie('trakr')
        user_db = self.application.db.users
        user_db.update({'email_id': user_email}, {'$pull': {'tracked_products': ObjectId(product_id)}})
        self.redirect('/products')
        return
You can try editing your BaseHandler like this

class BaseHandler(tornado.web.RequestHandler):
    def prepare(self):
        self.user_email = self.get_secure_cookie('trakr')
        self.user_db = self.application.db.users


and then call the  following in your other Handlers 

self.userdb.update({'email_id': self.user_email},


Basically the prepare function is called right at the beginning of the request
for more information you can look at the tornado docs