• Aucun résultat trouvé

Handling Live Entries

Dans le document Projects Django (Page 113-117)

Before you move on to the last part of the weblog—templating and comments, which I’ll cover in the next chapter—let’s solve one more missing feature.

You’ll recall that when you set up the Entrymodel, you gave it a field called status, which allows entries to be marked as Live,Draft, or Hidden. At the moment, none of your views are taking that into account. If you add an entry with a status other than Live, you’ll notice that it still shows up in all of the archive and detail views.

You’ve already seen that you can use the filter()method to get only the objects that match certain specific criteria. At first, that seems like an easy way to handle this. Anywhere you’re using this:

Entry.objects.all() you could just replace it with this:

Entry.objects.filter(status=Entry.LIVE_STATUS)

Remember that you defined named constants for the different statusvalues to make these kinds of queries easier. But this is going to involve an awful lot of typing. You’ll need to remember to type that extra query argument anywhere you’re querying for entries. It would be much nicer if you could have a separate way of querying entries that only returns objects with

the statusfield set to Live, maybe something like Entry.live.all()instead of Entry.objects.

all(). This is actually pretty easy to do, but it requires the introduction of one more major fea-ture of Django’s model system: managers.

Up until now, I’ve been glossing over how Django actually does database queries. I’ve just been discussing things like Entry.objects.all()or FlatPage.objects.filter()without really talking about that special attribute called objectsor where it comes from.

The objectsattribute is an instance of a special class (django.db.models.Manager), which is meant to be “attached” to a particular model class, and which knows how to perform all sorts of database queries. In addition to the methods you’ve already seen—all()and filter()—it has a large number of other methods that can return single specific objects, return lists of objects, return other data structures corresponding to data stored by a model, change the ordering used to return results, and handle a variety of other useful tasks. Full documentation of the database API and all of its methods and options is available online at www.djangoproject.com/documentation/db-api/.

If you don’t specify a manager for your model, Django adds one and calls it objects(this happens automatically for any class that subclasses django.db.models.Model). However, you’re free to attach a manager with any name you like, and if you do, Django won’t bother with the automatic default objectsmanager. For example, you could define a model like so:

class MyModel(models.Model):

name = models.CharField(max_length=50) object_fetcher = models.Manager()

Then, instead of using, say,MyModel.objects.all(), you would use MyModel.object_

fetcher.all(). All of the standard querying methods will be there, just in an attribute with the name you’ve specified.

The most important thing about managers, however, is that you can easily define your own manager classes and give them customized behavior by writing a subclass of django.db.

models.Managerand overriding the methods you want to customize. In this case you want to write a manager that, when attached to the Entrymodel, will only return entries whose status is Live. You can do this by writing a subclass of Managerand overriding one method, get_query_set(), which returns the initial QuerySetobject that all(),filter(), and all the other querying methods will use. Doing this is surprisingly easy:

class LiveEntryManager(models.Manager):

def get_query_set(self):

return super(LiveEntryManager, self).get_query_set().filter( status=self.model.LIVE_STATUS)

The only tricky bit here is that you’re using self.model.LIVE_STATUSas the value to filter on. Every Managerthat’s been attached to a model can access that model class through the attribute self.model.

Place the preceding code in the weblog application’s models.pyfile, somewhere above the definition of the Entrymodel. Then add the following lines inside the Entrymodel:

live = LiveEntryManager() objects = models.Manager()

This gives the Entrymodel two managers. One is called objectsand is just the standard manager every model normally gets. The other is an instance of the LiveEntryManager, which means you can now write

Entry.live.all()

and it will do precisely what you want it to do. Note that you have to define objectsmanually.

When a model has a custom manager, Django doesn’t automatically set up the objects man-ager for you.

Now you can simply perform a search and replace on the weblog code, changing any use of Entry.objectsto Entry.live, and that will take care of any situations where you’re querying for entries (only one so far, but if you had gone much further it could easily have been more).

There are two other places, though, where you’ll need to worry about filtering for only live entries—when you retrieve entries for a specific category or tag. For categories, you can solve this fairly easily by adding a method on the Categorymodel:

def live_entry_set(self):

from coltrane.models import Entry

return self.entry_set.filter(status=Entry.LIVE_STATUS)

And now, anywhere you used the entry_setattribute of a Category, you can simply replace it with a call to live_entry_set(). So, for example, the category_detailview will now look like this:

def category_detail(request, slug):

category = get_object_or_404(Category, slug=slug)

return render_to_response('coltrane/category_detail.html',

{ 'object_list': category.live_entry_set() }) With tags it’s a bit trickier, but you can still make it work. Remember that the argument the tagged_object_listview receives is called queryset_or_model. This means you can pass it either a model class, like Link, or a QuerySet. So where you're using the tagged_object_list view with the Entrymodel as an argument, change it to use Entry.live.all()instead.

Looking Ahead

The weblog application is almost complete now. There are only a couple of features left to add, and for them you’ll be using applications bundled with Django plus a few customizations. I’ll cover those in Chapter 7, but in the next chapter you’ll take a much more detailed look at Django’s template system, writing templates for the blog, and even writing a couple of custom template tags.

If you’d like to pause for a little while and play with the weblog application before moving on to Chapter 6, feel free to do so. Even without the comment system and template techniques you’ll cover in the next chapter, this weblog application is already a pretty solid piece of soft-ware and offers a significant subset of the functionality of popular off-the-shelf weblog systems like Wordpress (but with significantly less code).

Dans le document Projects Django (Page 113-117)