Creating the Weblog Application
This is part 4 of a series of posts on James Bennett's excellent Practical Django Projects. The table of contents and explanation can be found here. Before we start going through the Weblog app, you may want to have a look at my post on Django tests. This will help sort out any basic errors you make typing up examples.In this section of the book James gives some useful tips for organising your project files, which are worth taking on board. I also recommend checking out Eric Florenzano's screencast on the topic. Once you get to the point of needing to maintain different combinations of versions of packages you'll want something more like zc.buildout or virtualenv but for now symlinks or altering your PYTHONPATH is going to be fine.
Designing the Models
On p47 we design the Category model. As usual remove the Admin class and create your own admin.py. If you want to do tests as well go ahead and create tests.py as well#admin.py from django.contrib import admin from coltrane.models import Category admin.site.register(Category)
#tests.py from coltrane import admin, models, viewsAdd coltrane to the installed apps as described on p48 and then run python manage.py test to ensure you haven't made any typos. Run python manage.py syncdb and continue with p48.
On p50 instead of adding prepopulate_from=['title'] to your Category model reorganise your admin.py instead to create a custom admin class.
#admin.py
from django.contrib import admin
from coltrane.models import Category
class CategoryAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug":("title",)}
admin.site.register(Category, CategoryAdmin)
Also on page 50 help_text is added. There is a way of overriding this in your admin class but for simple cases you can leave it in the model. I would have thought help_text would have been shifted entirely to forms but I guess there is a case to have some default description in your model to describe the field even if you override it in your form or admin.On p54 the class Entry is updated to include a prepopulated field slug. Update your admin.py for this.
#admin.py
from django.contrib import admin
from coltrane.models import Category, Entry
class CategoryAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug":("title",)}
class EntryAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug":("title",)}
admin.site.register(Category, CategoryAdmin)
admin.site.register(Entry, EntryAdmin)
On p59 the django-tagging app is downloaded.svn checkout http://django-tagging.googlecode.com/svn/trunk django-tagging
On page 60 the save function for the Entry class uses super which is briefly described. Super was one of those things that seems straightforward to me now, but the first time I saw it, it was like some magicians trick where half the trick is hidden from view, but a rabbit gets plucked impossibly from a hat. For the benefit of those new to python (and programming), I'll show a simple example.
# First we'll have our base class which is usually someone elses code you're going to subclass.
class Container(object):
"""Stuff comes out of containers"""
def payoff(self, some_object=None):
if some_object:
return "dove"
return
# Now here's the class we might have written
class Hat(Container):
"""Rabbits come out of hats"""
def payoff(self, some_object=None):
if some_object == "watch":
return "rabbit"
return super(Hat,self).payoff(some_object)
# Here's the example of how we'd use this class
>>> trick = Hat()
# if we put in a watch we get the class we've defined
>>> trick.payoff('watch')
rabbit
# If we put in anything else including nothing at all we get the parent class
>>> trick.payoff('hankerchief')
dove
Pretty straightforward really. I think I originally just got confused by the syntax of passing the name of the class in when you're calling it from the class itself, and the fact that invariably examples I'd seen didn't have the parent class code in front of me.Onto p61 ignore the class Admin, and then on p69 there is a typo in the regex. The last bit should be (?P<slug>[-\w]+)/$'
On p71 the urls.py is re-written to take advantage of generic views. after d{4} on each entry there should be a closing bracket - ) - and the same again for p73. I've added my urls into my imports in tests.py as well.
Alas no templates are available on the apress website, so you'll have to make your own to take advantage of the generic views.
So finally we come to a bit more python magic with decorators. If you want to read further about python's implementation of decorators and what they can do, have a read of this article, but I figured I might as well include another silly example that is similar in spirit to the way it is used in PDP.
def magician(fn):
def new_trick():
print "Cut assistant into bits"
assist = fn()
cut = assist.split()[1]
return [bits for bits in cut]
return new_trick
@magician
def assistant():
name = 'lovely assistant'
print name
return name
# Get the assistant - you can see the order in which things are called.
>>> a = assistant()
Cut assistant into bits
lovely assistant
# Print what is returned by the magician
>>> print a
['a', 's', 's', 'i', 's', 't', 'a', 'n', 't']
So that's it until part 5. Enjoy.
12 comments:
Hi Brett,
many thanks. I am following along! When can we expect part 5?
best regards,
St.john
I was away for the weekend but should be able to work through the next chapter in a couple of days.
Brett,
Your notes have been enormously helpful in working through the book.
I had a lot of trouble with the save() method inside the Entry model - pages 59-61 - I was getting obscure error messages about unicode.
To get it to work, I had to manually install python-markdown 1.7 via download from sourceforge.
I think I may have had an old version of python-markdown from my Debian installation of python.
John
Thanks for a VERY helpful information! I almost quit reading the book, but now I'm on my way again.
One comment and question:
> on p69 there is a typo in the regex. The last bit should be (P?[-\w]+)/$'
Is "P?" correct?
Shouldn't be: (?P[-\w]+)/$' ?
I also don't understand what part of the regex, the correction is applied to.
It would helpful if the whole correct regex was shown.
Brett,
Another thing I discovered. The example code on page 69 works if the template files are at the default location (see page 71), but if they are somewhere else it is necessary to use the template_name argument.
I wasn't clear where to do this but in the end I decided it looked best to add it to the definition of entry_info_dict, as follows:
entry_info_dict = {
'queryset': Entry.objects.all(),
'date_field': 'pub_date',
'template_name': 'entry_detail.html',
}
In other examples I have found on the web, the template_name is defined in the urlpatterns - this may be more flexible but to me it looks untidy.
John
Sorry, I've just realised my suggestion above won't work if entry_info_dict is used for a whole series of different views. In that case I guess the template_name has to be inserted into the urlpatterns.
John
Thanks markkus. Yes is should be ?P and also the Blogger swallowed my slug..
Hi Brett, many thanks for this. You solved my problem with the regex typo on page 69. IOU a beer.
:-)
The typo in the regex. The last bit should be (?P[-\w]+)/$' messsssssssssssssssed me around like there was no tomorrow!!! Thanks so much for your post. Save me banging my head into the wall..
also we need to add 'from coltrane.models import Entry' in urls.py
Post a Comment