I've come to believe Django's way of defining database tables is wrong

January 30, 2015

Django defines both database tables and HTML forms in the same way, a way that seems to be extremely common in web frameworks across several languages (and which I think first surfaced in Rails, although I may well be wrong there):

class AForm(...):
   login = forms.CharField(...)
   email = forms.EmailField(...)
   ...

This is very appealing initially and Django goes well out of its way to make it all work. But over time I've come around to feeling that this is in fact the wrong way to do forms, database tables, and so on in Python. Why not boils down to one famous sentence from 'import this' (aka the zen of Python):

Explicit is better than implicit.

Django form classes and database classes are full to the brim of implicit magic. They're essentially an illusion. Worse, they're not really a very Pythonic illusion. We accept the illusion because it's convenient and this way of defining forms and tables has become more or less standard, but that doesn't mean that it's right in Python.

(My view is that the initial Rails version was a reasonably natural looking DSL that happened to also be valid Ruby code with the right mangling. The Python version is clearly not something you can read as a DSL, so I think that the seems show much more; it looks like Python but it's kind of bizarre Python.)

Given the Tim Peters remark I led with, I think a more Pythonic way would make explicit various things that are currently implicit. I don't have a good handle on what that would look like, though. Doing the setup in class __init__? Defining the table or form layout by calling code instead of defining a class? Either would be (or at least could be) more explicit and less magical.

(Part of the issue is that Python has decided that structures with named fields are only really available as classes. Once you have classes, all sorts of temptations start materializing and looking at least partly natural.)

PS: It's my view that the magical, illusory nature of Django form and table definitions starts showing through very distinctly once you want to do more complex things with them. Like much magic, it works best if you don't touch it at all.


Comments on this page:

By Helmut at 2015-01-30 03:16:28:

Could you give us a few examples of implicit magic bits that you would like to be more explicit?

By cks at 2015-01-30 12:56:04:

The obvious example of implicit magic is how Django forms have an implicit field order based on the order of definition in the class. That takes deep magic to achieve, is like nothing else in Python, and actually breaks down under circumstances if you do unusual things. But once you start looking there's a lot of unusual things involved, such as field definition. In my example, AForm.login certainly acts like a normal instance variable when you use it in code but it's really neither an instance variable (which would be created in __init__ anyways) or a property (which are what you normally create when you're writing something like this at class definition time).

(I think that form fields are normal instance variables plus a pile of metadata about them, but I'm not sure about the actual implementation. That's certainly what it feels like to use them; they act like instance variables but Django knows how to do magic things with them.)

By Helmut at 2015-02-01 23:31:25:

Cool, thanks for clarifying further. Now I understand better what you were getting at. :)

Written on 30 January 2015.
« The practical result of OpenBSD's support policy
Upgrades and support periods »

Page tools: View Source, View Normal.
Search:
Login: Password:

Last modified: Fri Jan 30 02:14:09 2015
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.