Contributing to Django
This document describes Django version 0.96. For current documentation, go here.
If you think working with Django is fun, wait until you start working on it. We’re passionate about helping Django users make the jump to contributing members of the community, so there are many ways you can help Django’s development:
- Blog about Django. We syndicate all the Django blogs we know about on the community page; contact jacob@jacobian.org if you’ve got a blog you’d like to see on that page.
- Report bugs and request features in our ticket tracker. Please read Reporting bugs, below, for the details on how we like our bug reports served up.
- Submit patches for new and/or fixed behavior. Please read Submitting patches, below, for details on how to submit a patch.
- Join the django-developers mailing list and share your ideas for how to improve Django. We’re always open to suggestions, although we’re likely to be skeptical of large-scale suggestions without some code to back it up.
- Triage patches that have been submitted by other users. Please read Ticket triage below, for details on the triage process.
That’s all you need to know if you’d like to join the Django development community. The rest of this document describes the details of how our community works and how it handles bugs, mailing lists, and all the other minutiae of Django development.
Reporting bugs
Well-written bug reports are incredibly helpful. However, there’s a certain amount of overhead involved in working with any bug tracking system, so your help in keeping our ticket tracker as useful as possible is appreciated. In particular:
- Do read the FAQ to see if your issue might be a well-known question.
- Do search the tracker to see if your issue has already been filed.
- Do ask on django-users first if you’re not sure if what you’re seeing is a bug.
- Do write complete, reproducible, specific bug reports. Include as much information as you possibly can, complete with code snippets, test cases, etc. This means including a clear, concise description of the problem, and a clear set of instructions for replicating the problem. A minimal example that illustrates the bug in a nice small test case is the best possible bug report.
- Don’t use the ticket system to ask support questions. Use the django-users list, or the #django IRC channel for that.
- Don’t use the ticket system to make large-scale feature requests. We like to discuss any big changes to Django’s core on the django-developers list before actually working on them.
- Don’t reopen issues that have been marked “wontfix”. This mark means that the decision has been made that we can’t or won’t fix this particular issue. If you’re not sure why, please ask on django-developers.
- Don’t use the ticket tracker for lengthy discussions, because they’re likely to get lost. If a particular ticket is controversial, please move discussion to django-developers.
Reporting security issues
Report security issues to security@djangoproject.com. This is a private list only open to long-time, highly trusted Django developers, and its archives are not publicly readable.
In the event of a confirmed vulnerability in Django itself, we will take the following actions:
- Acknowledge to the reporter that we’ve received the report and that a fix is forthcoming. We’ll give a rough timeline and ask the reporter to keep the issue confidential until we announce it.
- Halt all other development as long as is needed to develop a fix, including patches against the current and two previous releases.
- Determine a go-public date for announcing the vulnerability and the fix. To try to mitigate a possible “arms race” between those applying the patch and those trying to exploit the hole, we will not announce security problems immediately.
- Pre-notify everyone we know to be running the affected version(s) of Django. We will send these notifications through private e-mail which will include documentation of the vulnerability, links to the relevant patch(es), and a request to keep the vulnerability confidential until the official go-public date.
- Publicly announce the vulnerability and the fix on the pre-determined go-public date. This will probably mean a new release of Django, but in some cases it may simply be patches against current releases.
Submitting patches
We’re always grateful for patches to Django’s code. Indeed, bug reports with associated patches will get fixed far more quickly than those without patches.
Patch style
- Make sure your code matches our coding style.
- Submit patches in the format returned by the svn diff command. An exception is for code changes that are described more clearly in plain English than in code. Indentation is the most common example; it’s hard to read patches when the only difference in code is that it’s indented.
- Attach patches to a ticket in the ticket tracker, using the “attach file” button. Please don’t put the patch in the ticket description or comment unless it’s a single line patch.
- Name the patch file with a .diff extension; this will let the ticket tracker apply correct syntax highlighting, which is quite helpful.
- Check the “Has patch” box on the ticket details. This will make it obvious that the ticket includes a patch, and it will add the ticket to the list of tickets with patches.
- The code required to fix a problem or add a feature is an essential part of a patch, but it is not the only part. A good patch should also include a regression test to validate the behavior that has been fixed (and prevent the problem from arising again).
- If the code associated with a patch adds a new feature, or modifies behavior of an existing feature, the patch should also contain documentation.
Non-trivial patches
A “non-trivial” patch is one that is more than a simple bug fix. It’s a patch that introduces Django functionality and makes some sort of design decision.
If you provide a non-trivial patch, include evidence that alternatives have been discussed on django-developers. If you’re not sure whether your patch should be considered non-trivial, just ask.
Ticket triage
Unfortunately, not all bug reports in the ticket tracker provide all the required details. A number of tickets have patches, but those patches don’t meet all the requirements of a good patch.
One way to help out is to triage bugs that have been reported by other users. A couple of dedicated volunteers work on this regularly, but more help is always appreciated.
Most of the workflow is based around the concept of a ticket’s “triage stage”. This stage describes where in its lifetime a given ticket is at any time. Along with a handful of flags, this field easily tells us what and who each ticket is waiting on.
Since a picture is worth a thousand words, let’s start there:
We’ve got two roles here:
- Core developers: people with commit access who make the decisions and write the bulk of the code.
- Ticket triagers: community members who keep track of tickets, making sure the tickets are always categorized correctly.
Second, note the four triage stages:
- A ticket starts as “Unreviewed”, meaning that a triager has yet to examine the ticket and move it along.
- “Design decision needed” means “this concept requires a design decision,” which should be discussed either in the ticket comments or on django-developers.
- Once a ticket is ruled to be approved for fixing, it’s moved into the “Accepted” stage. This stage is where all the real work gets done.
- If a ticket has an associated patch (see below), a triager will review the patch. If the patch is complete, it’ll be marked as “ready for checkin” so that a core developer knows to review and check in the patches.
The second part of this workflow involves a set of flags the describe what the ticket has or needs in order to be “ready for checkin”:
- “Has patch”
- This means the ticket has an associated patch. These will be reviewed to see if the patch is “good”.
- “Needs documentation”
- This flag is used for tickets with patches that need associated documentation. Complete documentation of features is a prerequisite before we can check a fix into the codebase.
- “Needs tests”
- This flags the patch as needing associated unit tests. Again, this is a required part of a valid patch.
- “Patch needs improvement”
- This flag means that although the ticket has a patch, it’s not quite ready for checkin. This could mean the patch no longer applies cleanly, or that the code doesn’t live up to our standards.
A ticket can be resolved in a number of ways:
- “fixed”
- Used by one of the core developers once a patch has been rolled into Django and the issue is fixed.
- “invalid”
- Used if the ticket is found to be incorrect or a user error.
- “wontfix”
- Used when a core developer decides that this request is not appropriate for consideration in Django. This is usually chosen after discussion in the django-developers mailing list, and you should feel free to join in when it’s something you care about.
- “duplicate”
- Used when another ticket covers the same issue. By closing duplicate tickets, we keep all the discussion in one place, which helps everyone.
- “worksforme”
- Used when the triage team is unable to replicate the original bug.
If you believe that the ticket was closed in error — because you’re still having the issue, or it’s popped up somewhere else, or the triagers have — made a mistake, please reopen the ticket and tell us why. Please do not reopen tickets that have been marked as “wontfix” by core developers.
Submitting and maintaining translations
Various parts of Django, such as the admin site and validator error messages, are internationalized. This means they display different text depending on a user’s language setting.
These translations are contributed by Django users worldwide. If you find an incorrect translation, or if you’d like to add a language that isn’t yet translated, here’s what to do:
- Join the Django i18n mailing list and introduce yourself.
- Create and submit translations using the methods described in the i18n documentation.
Coding style
Please follow these coding standards when writing code for inclusion in Django:
Unless otherwise specified, follow PEP 8.
Use four spaces for indentation.
Use underscores, not camelCase, for variable, function and method names (i.e. poll.get_unique_voters(), not poll.getUniqueVoters).
Use InitialCaps for class names (or for factory functions that return classes).
Mark all strings for internationalization; see the i18n documentation for details.
In Django template code, put one (and only one) space between the curly brackets and the tag contents.
Do this:
{{ foo }}Don’t do this:
{{foo}}In Django views, the first parameter in a view function should be called request.
Do this:
def my_view(request, foo): # ...Don’t do this:
def my_view(req, foo): # ...Please don’t put your name in the code you contribute. Our policy is to keep contributors’ names in the AUTHORS file distributed with Django — not scattered throughout the codebase itself. Feel free to include a change to the AUTHORS file in your patch if you make more than a single trivial change.
Committing code
Please follow these guidelines when committing code to Django’s Subversion repository:
For any medium-to-big changes, where “medium-to-big” is according to your judgment, please bring things up on the django-developers mailing list before making the change.
If you bring something up on django-developers and nobody responds, please don’t take that to mean your idea is great and should be implemented immediately because nobody contested it. Django’s lead developers don’t have a lot of time to read mailing-list discussions immediately, so you may have to wait a couple of days before getting a response.
Write detailed commit messages in the past tense, not present tense.
- Good: “Fixed Unicode bug in RSS API.”
- Bad: “Fixes Unicode bug in RSS API.”
- Bad: “Fixing Unicode bug in RSS API.”
For commits to a branch, prefix the commit message with the branch name. For example: “magic-removal: Added support for mind reading.”
Limit commits to the most granular change that makes sense. This means, use frequent small commits rather than infrequent large commits. For example, if implementing feature X requires a small change to library Y, first commit the change to library Y, then commit feature X in a separate commit. This goes a long way in helping all core Django developers follow your changes.
If your commit closes a ticket in the Django ticket tracker, begin your commit message with the text “Fixed #abc”, where “abc” is the number of the ticket your commit fixes. Example: “Fixed #123 — Added support for foo”. We’ve rigged Subversion and Trac so that any commit message in that format will automatically close the referenced ticket and post a comment to it with the full commit message.
If your commit closes a ticket and is in a branch, use the branch name first, then the “Fixed #abc.” For example: “magic-removal: Fixed #123 — Added whizbang feature.”
For the curious: We’re using a Trac post-commit hook for this.
If your commit references a ticket in the Django ticket tracker but does not close the ticket, include the phrase “Refs #abc”, where “abc” is the number of the ticket your commit references. We’ve rigged Subversion and Trac so that any commit message in that format will automatically post a comment to the appropriate ticket.
Unit tests
Django comes with a test suite of its own, in the tests directory of the Django tarball. It’s our policy to make sure all tests pass at all times.
The tests cover:
- Models and the database API (tests/modeltests/).
- The cache system (tests/regressiontests/cache.py).
- The django.utils.dateformat module (tests/regressiontests/dateformat/).
- Database typecasts (tests/regressiontests/db_typecasts/).
- The template system (tests/regressiontests/templates/ and tests/regressiontests/defaultfilters/).
- QueryDict objects (tests/regressiontests/httpwrappers/).
- Markup template tags (tests/regressiontests/markup/).
We appreciate any and all contributions to the test suite!
The Django tests all use the testing infrastructure that ships with Django for testing applications. See Testing Django applications for an explanation of how to write new tests.
Running the unit tests
To run the tests, cd to the tests/ directory and type:
./runtests.py --settings=path.to.django.settings
Yes, the unit tests need a settings module, but only for database connection info — the DATABASE_ENGINE, DATABASE_USER and DATABASE_PASSWORD. You will also need a ROOT_URLCONF setting (its value is ignored; it just needs to be present) and a SITE_ID setting (any integer value will do) in order for all the tests to pass.
The unit tests will not touch your existing databases; they create a new database, called django_test_db, which is deleted when the tests are finished. This means your user account needs permission to execute CREATE DATABASE.
Requesting features
We’re always trying to make Django better, and your feature requests are a key part of that. Here are some tips on how to most effectively make a request:
- Request the feature on django-developers, not in the ticket tracker; it’ll get read more closely if it’s on the mailing list.
- Describe clearly and concisely what the missing feature is and how you’d like to see it implemented. Include example code (non-functional is OK) if possible.
- Explain why you’d like the feature. In some cases this is obvious, but since Django is designed to help real developers get real work done, you’ll need to explain it, if it isn’t obvious why the feature would be useful.
As with most open-source projects, code talks. If you are willing to write the code for the feature yourself or if (even better) you’ve already written it, it’s much more likely to be accepted. If it’s a large feature that might need multiple developers we’re always happy to give you an experimental branch in our repository; see below.
Branch policy
In general, most development is confined to the trunk, and the trunk is kept stable. People should be able to run production sites against the trunk at any time.
Thus, large architectural changes — that is, changes too large to be encapsulated in a single patch, or changes that need multiple eyes on them — will have dedicated branches. See, for example, the i18n branch. If you have a change of this nature that you’d like to work on, ask on django-developers for a branch to be created for you. We’ll create a branch for pretty much any kind of experimenting you’d like to do.
We will only branch entire copies of the Django tree, even if work is only happening on part of that tree. This makes it painless to switch to a branch.
Developers working on a branch should periodically merge changes from the trunk into the branch. Please merge at least once a week. Every time you merge from the trunk, note the merge and revision numbers in the commit message.
Once the branch is stable and ready to be merged into the trunk, alert django-developers.
After a branch has been merged, it should be considered “dead”; write access to it will be disabled, and old branches will be periodically “trimmed.” To keep our SVN wrangling to a minimum, we won’t be merging from a given branch into the trunk more than once.
Using branches
To use a branch, you’ll need to do two things:
- Get the branch’s code through Subversion.
- Point your Python site-packages directory at the branch’s version of the django package rather than the version you already have installed.
Getting the code from Subversion
To get the latest version of a branch’s code, check it out using Subversion:
svn co http://code.djangoproject.com/svn/django/branches/<branch>/
…where <branch> is the branch’s name. See the list of branch names.
Alternatively, you can automatically convert an existing directory of the Django source code as long as you’ve checked it out via Subversion. To do the conversion, execute this command from within your django directory:
svn switch http://code.djangoproject.com/svn/django/branches/<branch>/
The advantage of using svn switch instead of svn co is that the switch command retains any changes you might have made to your local copy of the code. It attempts to merge those changes into the “switched” code. The disadvantage is that it may cause conflicts with your local changes if the “switched” code has altered the same lines of code.
(Note that if you use svn switch, you don’t need to point Python at the new version, as explained in the next section.)
Pointing Python at the new Django version
Once you’ve retrieved the branch’s code, you’ll need to change your Python site-packages directory so that it points to the branch version of the django directory. (The site-packages directory is somewhere such as /usr/lib/python2.4/site-packages or /usr/local/lib/python2.4/site-packages or C:\Python\site-packages.)
The simplest way to do this is by renaming the old django directory to django.OLD and moving the trunk version of the code into the directory and calling it django.
Alternatively, you can use a symlink called django that points to the location of the branch’s django package. If you want to switch back, just change the symlink to point to the old code.
A third option is to use a path file (<something>.pth) which should work on all systems (including Windows, which doesn’t have symlinks available). First, make sure there are no files, directories or symlinks named django in your site-packages directory. Then create a text file named django.pth and save it to your site-packages directory. That file should contain a path to your copy of Django on a single line and optional comments. Here is an example that points to multiple branches. Just uncomment the line for the branch you want to use (‘Trunk’ in this example) and make sure all other lines are commented:
# Trunk is a svn checkout of: # http://code.djangoproject.com/svn/django/trunk/ # /path/to/trunk # <branch> is a svn checkout of: # http://code.djangoproject.com/svn/django/branches/<branch>/ # #/path/to/<branch> # On windows a path may look like this: # C:/path/to/<branch>
If you’re using Django 0.95 or earlier and installed it using python setup.py install, you’ll have a directory called something like Django-0.95-py2.4.egg instead of django. In this case, edit the file setuptools.pth and remove the line that references the Django .egg file. Then copy the branch’s version of the django directory into site-packages.
Official releases
Django’s release numbering works as follows:
Versions are numbered in the form A.B or A.B.C.
A is the major version number, which is only incremented for major changes to Django, and these changes are not necessarily backwards-compatible. That is, code you wrote for Django 6.0 may break when we release Django 7.0.
B is the minor version number, which is incremented for large yet backwards compatible changes. Code written for Django 6.4 will continue to work under Django 6.5.
A minor release may deprecate certain features in previous releases. If a feature in version A.B is deprecated, it will continue to work in version A.B+1. In version A.B+2, use of the feature will raise a PendingDeprecationWarning but will continue to work. Version A.B+3 will remove the feature entirely. Major point releases will always remove deprecated features immediately.
C is the micro version number which, is incremented for bug and security fixes. A new micro-release will always be 100% backwards-compatible with the previous micro-release.
In some cases, we’ll make release candidate releases. These are of the form A.BrcN, which means the Nth candidate release of version A.B.
An exception to this version numbering scheme is the pre-1.0 Django code. There’s no guarantee of backwards-compatibility until the 1.0 release.
In Subversion, each Django release will be tagged under tags/releases. If it’s necessary to release a bug fix release or a security release that doesn’t come from the trunk, we’ll copy that tag to branches/releases to make the bug fix release.
Deciding on features
Once a feature’s been requested and discussed, eventually we’ll have a decision about whether to include the feature or drop it.
Whenever possible, we strive for a rough consensus. To that end, we’ll often have informal votes on django-developers about a feature. In these votes we follow the voting style invented by Apache and used on Python itself, where votes are given as +1, +0, -0, or -1. Roughly translated, these votes mean:
- +1: “I love the idea and I’m strongly committed to it.”
- +0: “Sounds OK to me.”
- -0: “I’m not thrilled, but I won’t stand in the way.”
- -1: “I strongly disagree and would be very unhappy to see the idea turn into reality.”
Although these votes on django-developers are informal, they’ll be taken very seriously. After a suitable voting period, if an obvious consensus arises we’ll follow the votes.
However, consensus is not always possible. Tough decisions will be discussed by all full committers and finally decided by the Benevolent Dictators for Life, Adrian and Jacob.
Commit access
Django has two types of committers:
- Full committers
These are people who have a long history of contributions to Django’s codebase, a solid track record of being polite and helpful on the mailing lists, and a proven desire to dedicate serious time to Django’s development.
The bar is very high for full commit access. It will only be granted by unanimous approval of all existing full committers, and the decision will err on the side of rejection.
- Partial committers
These are people who are “domain experts.” They have direct check-in access to the subsystems that fall under their jurisdiction, and they’re given a formal vote in questions that involve their subsystems. This type of access is likely to be given to someone who contributes a large subframework to Django and wants to continue to maintain it.
Like full committers, partial commit access is by unanimous approval of all full committers (and any other partial committers in the same area). However, the bar is set lower; proven expertise in the area in question is likely to be sufficient.
To request commit access, please contact an existing committer privately. Public requests for commit access are potential flame-war starters, and will be ignored.
Questions/Feedback
If you notice errors with this documentation, please open a ticket and let us know!
Please only use the ticket tracker for criticisms and improvements on the docs. For tech support, ask in the IRC channel or post to the django-users list.

