Django for Flask users
05 Feb 2017I’m using Django for a serious project for the first time. I had played with Django a couple of times before, but I’m a long-time Flask fanboy and I invariably gave up in frustration (“why would anyone ever need separate files for settings, urls, and views?!”). Well, turns out Django is pretty cool if you want to put a bunch of apps under the same umbrella. Now, the official tutorial is a bit too verbose if you’re impatient. And if you’re used to Flask’s minimalism, you will get impatient with Django at times. So, here a few potentially useful pointers (largely for my own future consultation).
To get started, just pip install
Django, run django-admin startproject mysite
, then run python manage.py startapp myapp
. (Replace mysite
and myapp
by whatever names you want.) This should create the essential files and directories you’ll need.
making urls work
In Flask you create your views and map your urls all at once:
This is about as simple as it gets (unless you want to get really minimalist).
In Django you can’t do that. You have to define your views in one place and map your urls elsewhere. The usual way to do it is to define your views in your (aptly named) myapp/views.py
file, like this:
Unlike in Flask you can’t just do return 'Hello World!'
- the returned object cannot be a string, so we need to import HttpResponse
. Also unlike in Flask, we must feed the request to the function - there is no global request
object in Django, so we need to pass it around explicitly (more about this in a moment).
Now on to mapping urls. This requires changing two different files. The first is your mysite/urls.py
file, wherein you’ll put this:
This piece of code tells mysite
(the big project inside which your various apps will live) to defer to myapp
(one of your various apps) whenever someone hits http://blablabla/myapp/
. (That r'^myapp/
thing is a regular expression that matches any url that contains myapp/
.)
So, mysite/urls.py
is a big dispatcher: it’ll check the url and send the request to the appropriate app. Here we only have one app (myapp
), but if you’re using Django you’ll likely have several apps, in which case the urlpatterns
list will contain several url()
objects.
Now, myapp
must be prepared to receive the baton. For that to happen your myapp/urls.py
file (not your mysite/urls.py
file!) must look like this:
Here we have another regex: r'^$
. This will capture any requests that end in myapp/
. (If the request got this far then it must contain myapp/
, so you don’t need to repeat it in the regex here.) We’re telling myapp
that any such requests should be handled by the view function named index
- which you defined before, in your myapp/views.py
file (see above).
So, myapp/urls.py
is a secondary dispatcher: it’ll check the url and send the request to the appropriate view. Here we only have one view (the app’s index page), but in real life you’ll have several views, in which case the urlpatterns
list will contain several url()
objects.
That’s it. If you run python manage.py runserver
and then open http://127.0.0.1:8000/
in your browser you should be greeted by the Hello World!
message.
If you really want to you can have a single-file Django project: check this. But if your project is so small that you can have a single file then maybe you’d be better off using Flask or CherryPy or some other minimalist web framework.
request and session
Accessing request and session data in Flask is a no brainer. There is a global request
object and a global session
object and, well, you just do whatever you want to do with them.
In Django, as I mentioned before, there is no global request
object - you need to explicitly pass request
around to work with it. There is no global session
object either. Instead, session
is an attribute of request
. This is how the above snippet translates into Django:
So, session
becomes request.session
and request.form
becomes request.POST
.
templates
You must tell Django where to look for templates. Open mysite/settings.py
, locate the TEMPLATES
list and edit DIRS
.
There are a few syntax differences between Jinja2 (Flask’s default templating language) and Django’s templating language (DTL). For instance, to access the first element of mylist
it’s {% mylist[0] %}
in Jinja2 but {% mylist.0 %}
in DTL. But most of the syntax is identical. Template inheritance works the same way, with {% extends 'parent.html' %}
and {% block blockname %}{% endblock $}
. Same with loops, if/elses, and variables: {% for bla in blablabla %}{% endfor %}
, {% if something %}{% elif somethingelse %}{% else %}{% endif %}
, {{ some_variable }}
. If you’re porting something from Flask to Django there is a chance your templates will work just as they are.
You need to change your views though. In Flask you render a template and pass variables to it like this:
In Django you do it like this:
So, in Django you must pass the request
object to render the template. And your template variables must be passed as a dict.
connections
In both Flask and Django you can use something like pyodbc
or pymssql
to connect to your databases. But you can put a layer of abstraction on top of that. In Flask there is Flask-SQLAlchemy. Here’s their quickstart snippet:
In Django the connection and the models go into separate scripts. You set up the connection by adding an entry to the DATABASES
dict in your mysite/settings.py
file:
Then, in your myapp/models.py
, you define your models.
You don’t have to use any models though. If you prefer to run raw SQL queries you can do it like this:
Just as you would do with pyodbc (except that here you don’t need to .commit()
after every database modification).
afterwards
I’m just trying to get you past the initial rage over all the boilerplate code Django requires. :-) This is all just about syntax - I’m merely “translating” Flask to Django. If you’re serious about Django you should invest some time in learning Django’s semantics. Their official tutorial is a good place to start. Have fun!