From Django .96.2 to 1.0
If you’re updating from Django .96 to 1.0, the first place to go is Porting your apps from Django 0.96 to 1.0. But there are a bunch of things not mentioned there that can bring a .96 app to a grinding crash.
Model-level validation is gone
The “validator_list” option to model fields has gone away in favor of validation functions, but that functionality isn’t yet a part of Django. I solve this by moving the validation function to the model, and then overriding the save function to always call it. That isn’t quite as useful, because it causes errors that need to be trapped, but it should work until model-level validation returns.
Note that this actually changed on moving from oldforms to newforms. The new forms system didn’t call the validator_list functions even under 0.96.2.
Overriding save requires special parameters
The save method didn’t use to need any parameters. It does now. There’s force_insert and force_update. The Writing Models documentation recommends:
[toggle code]
-
def save(self, force_insert=False, force_update=False):
- do_something()
- super(Blog, self).save(force_insert, force_update) # Call the "real" save() method.
- do_something_else()
I don’t know why that’s recommended over using *args and **kwargs; that would seem to me to be a longer-lasting fix.
Core=True is unnecessary
There is no core=True. This was used to determine whether or not an inline record needed to be removed. Now, there’s a delete checkbox next to each inline record.
HttpResponse mimetype must be str
This may be a mod_python requirement, but the mimetype given to HttpResponse must be type str, not unicode, but Django is treating all strings as unicode strings. So if you used to pull the mimetype from the database, something like this:
- response = HttpResponse(page, mimetype=mimetype)
You’ll have to coerce the variable to str:
- response = HttpResponse(page, mimetype=str(mimetype))
PhoneNumberField is gone
The model.PhoneNumberField is gone in favor of “local flavor”. You’ll need to import the model from localflavor.countrycode. For example:
- from django.contrib.localflavor.us.models import PhoneNumberField
- …
- phone = PhoneNumberField('Phone Number', blank=True)
mod_python PATH_INFO matches development server
Under 0.96, the PATH_INFO META under mod_python was a partial path, though it was a full path in the development server. In 1.0, it is now a full path under mod_python also.
Fields automatically escape HTML
I’ve saved the best for last. I have to say I’m torn on the propriety of magically escaping everything that goes through a template. On the one hand it does make sure that nobody forgets to escape a field; on the other hand, if you’ve been using templates to assiduously avoid hard-coding any HTML in your code, you’re going to find that this change goes pretty deep and requires extreme care to avoid exposing HTML or other code in your pages.
One of the reasons I switched to Django is that it managed to handle escaping HTML code in forms perfectly. Because I often put sample code in my blog entries and I often put real HTML in my blog entries, I know how much of a pain it is to know when to escape code and when not to; Django 0.96 did exactly what I needed. It escaped what needed to be escaped, and left what needed to be left. Under 1.0, as far as I can tell, it always escapes or it never escapes.
My first step was to change the method that returns the content field of my pages; I ran the final value through mark_safe(), like this:
[toggle code]
- from django.utils.safestring import mark_safe
- …
-
def pageContent
- …
- text = mark_safe(text)
- return text
However, some of the fields are normally accessed directly. Since I know that these fields always need to be HTML, I looked up the possibility of an “HTMLField” and found some partial examples. Note that the on-line examples often omit SubfieldBase, but you need that or Django will ignore to_python in the subclass.
[toggle code]
-
class HTMLField(models.TextField):
- __metaclass__ = models.SubfieldBase
-
def to_python(self, value):
- value= mark_safe(value)
- return value
Yesterday, while editing one of my pages with sample code in it, I suddenly saw the entire page disappear from the live version. Going back to the editor, I noticed that the sample code had become real code. Apparently, telling Django that a value is safe short-circuits whatever Django used to do when putting a value into a textfield on a custom form and on the admin form—both were showing entities as themselves rather than as their encoded form. < becomes <, with all the resultant hilarity you would expect when sample code suddenly starts rendering.
So I added a line to replace ampersands with their entity:
[toggle code]
-
class HTMLField(models.TextField):
- __metaclass__ = models.SubfieldBase
-
def to_python(self, value):
- value=value.replace('&', '&')
- value= mark_safe(value)
- return value
Now the forms worked. On re-uploading the resultant file to the server, however, suddenly the example code was double-escaped!
In the end, I removed the custom HTMLField and went through all of the non-form templates to add {% autoescape off %} {% endautoescape %} around each of the fields that can validly contain HTML.
This is the kind of cascading problem that I moved to Django to avoid; hopefully that’s the end of the hacks, but I suspect more will be necessary. It would be nice to have a model field option that says “escape this like you did in 0.96, because that was what I needed”.
- Porting your apps from Django 0.96 to 1.0
- “This guide will help you port 0.96 projects and apps to 1.0. The first part of this document includes the common changes needed to run with 1.0. If after going through the first part your code still breaks, check the section Less-common Changes for a list of a bunch of less-common compatibility issues.”
- Writing models
- “A model is the single, definitive source of data about your data. It contains the essential fields and behaviors of the data you’re storing. Generally, each model maps to a single database table.”
More Django
- Converting an existing Django model to Django-MPTT
- Using a SQL database to mimic a filesystem will, eventually, create bottlenecks when it comes to traversing the filesystem. One solution is modified preordered tree traversal, which saves the tree structure in an easily-used manner inside the model.
- Two search bookmarklets for Django
- Bookmarklets—JavaScript code in a bookmark—can make working with big Django databases much easier.
- Fixing Django’s feed generator without hacking Django
- It looks like it’s going to be a while before the RSS feed generator in Django is going to get fixed, so I looked into subclassing as a way of getting a working guid in my Django RSS feeds.
- ModelForms and FormViews
- This is just a notice because when I did a search, nothing came up. Don’t use ModelForm with FormView, use UpdateView instead.
- Django: fix_ampersands and abbreviations
- The fix_ampersands filter will miss some cases where ampersands need to be replaced.
- 29 more pages with the topic Django, and other related pages
Update: Added PhoneNumberField