Deploying a Flask App with Peewee to Heroku

Background

Flask is a micro web application framework that allows rapid development and prototyping.  Having used Ruby on Rails, I wanted to try it out to see how it helps with prototyping a web app.

If you have not used Rails before, it works out of the box.  You type rails new <appname> and you get files generated in an organised directory structure – models, views, controllers, configuration files, tests, etc.  It also comes with SQLite database.  You have everything you need.  Sure, you need to spend some time learning which files go where and how to use the framework.

Flask on the other hand works with the concept of ‘one drop at a time.’  If you need something, you import it and use it.  There are no generated files or directory structures.  You start with a completely empty working directory.  It works really well when you want to take one small step at a time to develop what you have in mind because you need to learn only what is required and relevant.

Using Flask, I started off by building a very simple web API which uses a database.  To interface with a SQLite database in my local development environment, I used a database ORM called Peewee.  Later on, I wanted to make the app available outside local network so that more testing can be done from various devices.  I used Heroku, as I am already familiar with it as part of my previous Rails development.

The challenge is Heroku does not support SQLite.  It does, however, offer various other types of databases.  For Django apps, a Heroku Postgres database is automatically provisioned (the same is true for Rails apps).  For all other Python apps, a Postgres add-on must be provisioned manually.  This tutorial explains how to deploy to Heroku a Flask app which uses Peewee to connect to a database.

The source code used in this tutorial is available on GitHub at: https://github.com/swifthorseman/flask-peewee-heroku-setup.

Preliminaries

  1. Your app is already running fine locally.
  2. You have created an app on Heroku and know how to deploy it there.  If not, please follow the instructions in Getting Started with Python on Heroku.

Steps

  1. Set up Postgres on Heroku, following the instructions in Heroku Postgres.  Note that in the part where it says Connecting in Python, it tells you to install psycopg2.  It also assumes that you are using Python 2 rather than Python 3, since urlparse is a Python 2 module.  If you are using Python 3, you will need to import urllib.parse and also tell Heroku which Python runtime you are using, since the default runtime is 2.7.9.
  2. Set the database handle dynamically.  We modify the model file (tellytubbies.py) so that a correct database is selected based on the environment (e.g., on Heroku, elsewhere).  For details on setting config variables, see Configuration and Config Vars.  We set the variable HEROKU to 1 (since it is a key-value pair).  The value can be set from the command line (if you have the Heroku Toolbelt installed) or from the Heroku web interface.  You can set any key-value pair.We make use of this variable in tellytubbies.py as follows:
    db_proxy = Proxy()
    
    if 'HEROKU' in os.environ:
        import urlparse, psycopg2
        urlparse.uses_netloc.append('postgres')
        url = urlparse.urlparse(os.environ["DATABASE_URL"])
        db = PostgresqlDatabase(database=url.path[1:], user=url.username, password=url.password, host=url.hostname, port=url.port)
        db_proxy.initialize(db)
    else:
        db = SqliteDatabase('tellytubbies.db')
        db_proxy.initialize(db)
  3. We also need to manage the database connections explicitly.  It is implicitly managed when running SQLite but is required when using Postgres.  It is also a good practice to manage database connections explicitly when running a web application.We add the following in server.py.
    from flask import g
    from tellytubbies import db_proxy
    
    @app.before_request
    def before_request():
        g.db = db_proxy
        g.db.connect()
    
    @app.after_request
    def after_request(response):
        g.db.close()
        return response
  4. Deploy the app to Heroku.  Once deployed, we still need to create the database.  We do so by running: python tellytubbies.py, as we would do in a development environment.
    $ heroku login
    $ heroku run bash
    $ python tellytubbies.py
    

    We verify that the tellytubby table was created by logging into the database and listing the tables using psql:

    $ heroku pg:psql
    ---> Connecting to DATABASE_URL
    psql (9.3.5, server 9.4.4)
    WARNING: psql major version 9.3, server major version 9.4.
    Some psql features might not work.
    SSL connection (cipher: ECDHE-RSA-AES256-SHA, bits: 256)
    Type "help" for help.
    
    ::DATABASE=> \dt
                 List of relations
     Schema |    Name    | Type  |     Owner
    --------+------------+-------+----------------
     public | tellytubby | table | sgaluyzmzkklpj
    (1 row)
    ::DATABASE=> select * from tellytubby;
     id |    name     | colour
    ----+-------------+--------
      1 | Tinky Winky | Purple
      2 | Dipsy       | Green
      3 | Laa-Laa     | Yellow
      4 | Po          | Red
    (4 rows)

When you connect to the app through a URL, everything should now work!

A few concluding remarks

The general advice is that you should have the same type and version of database setup in your local environment as your production database so that there are no surprises when deploying.  In my case, I wanted to prototype my app and wanted to do it iteratively, so setting up a local Postgres database was the last thing on my mind.  Now that you have read this, perhaps it is time to go and set up a local Postgres database.

References

  1. Getting Started with Python on Heroku
  2. Heroku Postgres
  3. Postgresql config for local and heroku with peewee ORM
  4. How to use Flask/Peewee with Heroku?
  5. Dynamically defining a database
Advertisement

Star Ratings in Rails Using CSS

Star ratings are one of the most common features in the front-end of a system that allows users to provide feedback.  You see it on Amazon, IMDB, App Store, the list goes on.  I wanted to incorporate this functionality in a Rails application, so I was looking around the web.

My preferences are:

  • No JavaScript if possible.
    Most browsers have JavaScript turned on and the chances are with mostly Web 2.0 applications, they wouldn’t function without JavaScript.  However, there has been growing unpopularity of shipping a lot of JavaScript libraries (even if mimified) mainly due to increasing number of mobile users and the limited bandwidth available on mobile devices.  The less JavaScript the better for your web app.
  • No instant communication to the server necessary for the rating to be recorded.
    In some implementations, every time a star is selected, jQuery sends the rating to the back-end immediately.  Again, bandwidth does not come free.  Not just on mobile devices but on any connection.  In some parts of the world, high speed internet is still a scarce commodity.  If your app takes too long to load, the user experience will be off-putting.  Therefore, it is much preferable to have the rating sent to the back-end as part of the form submission.

In my attempt to find the most suitable one for my Rails app, I will document my findings here, in the hope that any person who is new to this arena like myself finds it of use.

The first one that I came across was called Star Ratings With Very Little CSS by Chris Coyier.  Before I stumbled upon this, I did not know that it was possible to do this without JavaScript.  As the author has advised, there still needs to be a way to register what the user has selected.  Otherwise, how would you send to the back-end what was selected?  His post referred to Accessible star rating widget with pure CSS by Lea Verou which I went on to explore further.

The trick involves using radio buttons to be displayed as stars.  As the title says, it involves no JavaScript.  I tried to integrate this to my Rails app and have listed below the steps involved in a tutorial on submitting book reviews (the code for this sample project is available on GitHub).  A book review has a summary, comments, star ratings and of course, the book being reviewed.

  1. Place the CSS code in app/assets/stylesheets/.  In our case, the CSS goes into bookreviews.css.
  2. The HTML code goes into _form.html.erb under app/views/bookreviews.
  3. We also make changes to the model, the controller and the view of bookreview so that ratings can be received, stored and displayed accordingly.

Using the HTML code as-is, we find that the ‘rating’ attribute will not be part of the bookreview hash of the params hash in the request sent to the server:

Started POST "/bookreviews" for 127.0.0.1 at 2015-05-12 19:05:50 +0000
Processing by BookreviewsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"PQqwM/AQG5aUKDjqU8yK/tu5PeQeQvxgYqfkoxnZoa8=", "rating"=>"4", "bookreview"=>{"summary"=>"Fantastic Book", "details"=>"Full of excitement and adventure.", "book_id"=>"2"}, "commit"=>"Create Bookreview"}

If that works for you, you need not read further.  However, we want ‘rating’ to be part of ‘bookreview,’ since it is an attribute of the bookreview model.  In order for this to tie up with Rails’ form_for generator, we need to make a few changes.  Essentially, the aim is to generate the similar HTML code using Rails’ form helpers.  Take a look at the radio_button and label methods to understand how the tag attributes are generated.  For the star ratings CSS to work, the value of the for attribute in the label tag must be the same as the value of the id attribute in the input tag.  In the original HTML code, they are “star5” and “star5,” “star4,” “star4” and so on.  To remind ourselves, this is what the original HTML code looks like:

<fieldset class="rating">
    <legend>Please rate:</legend>
    <input type="radio" id="star5" name="rating" value="5" /><label for="star5" title="Rocks!">5 stars</label>
    <input type="radio" id="star4" name="rating" value="4" /><label for="star4" title="Pretty good">4 stars</label>
    <input type="radio" id="star3" name="rating" value="3" /><label for="star3" title="Meh">3 stars</label>
    <input type="radio" id="star2" name="rating" value="2" /><label for="star2" title="Kinda bad">2 stars</label>
    <input type="radio" id="star1" name="rating" value="1" /><label for="star1" title="Sucks big time">1 star</label>
</fieldset>

The first part we need to write is the radio button:

<%= f.radio_button(:rating, "5") %>

which generates the following HTML code:

 <input id="bookreview_rating_5" name="bookreview[rating]" type="radio" value="5" />

So, id is concatenation of the current model name, the (humanised?) string generated from the symbol (rating) and the value (5) passed to the radio_button method of the FormBuilder object (f).  As mentioned above, for the star rating to work, the value of id in the input tag must be the same as that of for in the label tag.  Using the label method, we write the following after the input_tag:

<%= f.label(:rating.to_s + "_5", "Rocks!") %>

which generates the following HTML code:

<label for="bookreview_rating_5">Rocks!</label>

There you have it.  The code in Rails is:

<fieldset class="rating>
  <legend>Please rate:</legend>
  <%= f.radio_button(:rating, "5") %> <%= f.label(:rating.to_s + "_5", "Rocks") %> 
  <%= f.radio_button(:rating, "4") %> <%= f.label(:rating.to_s + "_4", "Pretty good") %> 
  <%= f.radio_button(:rating, "3") %> <%= f.label(:rating.to_s + "_3", "Meh") %> 
  <%= f.radio_button(:rating, "2") %> <%= f.label(:rating.to_s + "_2", "Kinda bad") %> 
  <%= f.radio_button(:rating, "1") %> <%= f.label(:rating.to_s + "_1", "Sucks big time") %>
</fieldset>

And the generated HTML code is:

<fieldset class="rating">
 <legend>Please rate:</legend>
 <input id="bookreview_rating_5" name="bookreview[rating]" type="radio" value="5" /><label for="bookreview_rating_5">Rocks!</label>
 <input checked="checked" id="bookreview_rating_4" name="bookreview[rating]" type="radio" value="4" /><label for="bookreview_rating_4">Pretty good</label>
 <input id="bookreview_rating_3" name="bookreview[rating]" type="radio" value="3" /><label for="bookreview_rating_3">Meh</label>
 <input id="bookreview_rating_2" name="bookreview[rating]" type="radio" value="2" /><label for="bookreview_rating_2">Kinda bad</label> 
 <input id="bookreview_rating_1" name="bookreview[rating]" type="radio" value="1" /><label for="bookreview_rating_1">Sucks big time</label>
</fieldset>

The request sent to the server now shows that ‘rating’ is now part of the bookreview hash:

Started POST "/bookreviews" for 127.0.0.1 at 2014-05-12 20:32:24 +0000
Processing by BookreviewsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"PQqwM/AQG5aUKDjqU8yK/tu5PeQeQvxgYqfkoxnZoa8=", "bookreview"=>{"rating"=>"4", "summary"=>"Fantastic Book", "details"=>"Full of excitement and adventure.", "book_id"=>"2"}, "commit"=>"Create Bookreview"}

Depending on your needs, you might want to style the form (e.g., removing the legend tag), play with the CSS code for different star colours and sizes.  Be sure to adjust the CSS parameters and test it in different browsers because I had a bit of a surprise when I opened the page in Firefox, though stars look pretty good on Chrome and Safari.  Who knows what it looks like in Internet Explorer.  In fact, I was pretty happy with this approach until I saw in Firefox how different the stars looked (they are smaller) and a slightly different ‘feel’ (e.g. when you click the third star, it is the only one that looks pressed).

To add icing on the cake, in the read-only mode, stars can be displayed using Font Awesome.  Using the logic described in Adding a 5 star ratings feature to a Rails 4 model by Pawel Janiak (which I will also explore), we define a method in the Book model to calculate the average rating, a helper method to determine how many full stars, open stars and half stars to be displayed based on the average rating and call them from View accordingly.

Does this suit my needs?  I’m sure there is a better solution which makes the look of the stars consistent but I will settle with this for the time being.  I will share what I find next or what I settle with.

Which iPad Would You Tell Your Friends to Buy?

Sarah Perez writes in “Apple Announces Too Many iPads“:

How many iPad models can you choose from now? Five? And that’s not even counting the fact that each flavor comes with various storage sizes as well as Wi-Fi and cellular versions!

This reminds me of the product line review Steve Jobs did when he made his second coming at Apple.  In ‘Steve Jobs,’ Walter Isaacson writes:

The product review revealed how unfocused Apple had become. The company was churning out multiple versions of each product because of bureaucratic momentum and to satisfy the whims of retailers. “It was insanity,” Schiller recalled. “Tons of products, most of them crap, done by deluded teams.” Apple had a dozen versions of the Macintosh, each with a different confusing number, ranging from 1400 to 9600. “I had people explaining this to me for three weeks,” Jobs said. “I couldn’t figure it out.” He finally began asking simple questions, like, “Which ones do I tell my friends to buy?”

So, which iPad would you tell your friends to buy?