Week 9 Miscellany
http://www.flickr.com/photos/unusual_image/3866046218/
Making views less repetitive
Typing this gets old after a while:
from django.shortcuts import render_to_response
from django.template import RequestContext
def some_view(request):
# ... define something ...
render_to_response('some_template.html', {'something': something},
context_instance=RequestContext(request))
Let's DRY that off
Let's wrap that up in a utility function so we don't have to type
so much (I'll put it in a utils.py file in my project
dir):
from django.shortcuts import render_to_response
from django.template import RequestContext
def render(template_name, context_dict, request):
return render_to_response(template_name, context_dict,
context_instance=RequestContext(request))
What's that do?
Now my views.py can be a lot simpler:
from myproject.utils import render
def some_view(request):
# ... define something ...
render('some_template.html', {'something': something}, request)
Much nicer! (So much so that something like this will be included in Django 1.2).
Security update to Django 1.1
We should all upgrade our projects to Django 1.1.1, which has a critical security fix but is otherwise backwards-compatible with 1.1. First modify your requirements.txt file to specify Django==1.1.1, then with your virtualenv activated:
$ easy_install pip==dev $ pip install -r requirements.txt
Mea culpa
http://www.flickr.com/photos/senzanome/2265614466/
In our last episode...
syntax: glob *.pyc *~ *# db.sqlite
Ooops.
Try this instead
syntax: glob *.pyc *~ *\# db.sqlite
Also, the last line needs to be changed to whatever your database file is named (mydatabase, djangodb.sqlite, sqlite.db...).
And remember that the .hgignore file doesn't remove
anything you already added: have to use hg rm for that
(or just delete the file and then hg addremove).
What goes in? Code vs data
Code is your project. It goes in your repo.
Files that are part of your site design (i.e. banner images, logos, icons...) are part of your project. They go in your repo.
Data changes all the time. Your database, and things connected to your database data (i.e. uploaded files and images), do not go in your repo.
The middle ground
There is a middle ground: initial data that's required to be in the database for your project to function at all, and test data that just makes it more convenient to get the project up and running quickly for development at a new location.
Fixtures
The solution: fixtures. A text format (XML or JSON) dump of your data that can easily be loaded back into the database. Why fixtures and not just committing a sqlite db file?
- SQLite is only good for development. Once you deploy to a real database (Postgres, MySQL), you can't just commit the database file into your repo (you usually don't have access to it), you have to dump the data somehow.
- Your SQLite db file changes all the time as you're working on your site. Fixtures should only change when you need them to.
- Mercurial can't merge changes in a binary file (like the SQLite db). It can merge changes in a text file.
How?
First create a fixtures directory in your project dir next to
settings.py etc (mkdir fixtures), and
add FIXTURE_DIRS = (join(PROJECT_DIR, 'fixtures'),) in
your settings.py so Django knows where to look for your
fixtures.
Dumping data
python manage.py dumpdata --format=json --indent=4 appname appname2 > fixtures/test_data.json
Dumps all the data currently in your database, from the
apps appname and appname2, into the
file fixtures/test_data.json
You can list only one app, or as many as you want. You can also
use appname.modelname to dump only the contents of a
certain model: for instance I often use auth.user to dump
a test user or two, without getting a bunch of other crud from the
django.contrib auth app.
Loading data
python manage.py loaddata test_data
This loads the data from the site_data.json fixture
file into your database. If you do this when your database is not
empty, it will overwrite models in your database with the same
auto-ids (primary keys) as the ones in your fixture, and leave others
alone.
Note that you don't have to give the path to the file (Django knows that from your FIXTURE_DIRS setting), and you can leave off the .json extension.
What about uploaded files/images?
If your models include an ImageField or FileField, you'll have a
directory or two under media where those uploaded files
go (determined by your upload_to parameter). These
directories should be in your .hgignore so those uploaded
files don't get committed to the repo: they are data,
and they change constantly as you test your site in development;
committing them will balloon your repo's size and make merges etc very
difficult.
But if you dump some test data, you'll want to also save the images
that go with it, otherwise that test data might be missing its images
when you load it later. So copy those into your fixtures dir,
too: cp -a media/uploaded_photos fixtures/. This stuff
in the fixtures dir should be committed; the point is
to have this test data with you wherever your repo goes.
Restoring the uploaded files.
So when you use python manage.py loaddata test_data to
load your fixture into the database, you also want to restore the
associated images back to their proper place under media/: cp -a
fixtures/uploaded_photos media/
Wrapping it all up in scripts
Now you have two long-ish commands to run when you dump your fixture, and two more to restore it. Let's wrap those up in a couple of scripts...