Flask and Peewee 101

Flask and Peewee 101

My curiosity is my doom. I should have settled on a web framework years ago and I should just use it. Unfortunately, I haven’t done that. Currently, I’m enjoying Flask. By enjoying, I mean bumbling my way around. I’m going to be throwing up notes on the blog periodically.

Requirement: Downloading Results of an SQL Query as a CSV File

Almost everything I write needs this. Here’s a snippet that gives you an idea of how to make this happen:


   @app.route('/returncsv/')
   @auth.login_required # this is part of the flask-peewee package.
   def returncsv():
        students = Student.select().order_by(Student.lname, Student.fname)
        csvfile = cStringIO.StringIO()
        writer = csv.writer(csvfile)
        writer.writerow(['Last','First','Emplid',
                       'Netid','Email','Group'])
        for student in students:
            writer.writerow([student.lname,
            student.fname,
            student.emplid,
            student.netid,
            student.email,
            student.group])
        csvfile.seek(0) # Rewind the file
        return send_file(csvfile,
                      attachment_filename="profstudents.csv",
                      as_attachment=True)

You can see more about this here: http://flask.pocoo.org/snippets/32/. Also, note the comment with its caution about unicode objects.

Requirement: Creating a Select List Based on an SQL Query

This is another standard one. Assume that students can only be enrolled in certain groups. We would like them to pick the groups from a list returned from an SQL query. While this is partly Flask, it’s mostly Flask-peewee stuff.

  @app.route('/selfregister/', methods=['GET', 'POST'])
  def selfregister():
      form = SelfRegister(request.form)
      form.selfgroup.choices = [(q.group, q.group + '-' + q.room) for q in ELSGroup.select()]
      if request.method == 'POST' and form.validate():
          selfgroup = form.selfgroup.data
          session['selfgroup'] = str(selfgroup)
          s = Student.update(group = selfgroup).where(Student.netid == form.netid.data)
          s.execute()
          # Use 'get' to retrieve a single item. Otherwise, you're returning a query.
          selfstudent = Student.get(Student.netid == form.netid.data)
          # flash('%s, you have succesfully registered for session %s.' % (selfstudent.fname, str(selfgroup)))
          return render_template('selfsuccessful.html', selfstudent = selfstudent)
      return render_template('selfregister.html', form=form)

There are a couple of things going on here. The Flask-peewee query result stored in form.selfgroup.choices creates a list of tuples like this:

[(u'1', u'1-1C'),
(u'10', u'10-CSLR Library'),
(u'11', u'11-575 (Fac Lounge)'),
(u'12', u'12-5K'),
(u'13', u'13-Elsas Room (Lib 4th)')]

These choices are used to populate a wtforms.Form instance. The form is defined in my models.py like so (with the validation code left out for brevity):

class SelfRegister(Form):
netid = StringField(u'NetID', [validators.Required(), validators.Length(max=7), validators.Regexp(CHECK_RE,message=u'Invalid characters. Use letters and numbers only.'),])
selfgroup = SelectField(u'Group')

Having populated form.selfgroup.data with the results of the Flask-peewee query, we then render_template('selfregister.html', form=form) to generate the initial form from which the student will select her choices. The form selfregister.html then looks like this:

{% from "_formhelpers.html" import render_field %}
{% extends "base.html" %}
{% block title %}Choose Group{% endblock %}
{% block content %}
<form method="post" action="#">
<h2>Enter your NetID</h2>
<dl>
{{ render_field(form.netid) }}
</dl>
<dl>
<h2>Choose the proper group</h2>
{{ render_field(form.selfgroup) }}
</dl>
<p><input type="submit" value="Set Group">
</form>
{% endblock %}

Here’s a screenshot of what the student sees when the form is rendered:

Entering a netid and choosing a group
Entering a netid and choosing a group

_formhelpers.html comes straight from this page: http://flask.pocoo.org/docs/patterns/wtforms/ on the Flask site. This whole page is must reading if you’re doing stuff with WTForms in Flask. It’s also a nice example of leveraging the Jinja2 templating engine’s macro capability.

Conclusion

I’m just getting started (as is clear from my slow progress) with Flask and Flask-peewee, but I’m having a fun with it[1]. I welcome your feedback – perhaps we can learn something new together!


  1. Incidentally, I just read one of those articles that says if you’re over 35, you shouldn’t be programming. Hrmmmmmm…  ↩

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s