joelgoop/demokratikollen — pull request #82 by rasmuse (2014-12-14 16:18:23+00:00)
Title: Appointments timeline #71

The appointments timeline now works pretty well. Can still be styled and improved in various ways before 1.0, but I'd say it's 90% done.

It's built according to Mike Bostocks "reusable chart" proposal, and should be easy to reuse in other places. I'm considering making a "party chairman" timeline on the party page, for example.

I have also added a couple of significant new features in the Flask/SQLAlchemy backend, which is why I'm making a pull request to summarize it all.

Note: New dependency and change of `Base` class in ORM
-------------------------------------------------------------------------------
The data backend makes use of a new dependency `py-flask-jsontools` (https://github.com/kolypto/py-flask-jsontools) that provides a very simple way of exposing SQLAlchemy objects with a JSON API. JSON serialization is done in a clever way that guarantees that serialization doesn't lead to extra database queries. Only the things you have already loaded will be dumped.

Just to illustrate, check out the new view I made to get appointment and group data out to the timeline figure:

```
@blueprint.route('//appointments.json', methods=['GET'])
@jsonapi
def appointments_json(member_id):
appointments = db.session.query(with_polymorphic(Appointment, '*'), Group) \
.filter(Appointment.member_id == member_id) \
.outerjoin(Group) \
.all()

return appointments
```
This sort of magic is enabled by attaching `flask.ext.jsontools.DynamicJSONEncoder` as the default JSON encoder to the Flask app.

And a JSON serializer for `date` and `datetime`
--------------------------------------------------------------------
But if you try to serialize something like an `Appointment`, you still run into problems because the standard JSON encoder doesn't support `datetime.date` or `datetime.datetime`. So I wrote a minimal implementation of that functionality, inherited the `flask.ext.jsontools.DynamicJSONEncoder` and attached that new encoder as default JSON encoder on the Flask app. This means you will get an ISO standard date or datetime string (see https://docs.python.org/3.4/library/datetime.html#datetime.datetime.isoformat) whenever Flask makes JSON from a `datetime.date` or `datetime.datetime` object.