Home Web-development Web Development with Django Cookbook

Web Development with Django Cookbook

By Aidas Bendoraitis
books-svg-icon Book
Subscription
$10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
Subscription
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
  1. Free Chapter
    Getting Started with Django 1.6
About this book

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:

  1. 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})
    
  2. 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(),
        )
    
  3. 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]
    
  4. 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>
    
  5. 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"),
    )
    
  6. 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.10/ref/contrib/syndication/#feed-class-reference

The other parts of the code are kind of self-explanatory!

Publication date:
October 2014
Publisher
Packt
Pages
294
ISBN
9781783286898

 

Chapter 1. Getting Started with Django 1.6

In this chapter, we will cover the following topics:

  • Working with a virtual environment

  • Creating a project file structure

  • Handling project dependencies with pip

  • Including external dependencies in your project

  • Defining relative paths in the settings

  • Setting up STATIC_URL dynamically for Subversion users

  • Setting up STATIC_URL dynamically for Git users

  • Creating and including local settings

  • Setting UTF-8 as the default encoding for MySQL configuration

  • Setting the Subversion ignore property

  • Creating a Git ignore file

  • Deleting Python-compiled files

  • Importing order in Python files

  • Defining overwritable app settings

 

Introduction


In this chapter, I will show you good practices when starting a new project with Django 1.6 on Python 2.7. Some of the tricks introduced here are the best ways to deal with the project layout, settings, or configuration. However, for some of the tricks, you might find some alternatives online. So, feel free to evaluate and choose the best bits and pieces for yourself while digging deep into the Django world.

I am assuming that you are already familiar with the basics of Django, Subversion or Git version control, MySQL or PostgreSQL databases, and command-line usage. Also, I assume you are probably using a Unix-based operating system such as Mac OS X or Linux. It makes sense to develop with Django on Unix-based platforms because the websites will most likely be published on a Linux Server later, so you can establish routines that work the same while developing as while deploying. If you are working with Django locally on Windows, the routines are similar, but not always exactly the same.

 

Working with a virtual environment


It is very likely that you will develop multiple Django projects on your computer. Some modules, such as Python Image Library (or Pillow) and MySQLdb, can be installed once and shared for all projects. Other modules such as Django itself, third-party Python libraries, and Django apps will need to be kept isolated from each other. Virtualenv is a utility that separates all your Python projects into their own realms. In this recipe, we will show you how to use it.

Getting ready

Before getting into the usage example of virtual environments, let's install pip (the most convenient tool to install and manage Python packages), the shared Python modules Pillow and MySQLdb, and the virtualenv utility using the following commands:

$ sudo easy_install pip
$ sudo pip install Pillow
$ sudo pip install MySQL-python
$ sudo pip install virtualenv

How to do it...

Now, when you have your prerequisites installed, create a directory where all your Django projects will be stored, for example, virtualenvs under your home directory. Perform the following steps after creating the directory:

  1. Go to the newly created directory and create a virtual environment that uses shared system site packages:

    $ cd ~/virtualenvs
    $ mkdir myproject_env
    $ cd myproject_env
    $ virtualenv --system-site-packages .
    New python executable in ./bin/python
    Installing setuptools.............done.
    Installing pip...............done.
    
  2. To use your newly created virtual environment, you need to execute the activation script within your current shell. This can be done with one of the following commands:

    $ source bin/activate
    $ . bin/activate
    
  3. You will see that the prompt of the command-line tool gets a prefix of the project name, such as this:

    (myproject_env)$
    
  4. To get out of the virtual environment, type the following command:

    $ deactivate
    

How it works...

When you create a virtual environment, specific directories (bin, build, include, and lib) are created to store a copy of the Python installation, and some shared Python paths are defined. When the virtual environment is activated, whatever you install with pip or easy_install will be put into and used by the site packages of the virtual environment, and not the global site-packages of your Python installation.

To install Django 1.6 to your virtual environment, type the following command:

(myproject_env)$ pip install Django==1.6

See also

  • The Creating a project file structure recipe

  • The Deploying on Apache with mod_wsgi recipe in Chapter 10, Bells and Whistles

 

Creating a project file structure


A consistent file structure for your projects makes you well organized and more productive. When you have the basic workflow defined, you can get into the business logic quicker and create awesome projects.

Getting ready

If you haven't done this yet, first create the virtualenvs directory where you will keep all your virtual environments (read about this in the Working with a virtual environment recipe), and which can be created under your home directory.

Then, create the directory for your project's environment, for example, myproject_env. Start the virtual environment inside it. This will create the bin, build, include, and lib directories there. I suggest adding the commands directory for local bash scripts related to the project, the db_backups directory for database dumps, and the project directory for your Django project. Also, install Django into your virtual environment.

How to do it...

Follow these steps to create a file structure for your project:

  1. With the virtual environment activated, go to the project directory and start a new Django project, as follows:

    (myproject_env)$ django-admin.py startproject myproject
    
  2. For clearness, we will rename the newly created directory to django-myproject. This is the directory that you should put under version control, so it will have .git, .svn, or similar directories inside.

  3. In the django-myproject directory, create a README.md file to describe your project to new developers. You can also put requirements.txt with the Django version, and you can include other external dependencies (read about this in the Handling project dependencies with pip recipe). Also, this directory will contain your project's Python package named myproject, Django apps (I recommend to have one app called utils for different functionalities shared throughout the project), a locale directory for your project translations if it is multilingual, a Fabric deployment script named fabfile.py, and the externals directory for external dependencies included in this project if you decide not to use requirements.txt.

  4. In your project's Python package, myproject, create the media directory for project uploads, the site_static directory for project-specific static files, the static directory for collected static files, the tmp directory for the upload procedure, and the templates directory for project templates. Also, the myproject directory should contain your project settings, settings.py and local_settings.py, as well as the URL configuration, urls.py.

  5. In your site_static directory, create the site directory as a namespace for site-specific static files. Then, put the static files separated into directories inside it; for instance, scss for Sass files (optional), css for generated minified cascading style sheets, img for styling images and logos, js for JavaScript, and lastly, any third-party module combining all types of files, for example, the rich text editor tinymce. Besides the site directory, the site_static directory might also contain overwritten static directories of third-party apps, for example, cms overwriting static files from Django CMS. To generate the CSS files out of Sass and to minify your JavaScript files, you can use the CodeKit or Prepros applications with a graphical user interface.

  6. Put your templates that are separated by apps into your templates directory. If a template file represents a page (for example, change_item.html or item_list.html), then put it directly in the app's template directory. If the template is included in another template (for example, similar_items.html), put it into the includes subdirectory. Also, your templates directory can contain one directory called utils for globally reusable snippets such as pagination, language chooser, and others.

How it works...

The whole file structure for a complete project inside a virtual environment will look like this:

See also

  • The Handling project dependencies with pip recipe

  • The Including external dependencies in your project recipe

  • The Deploying on Apache with mod_wsgi recipe in Chapter 10, Bells and Whistles

  • The Creating and using the Fabric deployment script recipe in Chapter 10, Bells and Whistles

 

Handling project dependencies with pip


Pip is the most convenient tool to install and manage Python packages. Besides installing packages one by one, it is possible to define a list of packages you want to install and pass it to the tool so that it deals with the list automatically.

Getting ready

Before using this recipe, you need to have pip installed and a virtual environment activated. For more information on how to do this, read the Working with a virtual environment recipe.

How to do it...

Let's go to your Django project that you have under version control and create the requirements file with the following content:

#requirements.txt
Django==1.6
South==0.8.4
django-cms==2.4

Now, you can run the following command to install all required dependencies for your Django project:

(myproject_env)$ pip install -r requirements.txt

How it works...

This command installs all your project dependencies into your virtual environment one after another.

When you have many dependencies in your project, it is good practice to stick to specific versions of the Python modules because you can then be sure that when you deploy your project or give it to a new developer, the integrity doesn't get broken and all the modules function without conflicts.

If you have already installed project requirements with pip manually one by one, you can generate the requirements.txt file using the following command:

(myproject_env)$ pip freeze > requirements.txt

There's more...

If you need to install a Python library directly from a version control system or a local path, you can learn more about pip from the official documentation at http://pip.readthedocs.org/en/latest/reference/pip_install.html.

See also

  • The Working with a virtual environment recipe

  • The Including external dependencies in your project recipe

 

Including external dependencies in your project


Sometimes, it is better to include external dependencies in your project. This ensures that whenever one developer upgrades third-party modules, all the other developers will receive the upgraded version within the next update from the version control system (Git, Subversion, or others).

Also, it is good to have external dependencies included in your project when the libraries are taken from unofficial sources (somewhere other than Python Package Index (PyPI)) or different version control systems.

Getting ready

Start with a virtual environment with a Django project in it.

Tip

Downloading the example code

You can download the example code fles for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the fles e-mailed directly to you.

How to do it...

Execute the following steps one by one:

  1. Create a directory named externals under your Django project.

  2. Then, create the libs and apps directories under it.

    The libs directory is for Python modules that are required by your project, for example, requests, boto, twython, whoosh, and so on. The apps directory is for third-party Django apps, for example, django-haystack, django-cms, django-south, django-storages, and so on.

    Tip

    I highly recommend that you create README.txt files inside the libs and apps directories, where you mention what each module is for, what the used version or revision is, and where it is taken from.

  3. So, the directory structure should look like this:

  4. The next step is to put the external libraries and apps under the Python path so that they are recognized as if they were installed. This can be done by adding the following code in the settings:

    #settings.py
    # -*- coding: UTF-8 -*-
    import os
    import sys
    
    PROJECT_PATH = os.path.abspath(os.path.join(
        os.path.dirname(__file__), ".."))
    
    EXTERNAL_LIBS_PATH = os.path.join(PROJECT_PATH, "externals", "libs")
    EXTERNAL_APPS_PATH = os.path.join(PROJECT_PATH, "externals", "apps")
    sys.path = ["", EXTERNAL_LIBS_PATH, EXTERNAL_APPS_PATH] + sys.path

How it works...

A module is meant to be under the Python path if you can run Python and import the module. One of the ways to put a module under the Python path is to modify the sys.path variable before importing a module that is in an unusual location. The value of sys.path is a list of directories starting with an empty string for the current directory, followed by the directories in the virtual environment, and finally the globally shared directories of the Python installation. You can see the value of sys.path in the Python shell, as follows:

(myproject_env)$ python
>>> import sys
>>> sys.path

When trying to import a module, Python searches for the module in this list and returns the first result found.

So, at first, we define the PROJECT_PATH variable that is the absolute path to one level higher than the settings.py file. Then, we define the variables EXTERNAL_LIBS_PATH and EXTERNAL_APPS_PATH, which are relative to PROJECT_PATH. Lastly, we modify the sys.path property, adding new paths to the beginning of the list. Note that we also add an empty string as the first path to search, which means that the current directory of any module should always be checked first before checking other Python paths.

Tip

This way of including external libraries doesn't work cross-platform with Python packages that have C language bindings, for example, lxml. For such dependencies, I recommend using pip's requirements.txt file that was introduced in the previous recipe.

See also

  • The Creating a project file structure recipe

  • The Handling project dependencies with pip recipe

  • The Defining relative paths in the settings recipe

  • The Using the Django shell recipe in Chapter 10, Bells and Whistles

 

Defining relative paths in the settings


Django requires you to define different filepaths in the settings, such as the root of your media, the root of your static files, the path to templates, the path to translation files, and so on. For each developer of your project, the paths might differ as the virtual environment can be set up anywhere, and the user might be working on Mac OS X, Linux, or Windows. Anyway, there is a way to define these paths relative to your Django project directory.

Getting ready

To start with, open up settings.py.

How to do it...

Modify your path-related settings accordingly, instead of hardcoding paths to your local directories:

#settings.py
# -*- coding: UTF-8 -*-
import os

PROJECT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))

MEDIA_ROOT = os.path.join(PROJECT_PATH, "myproject", "media")

STATIC_ROOT = os.path.join(PROJECT_PATH, "myproject", "static")

STATICFILES_DIRS = (
    os.path.join(PROJECT_PATH, "myproject", "site_static"),
)

TEMPLATE_DIRS = (
    os.path.join(PROJECT_PATH, "myproject", "templates"),
)

LOCALE_PATHS = (
    os.path.join(PROJECT_PATH, "locale"),
)

FILE_UPLOAD_TEMP_DIR = os.path.join(PROJECT_PATH, "myproject", "tmp")

How it works...

At first, we define PROJECT_PATH, which is an absolute path to one level higher than the settings.py file. Then, we set all the paths relative to PROJECT_PATH using the os.path.join function.

See also

  • The Including external dependencies in your project recipe

 

Setting up STATIC_URL dynamically for Subversion users


If you set STATIC_URL to a static value, then each time you update a CSS file, a JavaScript file, or an image, you will need to clear the browser cache to see the changes. There is a trick to work around the clearing of the browser's cache. It is to have the revision number of the version control system shown in STATIC_URL. Whenever the code is updated, the visitor's browser will force the loading of all-new static files.

This recipe shows how to put a revision number into STATIC_URL for Subversion users.

Getting ready

Make sure that your project is under the Subversion version control and you have PROJECT_PATH defined in your settings, as shown in the Defining relative paths in the settings recipe.

Then, create the utils module in your Django project, and also create a file called misc.py there.

How to do it...

The procedure for putting the revision number into the STATIC_URL setting consists of the following two steps:

  1. Insert the following content:

    #utils/misc.py
    # -*- coding: UTF-8 -*-
    import subprocess
    
    def get_media_svn_revision(absolute_path):
        repo_dir = absolute_path
        svn_revision = subprocess.Popen(
            'svn info | grep "Revision" | awk \'{print $2}\'',
            stdout=subprocess.PIPE, stderr=subprocess.PIPE,
            shell=True, cwd=repo_dir, universal_newlines=True)
        rev = svn_revision.communicate()[0].partition('\n')[0]
        return rev
  2. Then, modify the settings.py file and add these lines:

    #settings.py
    # ... somewhere after PROJECT_PATH definition ...
    from utils.misc import get_media_svn_revision
    STATIC_URL = "/static/%s/" % get_media_svn_revision(PROJECT_PATH)

How it works...

The get_media_svn_revision function takes the absolute_path directory as a parameter and calls the svn info shell command in that directory to find out the current revision. We pass PROJECT_PATH to the function because we are sure it is under version control. Then, the revision is parsed, returned, and included in the STATIC_URL definition.

See also

  • The Setting up STATIC_URL dynamically for Git users recipe

  • The Setting the Subversion ignore property recipe

 

Setting up STATIC_URL dynamically for Git users


If you don't want to refresh the browser cache each time you change your CSS and JavaScript files, or while styling images, you need to set STATIC_URL dynamically with a varying path component. With the dynamically changing URL, whenever the code is updated, the visitor's browser will force the loading of all-new uncached static files. In this recipe, we will set a dynamic path for STATIC_URL when you use the Git version control system.

Getting ready

Make sure that your project is under the Git version control and you have PROJECT_PATH defined in your settings, as shown in the Defining relative paths in the settings recipe.

If you haven't done it yet, create the utils module in your Django project, and create a file called misc.py there.

How to do it...

The procedure for putting the Git timestamp into the STATIC_URL setting consists of the following two steps:

  1. Add the following content to the misc.py file placed at utils/:

    #utils/misc.py
    # -*- coding: UTF-8 -*-
    import subprocess
    from datetime import datetime
    
    def get_git_changeset(absolute_path):
        repo_dir = absolute_path
        git_show = subprocess.Popen(
            'git show --pretty=format:%ct --quiet HEAD',
            stdout=subprocess.PIPE, stderr=subprocess.PIPE,
            shell=True, cwd=repo_dir, universal_newlines=True,
        )
        timestamp = git_show.communicate()[0].partition('\n')[0]
        try:
            timestamp = datetime.utcfromtimestamp(int(timestamp))
        except ValueError:
            return ""
        changeset = timestamp.strftime('%Y%m%d%H%M%S')
        return changeset
  2. Then, import the newly created get_git_changeset function in the settings and use it for the STATIC_URL path:

    #settings.py
    # ... somewhere after PROJECT_PATH definition ...
    from utils.misc import get_git_changeset
    STATIC_URL = "/static/%s/" % get_git_changeset(PROJECT_PATH)

How it works...

The get_git_changeset function takes the absolute_path directory as a parameter and calls the git show shell command with the parameters to show the Unix timestamp of the HEAD revision in the directory. As in the previous recipe, we pass PROJECT_PATH to the function because we are sure it is under version control. The timestamp is parsed; converted to a string consisting of year, month, day, hour, minutes, and seconds; returned; and included in the definition of STATIC_URL.

See also

  • The Setting up STATIC_URL dynamically for Subversion users recipe

  • The Creating the Git ignore file recipe

 

Creating and including local settings


You will need to have at least two different instances of your project: the development environment where you create new features and the public website environment in a hosted server. Additionally, there might be different development environments for other developers. Also, you might have a staging environment to test the project in a public-website-like situation.

Getting ready

Most of the settings for different environments will be shared and saved in version control. However, there will be some settings that are specific to the environment of the project instance, for example, database or e-mail settings. We will put them in the local_settings.py file.

How to do it...

Perform the following steps:

  1. At the end of settings.py, add a version of local_settings.py that claims to be in the same directory, as follows:

    #settings.py
    # ... put this at the end of the file ...
    try:
        execfile(os.path.join(os.path.dirname(__file__), "local_settings.py"))
    except IOError:
        pass
  2. Create local_settings.py and put your environment-specific settings there, as follows:

    #local_settings.py
    DATABASES = {
        "default": {
            "ENGINE": "django.db.backends.mysql",
            "NAME": "myproject",
            "USER": "root",
            "PASSWORD": "root",
        }
    }
    EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
    INSTALLED_APPS += (
        "debug_toolbar",
    )

How it works...

As you can see, the local settings are not normally imported, but rather they are included and executed in the settings.py file itself. This allows you not only to create or overwrite the existing settings, but also to adjust the tuples or lists from the settings.py file; for example, we add debug_toolbar to INSTALLED_APPS here to be able to debug the SQL queries, template context variables, and so on.

See also

  • The Creating a project file structure recipe

  • The Toggling Debug Toolbar recipe in Chapter 10, Bells and Whistles

 

Setting UTF-8 as the default encoding for MySQL configuration


MySQL is the most popular open source database. In this recipe, I will tell you how to set UTF-8 as the default encoding for it. Note that if you don't set this encoding in the database configuration, you might get into a situation where LATIN1 is used by default with your UTF-8-encoded data. This will lead to database errors whenever symbols such as "€" are used. Also, this recipe will save you from the difficulties of converting database data from LATIN1 to UTF-8, especially when you have some tables encoded in LATIN1 and others in UTF-8.

Getting ready

Make sure that the MySQL database management system and the MySQLdb Python module are installed and you are using the MySQL engine in your project's settings.

How to do it...

Open the MySQL configuration file (/etc/mysql/my.cnf) in your favorite editor, and ensure that the following settings are set in the sections [client], [mysql], and [mysqld]:

#/etc/mysql/my.cnf
[client]
default-character-set = utf8

[mysql]
default-character-set = utf8

[mysqld]
collation-server = utf8_unicode_ci
init-connect = 'SET NAMES utf8'
character-set-server = utf8

If any of the sections don't exist, create them in the file. Then, restart MySQL in your command-line tool, as follows:

/etc/init.d/mysql restart

How it works...

Now, whenever you create a new MySQL database, the databases and all their tables will be set in the UTF-8 encoding by default.

Don't forget to set this in all computers where your project is developed or published.

 

Setting the Subversion ignore property


If you are using Subversion for version control, you will need to keep most of the projects in the repository, but some files and directories should stay only locally and not be tracked.

Getting ready

Make sure that your Django project is under the Subversion version control.

How to do it...

Open your command-line tool and set your default editor as nano, vi, vim, or any other that you prefer, as follows:

$ export EDITOR=nano

Tip

If you don't have a preference, I recommend using nano, which is very intuitive and a simple text editor for the terminal.

Then, go to your project directory and type the following command:

$ svn propedit svn:ignore .

This will open a temporary file in the editor, where you need to put the following file and directory patterns for Subversion to ignore:

*.pyc
local_settings.py
static
media
tmp

Save the file and exit the editor. For every other Python package in your project, you will need to ignore the *.pyc files. Just go to a directory and type the following command:

$ svn propedit svn:ignore .

Then, put this in the temporary file, save it, and close the editor:

*.pyc

How it works...

In Subversion, you need to define ignore properties for each directory of your project. Mainly, we don't want to track the Python-compiled files, for instance, *.pyc. We also want to ignore local_settings.py that is specific for each developer, static that replicates collected static files from different apps, media that contains uploaded files and will be changing together with the database, and tmp that is temporarily used for file uploads.

See also

  • The Creating and including local settings recipe about including local_settings.py into your settings.py file

  • The Creating the Git ignore file recipe

 

Creating the Git ignore file


If you are using Git—the most popular distributed version control system—ignoring some files and folders from version control is much easier than with Subversion.

Getting ready

Make sure that your Django project is under Git version control.

How to do it...

Using your favorite text editor, create a .gitignore file at the root of your Django project and put these files and directories there:

#.gitignore
*.pyc
/myproject/local_settings.py
/myproject/static/
/myproject/tmp/
/myproject/media/

How it works...

The .gitignore file specifies the paths that should intentionally be untracked by the Git version control system. The .gitignore file we created in this recipe will ignore the Python-compiled files, local settings, collected static files, temporary directory for uploads, and media directory with the uploaded files.

See also

  • The Setting the Subversion ignore property recipe

 

Deleting Python-compiled files


When you run your project for the first time, Python compiles all your *.py code to bytecode-compiled files, *.pyc, which are used later for execution.

Normally, when you change the *.py files, *.pyc are recompiled, but sometimes when switching branches or moving directories, you need to clean up the compiled files manually.

Getting ready

Use your favorite editor and edit, or create, a .bash_profile file in your home directory.

How to do it...

Add this alias at the end of .bash_profile:

#~/.bash_profile
alias delpyc="find . -name \"*.pyc\" -delete"

Now, to clean up the Python-compiled files, go to your project directory and type this command in the command line:

$ delpyc

How it works...

At first, we create a Unix alias that searches for the *.pyc files and deletes them in the current directory and its children. The .bash_profile file is executed when you start a new session in the command-line tool.

See also

  • The Setting the Subversion ignore property recipe

  • The Creating the Git ignore file recipe

 

Importing an order in Python files


When you create Python modules, it is good practice to stay consistent with the structure within the files. This makes it easier to read code for other developers and for yourself. This recipe will show you how to structure your imports.

Getting ready

Create a virtual environment and a Django project in it.

How to do it...

Use the following structure in any Python file you create. Just after the first line that defines UTF-8 as the default Python file encoding, put imports categorized into sections:

# -*- coding: UTF-8 -*-
# System libraries
import os
import re
from datetime import datetime

# Third-party libraries
import boto
from PIL import Image

# Django modules
from django.db import models
from django.conf import settings

# Django apps
from cms.models import Page

# Current-app modules
import app_settings

How it works...

We have five main categories for the imports, as follows:

  • System libraries for packages within the default installation of Python

  • Third-party libraries for additionally installed Python packages

  • Django modules for different modules from the Django framework

  • Django apps for third-party and local apps

  • Current-app modules for relative imports from the current app

There's more...

When coding in Python and Django, use the official style guide for Python code, PEP 8. You can find it at http://legacy.python.org/dev/peps/pep-0008/.

See also

  • The Handling project dependencies with pip recipe

  • The Including external dependencies in your project recipe

 

Defining overwritable app settings


This recipe will show you how to define settings for your app that can then be overwritten in your project's settings.py or local_settings.py file. This is especially useful for reusable apps.

Getting ready

Create your Django app either manually or by using this command:

(myproject_env)$ django-admin.py startapp myapp1

How to do it...

If you have just one or two settings, you can use the following pattern in your models.py file. If the settings are extensive, and you want to have them better organized, create an app_settings.py file in the app and put the settings in the following way:

#models.py or app_settings.py
# -*- coding: UTF-8 -*-
from django.conf import settings
from django.utils.translation import ugettext_lazy as _

SETTING1 = getattr(settings, "MYAPP1_SETTING1", u"default value")
MEANING_OF_LIFE = getattr(settings, "MYAPP1_MEANING_OF_LIFE", 42)
STATUS_CHOICES = getattr(settings, "MYAPP1_STATUS_CHOICES", (
    ('draft', _("Draft")),
    ('published', _("Published")),
    ('not_listed', _("Not Listed")),
))

Then, you can use the app settings in models.py in the following way:

#models.py
# -*- coding: UTF-8 -*-
from django.db import models
from django.utils.translation import ugettext_lazy as _

from app_settings import STATUS_CHOICES

class NewsArticle(models.Model):
    # ...
    status = models.CharField(_("Status"),
        max_length=20, choices=STATUS_CHOICES
    )

If you want to overwrite the STATUS_CHOICES setting for just one project, you simply open settings.py and add this:

#settings.py
# ...
from django.utils.translation import ugettext_lazy as _
MYAPP1_STATUS_CHOICES = (
    ("imported", _("Imported")),
    ("draft", _("Draft")),
    ("published", _("Published")),
    ("not_listed", _("Not Listed")),
    ("expired", _("Expired")),
)

How it works...

The Python function, getattr(object, attribute_name[, default_value]), tries to get the attribute_name attribute from object, and returns default_value if it is not found. In this case, different settings are tried to be taken from the Django project settings module, and if they are not found, the default values are assigned.

About the Author
  • Aidas Bendoraitis

    Aidas Bendoraitis has been professionally building websites for the past 18 years. For the last 14 years, he has been working at a design company, studio 38 pure communication, in Berlin. Together with a small dedicated team, he has mostly used Django in the backend and jQuery in the frontend to create cultural and touristic web platforms.Among different side projects, he is bootstrapping a SaaS business with strategic prioritizer 1st things 1st.

    Browse publications by this author
Latest Reviews (2 reviews total)
I develop on Linux and often find that authors don't cover the install reqs completely.
The price is very good and can you go wrong with education at this price? Of course not. Thanks!
Web Development with Django Cookbook
Unlock this book and the full library FREE for 7 days
Start now