Book Description
Django is easy to learn and solves all types of web development problems and questions, providing Python developers an easy solution to web-application development. With a wealth of third-party modules available, you'll be able to create a highly customizable web application with this powerful framework.
Web Development with Django Cookbook will guide you through all web development processes with the Django framework. You will get started with the virtual environment and configuration of the project, and then you will learn how to define a database structure with reusable components. Find out how to tweak the administration to make the website editors happy. This book deals with some important third-party modules necessary for fully equipped web development.
Read an extract of the book
Creating Filterable RSS Feeds
Django comes with a syndication feed framework that allows you to create RSS and Atom feeds easily. RSS and Atom feeds are XML documents with specific semantics. They can be subscribed in an RSS reader such as Feedly, or they can be aggregated into other websites, mobile applications, or desktop applications. In this recipe, we will create BulletinFeed, which provides a bulletin board with images. Moreover, the results will be filterable by URL query parameters.
Getting ready
Create a new bulletin_board app and put it under INSTALLED_APPS in the settings.
How to do itβ¦
We will create a Bulletin model and an RSS feed for it that can be filtered by type or category, so that the visitor can subscribe only to bulletins that are, for example, offering used books:
- In the models.py file of that app, add the models Category and Bulletin with a foreign key relationship between them:
#bulletin_board/models.py # -*- coding: UTF-8 -*- from django.db import models from django.utils.translation import ugettext_lazy as _ from django.core.urlresolvers import reverse from utils.models import CreationModificationDateMixin from utils.models import UrlMixin TYPE_CHOICES = ( ("searching", _("Searching")), ("offering", _("Offering")), ) class Category(models.Model): title = models.CharField(_("Title"), max_length=200) def __unicode__(self): return self.title class Meta: verbose_name = _("Category") verbose_name_plural = _("Categories") class Bulletin(CreationModificationDateMixin, UrlMixin): bulletin_type = models.CharField(_("Type"), max_length=20, choices=TYPE_CHOICES) category = models.ForeignKey(Category, verbose_name=_("Category")) title = models.CharField(_("Title"), max_length=255) description = models.TextField(_("Description"), max_length=300) contact_person = models.CharField(_("Contact person"), max_length=255) phone = models.CharField(_("Phone"), max_length=200, blank=True) email = models.CharField(_("Email"), max_length=254, blank=True) image = models.ImageField(_("Image"), max_length=255, upload_to="bulletin_board/", blank=True) class Meta: verbose_name = _("Bulletin") verbose_name_plural = _("Bulletins") ordering = ("-created",) def __unicode__(self): return self.title def get_url_path(self): return reverse("bulletin_detail", kwargs={"pk": self.pk})
- Then, create BulletinFilterForm that allows the visitor to filter bulletins by type and by category, as follows:
#bulletin_board/forms.py # -*- coding: UTF-8 -*- from django import forms from django.utils.translation import ugettext_lazy as _ from models import Category, TYPE_CHOICES class BulletinFilterForm(forms.Form): bulletin_type = forms.ChoiceField( label=_("Bulletin Type"), required=False, choices=(("", "---------"),) + TYPE_CHOICES, ) category = forms.ModelChoiceField( label=_("Category"), required=False, queryset=Category.objects.all(), )
- Add a feeds.py file with the BulletinFeed class inside, as follows:
#bulletin_board/feeds.py # -*- coding: UTF-8 -*- from django.contrib.syndication.views import Feed from django.core.urlresolvers import reverse from models import Bulletin, TYPE_CHOICES from forms import BulletinFilterForm class BulletinFeed(Feed): description_template = "bulletin_board/feeds/bulletin_description.html" def get_object(self, request, *args, **kwargs): form = BulletinFilterForm(data=request.REQUEST) obj = {} if form.is_valid(): obj = { "bulletin_type": form.cleaned_data["bulletin_type"], "category": form.cleaned_data["category"], "query_string": request.META["QUERY_STRING"], } return obj def title(self, obj): t = u"My Website - Bulletin Board" # add type "Searching" or "Offering" if obj.get("bulletin_type", False): tp = obj["bulletin_type"] t += u" - %s" % dict(TYPE_CHOICES)[tp] # add category if obj.get("category", False): t += u" - %s" % obj["category"].title return t def link(self, obj): if obj.get("query_string", False): return reverse("bulletin_list") + "?" + obj["query_string"] return reverse("bulletin_list") def feed_url(self, obj): if obj.get("query_string", False): return reverse("bulletin_rss") + "?" + obj["query_string"] return reverse("bulletin_rss") def item_pubdate(self, item): return item.created def items(self, obj): qs = Bulletin.objects.order_by("-created") if obj.get("bulletin_type", False): qs = qs.filter( bulletin_type=obj["bulletin_type"], ).distinct() if obj.get("category", False): qs = qs.filter( category=obj["category"], ).distinct() return qs[:30]
- Create a template for the bulletin description in the feed as follows:
{#templates/bulletin_board/feeds/bulletin_description.html#} {% if obj.image %} <p><a href="{{ obj.get_url }}"><img src="http://{{ request.META.HTTP_HOST }}{{ obj.image.url }}" alt="" /></a></p> {% endif %} <p>{{ obj.description }}</p>
- Create a URL configuration for the bulletin board app and include it in the root URL configuration, as follows:
#templates/bulletin_board/urls.py # -*- coding: UTF-8 -*- from django.conf.urls import * from feeds import BulletinFeed urlpatterns = patterns("bulletin_board.views", url(r"^$", "bulletin_list", name="bulletin_list"), url(r"^(?P<bulletin_id>[0-9]+)/$", "bulletin_detail", name="bulletin_detail"), url(r"^rss/$", BulletinFeed(), name="bulletin_rss"), )
- You will also need the views and templates for the filterable list and details of the bulletins. In the Bulletin list page template, add this link:
<a href="{% url "bulletin_rss" %}?{{ request.META.QUERY_STRING }}">RSS Feed</a>
How it worksβ¦
So, if you have some data in the database and you open http://127.0.0.1:8000/bulletin-board/rss/?bulletin_type=offering&category=4 in your browser, you will get an RSS feed of bulletins with the type Offering and category ID 4.
The BulletinFeed class has the get_objects method that takes the current HttpRequest and defines the obj dictionary used in other methods of the same class.
The obj dictionary contains the bulletin type, category, and current query string.
The title method returns the title of the feed. It can either be generic or related to the selected bulletin type or category. The link method returns the link to the original bulletin list with the filtering done. The feed_url method returns the URL of the current feed. The items method does the filtering itself and returns a filtered QuerySet of bulletins. And finally, the item_pubdate method returns the creation date of the bulletin.
To see all the available methods and properties of the Feed class that we are extending, refer to the following documentation: https://docs.djangoproject.com/en/1.6/ref/contrib/syndication/#feed-class-reference
The other parts of the code are kind of self-explanatory!