| ====================== |
| Contributing to Django |
| ====================== |
| |
| 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. If you're looking |
| for an easy way to start contributing to Django have a look at the |
| `easy-pickings`_ tickets. |
| |
| * 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. |
| |
| .. seealso:: |
| |
| This document contains specific details for contributing to |
| Django. However, many new contributors find this guide confusing |
| or intimidating at first. For a simpler introduction |
| to becoming a contributor please see the :doc:`/howto/contribute` guide. |
| |
| .. _reporting-bugs: |
| |
| 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 :doc:`FAQ </faq/index>` 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`_. |
| |
| * **Don't** post to django-developers just to announce that you have filed |
| a bug report. All the tickets are mailed to another list |
| (`django-updates`_), which is tracked by developers and interested |
| community members; we see them as they are filed. |
| |
| .. _django-updates: http://groups.google.com/group/django-updates |
| |
| .. _reporting-security-issues: |
| |
| 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. |
| |
| * Focus on developing a fix as quickly as possible and produce 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 third-party distributors of Django ("vendors"). We will send |
| these vendor notifications through private email 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. |
| |
| "Claiming" tickets |
| ------------------ |
| |
| In an open-source project with hundreds of contributors around the world, it's |
| important to manage communication efficiently so that work doesn't get |
| duplicated and contributors can be as effective as possible. Hence, our policy |
| is for contributors to "claim" tickets in order to let other developers know |
| that a particular bug or feature is being worked on. |
| |
| If you have identified a contribution you want to make and you're capable of |
| fixing it (as measured by your coding ability, knowledge of Django internals |
| and time availability), claim it by following these steps: |
| |
| * `Create an account`_ to use in our ticket system. |
| |
| * If a ticket for this issue doesn't exist yet, create one in our |
| `ticket tracker`_. |
| |
| * If a ticket for this issue already exists, make sure nobody else has |
| claimed it. To do this, look at the "Assigned to" section of the ticket. |
| If it's assigned to "nobody," then it's available to be claimed. |
| Otherwise, somebody else is working on this ticket, and you either find |
| another bug/feature to work on, or contact the developer working on the |
| ticket to offer your help. |
| |
| * Log into your account, if you haven't already, by clicking "Login" in the |
| upper right of the ticket page. |
| |
| * Claim the ticket by clicking the radio button next to "Accept ticket" |
| near the bottom of the page, then clicking "Submit changes." |
| |
| If you have an account but have forgotten your password, you can reset it |
| using the `password reset page`_. |
| |
| .. _Create an account: http://www.djangoproject.com/accounts/register/ |
| .. _password reset page: http://www.djangoproject.com/accounts/password/reset/ |
| |
| Ticket claimers' responsibility |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Once you've claimed a ticket, you have a responsibility to work on that ticket |
| in a reasonably timely fashion. If you don't have time to work on it, either |
| unclaim it or don't claim it in the first place! |
| |
| If there's no sign of progress on a particular claimed ticket for a week or |
| two, another developer may ask you to relinquish the ticket claim so that it's |
| no longer monopolized and somebody else can claim it. |
| |
| If you've claimed a ticket and it's taking a long time (days or weeks) to code, |
| keep everybody updated by posting comments on the ticket. If you don't provide |
| regular updates, and you don't respond to a request for a progress report, |
| your claim on the ticket may be revoked. As always, more communication is |
| better than less communication! |
| |
| Which tickets should be claimed? |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Of course, going through the steps of claiming tickets is overkill in some |
| cases. In the case of small changes, such as typos in the documentation or |
| small bugs that will only take a few minutes to fix, you don't need to jump |
| through the hoops of claiming tickets. Just submit your patch and be done with |
| it. |
| |
| 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. |
| |
| Patches in ``git diff`` format are also acceptable. |
| |
| * When creating patches, always run ``svn diff`` from the top-level |
| ``trunk`` directory -- i.e., the one that contains ``django``, ``docs``, |
| ``tests``, ``AUTHORS``, etc. This makes it easy for other people to |
| apply your patches. |
| |
| * 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. The core team--as well as many community members--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: |
| |
| .. image:: _images/djangotickets.png |
| :height: 451 |
| :width: 590 |
| :alt: Django's ticket workflow |
| |
| We've got two roles in this diagram: |
| |
| * Core developers: people with commit access who are responsible for |
| making the big decisions, writing large portions of the code and |
| integrating the contributions of the community. |
| |
| * Ticket triagers: anyone in the Django community who chooses to |
| become involved in Django's development process. Our Trac installation |
| is :ref:`intentionally left open to the public |
| <the-spirit-of-contributing>`, and anyone can triage tickets. |
| Django is a community project, and we encourage `triage by the |
| community`_. |
| |
| Triage stages |
| ------------- |
| |
| Second, note the five triage stages: |
| |
| 1. A ticket starts as **Unreviewed**, meaning that nobody has examined |
| the ticket. |
| |
| 2. **Design decision needed** means "this concept requires a design |
| decision," which should be discussed either in the ticket comments or on |
| `django-developers`_. The "Design decision needed" step will generally |
| only be used for feature requests. It can also be used for issues |
| that *might* be bugs, depending on opinion or interpretation. Obvious |
| bugs (such as crashes, incorrect query results, or non-compliance with a |
| standard) skip this step and move straight to "Accepted". |
| |
| 3. 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. |
| |
| 4. In some cases, a ticket might get moved to the **Someday/Maybe** state. |
| This means the ticket is an enhancement request that we might consider |
| adding to the framework if an excellent patch is submitted. These |
| tickets are not a high priority. |
| |
| 5. If a ticket has an associated patch (see below), it will be reviewed |
| by the community. If the patch is complete, it'll be marked as **Ready |
| for checkin** so that a core developer knows to review and commit the |
| patch. |
| |
| 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 them 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, there is a flaw in the implementation, or that the code |
| doesn't meet our standards. |
| |
| .. seealso:: |
| |
| The :ref:`contributing howto guide <triage-stages-explained>` has a detailed |
| explanation of each of the triage stages and how the triage process works in |
| Trac. |
| |
| .. _ticket-resolutions: |
| |
| Ticket Resolutions |
| ------------------ |
| |
| A ticket can be resolved in a number of ways: |
| |
| "fixed" |
| Used by 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. This means that the |
| issue in the ticket is actually the result of a user error, or |
| describes a problem with something other than Django, or isn't |
| a bug report or feature request at all (for example, some new users |
| submit support queries as tickets). |
| |
| "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. Feel free to |
| start or join in discussions of "wontfix" tickets on the mailing list, |
| but please do not reopen tickets closed as "wontfix" by core |
| developers. |
| |
| "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 ticket doesn't contain enough detail to replicate |
| the original bug. |
| |
| "needsinfo" |
| Used when the ticket does not contain enough information to replicate |
| the reported issue but is potentially still valid. The ticket |
| should be reopened when more information is supplied. |
| |
| 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 provide further information. |
| Please do not reopen tickets that have been marked as "wontfix" by core |
| developers. |
| |
| .. seealso:: |
| |
| For more information on what to do when closing a ticket, please see the |
| :ref:`contributing howto guide <closing-tickets>`. |
| |
| .. _required details: `Reporting bugs`_ |
| .. _good patch: `Patch style`_ |
| .. _triage by the community: `Triage by the general community`_ |
| .. _patch: `Submitting patches`_ |
| |
| Triage by the general community |
| ------------------------------- |
| |
| Although the core developers make the big decisions in the ticket triage |
| process, there's a lot that general community members can do to help the |
| triage process. In particular, you can help out by: |
| |
| * Closing "Unreviewed" tickets as "invalid", "worksforme" or "duplicate." |
| |
| * Promoting "Unreviewed" tickets to "Design decision needed" if a design |
| decision needs to be made, or "Accepted" in case of obvious bugs. |
| |
| * Correcting the "Needs tests", "Needs documentation", or "Has patch" |
| flags for tickets where they are incorrectly set. |
| |
| * Adding the `easy-pickings`_ keyword to tickets that are small and |
| relatively straightforward. |
| |
| * Checking that old tickets are still valid. If a ticket hasn't seen |
| any activity in a long time, it's possible that the problem has been |
| fixed but the ticket hasn't yet been closed. |
| |
| * Contacting the owners of tickets that have been claimed but have not |
| seen any recent activity. If the owner doesn't respond after a week |
| or so, remove the owner's claim on the ticket. |
| |
| * Identifying trends and themes in the tickets. If there a lot of bug |
| reports about a particular part of Django, it may indicate we should |
| consider refactoring that part of the code. If a trend is emerging, |
| you should raise it for discussion (referencing the relevant tickets) |
| on `django-developers`_. |
| |
| However, we do ask the following of all general community members working in |
| the ticket database: |
| |
| * Please **don't** close tickets as "wontfix." The core developers will |
| make the final determination of the fate of a ticket, usually after |
| consultation with the community. |
| |
| * Please **don't** promote your own tickets to "Ready for checkin". You |
| may mark other people's tickets which you've reviewed as "Ready for |
| checkin", but you should get at minimum one other community member to |
| review a patch that you submit. |
| |
| * Please **don't** reverse a decision that has been made by a core |
| developer. If you disagree with a decision that has been made, |
| please post a message to `django-developers`_. |
| |
| * If you're unsure if you should be making a change, don't make the change |
| but instead leave a comment with your concerns on the ticket, or |
| post a message to `django-developers`_. It's okay to be unsure, but |
| your input is still valuable. |
| |
| .. _contributing-translations: |
| |
| Submitting and maintaining translations |
| ======================================= |
| |
| Various parts of Django, such as the admin site and validation error messages, |
| are internationalized. This means they display different text depending on a |
| user's language setting. For this, Django uses the same internationalization |
| infrastructure available to Django applications described in the |
| :doc:`i18n documentation</topics/i18n/index>`. |
| |
| These translations are contributed by Django users worldwide. If you find an |
| incorrect translation or want to discuss specific translations, go to the |
| `translation team`_ page for that language. If you would like to help out |
| with translating or add a language that isn't yet translated, here's what |
| to do: |
| |
| * Join the `Django i18n mailing list`_ and introduce yourself. |
| |
| * Make sure you read the notes about :ref:`specialties-of-django-i18n`. |
| |
| * Signup at `Transifex`_ and visit the `Django project page`_. |
| |
| * On the "`Translation Teams`_" page, choose the language team you want |
| to work with, **or** -- in case the language team doesn't exist yet -- |
| request a new team by clicking on the "Request a new team" button |
| and select the appropriate language. |
| |
| * Then, click the "Join this Team" button to become a member of this team. |
| Every team has at least one coordinator who is responsible to review |
| your membership request. You can of course also contact the team |
| coordinator to clarify procedural problems and handle the actual |
| translation process. |
| |
| * Once you are a member of a team choose the translation resource you |
| want update on the team page. For example the "core" resource refers |
| to the translation catalogue that contains all non-app translations. |
| Each of the contrib apps also have a resource (prefixed with "contrib-"). |
| |
| .. note:: |
| For more information about how to use Transifex, see the |
| `Transifex Help`_ |
| |
| * Optionally, review and update the ``conf/locale/<locale>/formats.py`` |
| file to describe the date, time and numbers formatting particularities |
| of your locale. These files aren't covered by the use of Transifex and |
| require a patch against the Django source tree, just as a code change |
| would: |
| |
| * Create a diff against the current Subversion trunk. |
| |
| * Open a ticket in Django's ticket system, set its ``Component`` field |
| to ``Translations``, and attach the patch to it. See |
| :ref:`format-localization` for details. |
| |
| .. _Django i18n mailing list: http://groups.google.com/group/django-i18n/ |
| .. _Transifex: http://www.transifex.net/ |
| .. _Django project page: http://www.transifex.net/projects/p/django/ |
| .. _translation teams: http://www.transifex.net/projects/p/django/teams/ |
| .. _translation team: http://www.transifex.net/projects/p/django/teams/ |
| .. _Transifex Help: http://help.transifex.net/ |
| |
| Submitting javascript patches |
| ============================= |
| |
| .. versionadded:: 1.2 |
| |
| Django's admin system leverages the jQuery framework to increase the |
| capabilities of the admin interface. In conjunction, there is an emphasis on |
| admin javascript performance and minimizing overall admin media file size. |
| Serving compressed or "minified" versions of javascript files is considered |
| best practice in this regard. |
| |
| To that end, patches for javascript files should include both the original |
| code for future development (e.g. "foo.js"), and a compressed version for |
| production use (e.g. "foo.min.js"). Any links to the file in the codebase |
| should point to the compressed version. |
| |
| To simplify the process of providing optimized javascript code, Django |
| includes a handy script which should be used to create a "minified" version. |
| This script is located at ``/contrib/admin/media/js/compress.py``. |
| |
| Behind the scenes, ``compress.py`` is a front-end for Google's |
| `Closure Compiler`_ which is written in Java. However, the Closure Compiler |
| library is not bundled with Django directly, so those wishing to contribute |
| complete javascript patches will need to download and install the library |
| independently. |
| |
| The Closure Compiler library requires Java version 6 or higher (Java 1.6 or |
| higher on Mac OS X). Note that Mac OS X 10.5 and earlier did not ship with Java |
| 1.6 by default, so it may be necessary to upgrade your Java installation before |
| the tool will be functional. Also note that even after upgrading Java, the |
| default `/usr/bin/java` command may remain linked to the previous Java |
| binary, so relinking that command may be necessary as well. |
| |
| Please don't forget to run ``compress.py`` and include the ``diff`` of the |
| minified scripts when submitting patches for Django's javascript. |
| |
| .. _Closure Compiler: http://code.google.com/closure/compiler/ |
| |
| Django conventions |
| ================== |
| |
| Various Django-specific code issues are detailed in this section. |
| |
| Use of ``django.conf.settings`` |
| ------------------------------- |
| |
| Modules should not in general use settings stored in ``django.conf.settings`` |
| at the top level (i.e. evaluated when the module is imported). The explanation |
| for this is as follows: |
| |
| Manual configuration of settings (i.e. not relying on the |
| ``DJANGO_SETTINGS_MODULE`` environment variable) is allowed and possible as |
| follows:: |
| |
| from django.conf import settings |
| |
| settings.configure({}, SOME_SETTING='foo') |
| |
| However, if any setting is accessed before the ``settings.configure`` line, |
| this will not work. (Internally, ``settings`` is a ``LazyObject`` which |
| configures itself automatically when the settings are accessed if it has not |
| already been configured). |
| |
| So, if there is a module containing some code as follows:: |
| |
| from django.conf import settings |
| from django.core.urlresolvers import get_callable |
| |
| default_foo_view = get_callable(settings.FOO_VIEW) |
| |
| ...then importing this module will cause the settings object to be configured. |
| That means that the ability for third parties to import the module at the top |
| level is incompatible with the ability to configure the settings object |
| manually, or makes it very difficult in some circumstances. |
| |
| Instead of the above code, a level of laziness or indirection must be used, |
| such as `django.utils.functional.LazyObject``, ``django.utils.functional.lazy`` |
| or ``lambda``. |
| |
| Coding style |
| ============ |
| |
| Please follow these coding standards when writing code for inclusion in Django: |
| |
| * Unless otherwise specified, follow :pep:`8`. |
| |
| You could use a tool like `pep8.py`_ to check for some problems in this |
| area, but remember that PEP 8 is only a guide, so respect the style of |
| the surrounding code as a primary goal. |
| |
| * 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 :doc:`i18n |
| documentation </topics/i18n/index>` for details. |
| |
| * In docstrings, use "action words" such as:: |
| |
| def foo(): |
| """ |
| Calculates something and returns the result. |
| """ |
| pass |
| |
| Here's an example of what not to do:: |
| |
| def foo(): |
| """ |
| Calculate something and return the result. |
| """ |
| pass |
| |
| * 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. |
| |
| Template style |
| -------------- |
| |
| * In Django template code, put one (and only one) space between the curly |
| brackets and the tag contents. |
| |
| Do this: |
| |
| .. code-block:: html+django |
| |
| {{ foo }} |
| |
| Don't do this: |
| |
| .. code-block:: html+django |
| |
| {{foo}} |
| |
| View style |
| ---------- |
| |
| * 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): |
| # ... |
| |
| Model style |
| ----------- |
| |
| * Field names should be all lowercase, using underscores instead of |
| camelCase. |
| |
| Do this:: |
| |
| class Person(models.Model): |
| first_name = models.CharField(max_length=20) |
| last_name = models.CharField(max_length=40) |
| |
| Don't do this:: |
| |
| class Person(models.Model): |
| FirstName = models.CharField(max_length=20) |
| Last_Name = models.CharField(max_length=40) |
| |
| * The ``class Meta`` should appear *after* the fields are defined, with |
| a single blank line separating the fields and the class definition. |
| |
| Do this:: |
| |
| class Person(models.Model): |
| first_name = models.CharField(max_length=20) |
| last_name = models.CharField(max_length=40) |
| |
| class Meta: |
| verbose_name_plural = 'people' |
| |
| Don't do this:: |
| |
| class Person(models.Model): |
| first_name = models.CharField(max_length=20) |
| last_name = models.CharField(max_length=40) |
| class Meta: |
| verbose_name_plural = 'people' |
| |
| Don't do this, either:: |
| |
| class Person(models.Model): |
| class Meta: |
| verbose_name_plural = 'people' |
| |
| first_name = models.CharField(max_length=20) |
| last_name = models.CharField(max_length=40) |
| |
| * The order of model inner classes and standard methods should be as |
| follows (noting that these are not all required): |
| |
| * All database fields |
| * Custom manager attributes |
| * ``class Meta`` |
| * ``def __unicode__()`` |
| * ``def __str__()`` |
| * ``def save()`` |
| * ``def get_absolute_url()`` |
| * Any custom methods |
| |
| * If ``choices`` is defined for a given model field, define the choices as |
| a tuple of tuples, with an all-uppercase name, either near the top of the |
| model module or just above the model class. Example:: |
| |
| GENDER_CHOICES = ( |
| ('M', 'Male'), |
| ('F', 'Female'), |
| ) |
| |
| Documentation style |
| =================== |
| |
| We place a high importance on consistency and readability of documentation. |
| (After all, Django was created in a journalism environment!) |
| |
| How to document new features |
| ---------------------------- |
| |
| We treat our documentation like we treat our code: we aim to improve it as |
| often as possible. This section explains how writers can craft their |
| documentation changes in the most useful and least error-prone ways. |
| |
| Documentation changes come in two forms: |
| |
| * General improvements -- Typo corrections, error fixes and better |
| explanations through clearer writing and more examples. |
| |
| * New features -- Documentation of features that have been added to the |
| framework since the last release. |
| |
| Our policy is: |
| |
| **All documentation of new features should be written in a way that clearly |
| designates the features are only available in the Django development |
| version. Assume documentation readers are using the latest release, not the |
| development version.** |
| |
| Our preferred way for marking new features is by prefacing the features' |
| documentation with: ".. versionadded:: X.Y", followed by an optional one line |
| comment and a mandatory blank line. |
| |
| General improvements, or other changes to the APIs that should be emphasized |
| should use the ".. versionchanged:: X.Y" directive (with the same format as the |
| ``versionadded`` mentioned above. |
| |
| There's a full page of information about the :doc:`Django documentation |
| system </internals/documentation>` that you should read prior to working on the |
| documentation. |
| |
| Guidelines for reST files |
| ------------------------- |
| |
| These guidelines regulate the format of our reST documentation: |
| |
| * In section titles, capitalize only initial words and proper nouns. |
| |
| * Wrap the documentation at 80 characters wide, unless a code example |
| is significantly less readable when split over two lines, or for another |
| good reason. |
| |
| Commonly used terms |
| ------------------- |
| |
| Here are some style guidelines on commonly used terms throughout the |
| documentation: |
| |
| * **Django** -- when referring to the framework, capitalize Django. It is |
| lowercase only in Python code and in the djangoproject.com logo. |
| |
| * **e-mail** -- it has a hyphen. |
| |
| * **MySQL** |
| |
| * **PostgreSQL** |
| |
| * **Python** -- when referring to the language, capitalize Python. |
| |
| * **realize**, **customize**, **initialize**, etc. -- use the American |
| "ize" suffix, not "ise." |
| |
| * **SQLite** |
| |
| * **subclass** -- it's a single word without a hyphen, both as a verb |
| ("subclass that model") and as a noun ("create a subclass"). |
| |
| * **Web**, **World Wide Web**, **the Web** -- note Web is always |
| capitalized when referring to the World Wide Web. |
| |
| * **Web site** -- use two words, with Web capitalized. |
| |
| Django-specific terminology |
| --------------------------- |
| |
| * **model** -- it's not capitalized. |
| |
| * **template** -- it's not capitalized. |
| |
| * **URLconf** -- use three capitalized letters, with no space before |
| "conf." |
| |
| * **view** -- it's not capitalized. |
| |
| 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. |
| |
| * Separate bug fixes from feature changes. |
| |
| Bug fixes need to be added to the current bugfix branch (e.g. the |
| ``1.0.X`` branch) as well as the current trunk. |
| |
| * 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. |
| |
| .. _Trac post-commit hook: http://trac.edgewall.org/browser/trunk/contrib/trac-post-commit-hook |
| |
| * 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. |
| |
| Reverting commits |
| ----------------- |
| |
| Nobody's perfect; mistakes will be committed. When a mistaken commit is |
| discovered, please follow these guidelines: |
| |
| * Try very hard to ensure that mistakes don't happen. Just because we |
| have a reversion policy doesn't relax your responsibility to aim for |
| the highest quality possible. Really: double-check your work before |
| you commit it in the first place! |
| |
| * If possible, have the original author revert his/her own commit. |
| |
| * Don't revert another author's changes without permission from the |
| original author. |
| |
| * If the original author can't be reached (within a reasonable amount |
| of time -- a day or so) and the problem is severe -- crashing bug, |
| major test failures, etc -- then ask for objections on django-dev |
| then revert if there are none. |
| |
| * If the problem is small (a feature commit after feature freeze, |
| say), wait it out. |
| |
| * If there's a disagreement between the committer and the |
| reverter-to-be then try to work it out on the `django-developers`_ |
| mailing list. If an agreement can't be reached then it should |
| be put to a vote. |
| |
| * If the commit introduced a confirmed, disclosed security |
| vulnerability then the commit may be reverted immediately without |
| permission from anyone. |
| |
| * The release branch maintainer may back out commits to the release |
| branch without permission if the commit breaks the release branch. |
| |
| .. _unit-tests: |
| |
| 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/``). |
| * Everything else in core Django code (``tests/regressiontests``) |
| * Contrib apps (``django/contrib/<contribapp>/tests``, see below) |
| |
| 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 :doc:`Testing Django applications </topics/testing>` |
| for an explanation of how to write new tests. |
| |
| .. _running-unit-tests: |
| |
| Running the unit tests |
| ---------------------- |
| |
| Quickstart |
| ~~~~~~~~~~ |
| |
| Running the tests requires a Django settings module that defines the |
| databases to use. To make it easy to get started. Django provides a |
| sample settings module that uses the SQLite database. To run the tests |
| with this sample ``settings`` module, ``cd`` into the Django |
| ``tests/`` directory and run: |
| |
| .. code-block:: bash |
| |
| ./runtests.py --settings=test_sqlite |
| |
| If you get an ``ImportError: No module named django.contrib`` error, |
| you need to add your install of Django to your ``PYTHONPATH``. For |
| more details on how to do this, read `Pointing Python at the new |
| Django version`_ below. |
| |
| Using another ``settings`` module |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| The included settings module allows you to run the test suite using |
| SQLite. If you want to test behavior using a different database (and |
| if you're proposing patches for Django, it's a good idea to test |
| across databases), you may need to define your own settings file. |
| |
| To run the tests with different settings, ``cd`` to the ``tests/`` directory |
| and type: |
| |
| .. code-block:: bash |
| |
| ./runtests.py --settings=path.to.django.settings |
| |
| The :setting:`DATABASES` setting in this test settings module needs to define |
| two databases: |
| |
| * A ``default`` database. This database should use the backend that |
| you want to use for primary testing |
| |
| * A database with the alias ``other``. The ``other`` database is |
| used to establish that queries can be directed to different |
| databases. As a result, this database can use any backend you |
| want. It doesn't need to use the same backend as the ``default`` |
| database (although it can use the same backend if you want to). |
| |
| If you're using a backend that isn't SQLite, you will need to provide other |
| details for each database: |
| |
| * The :setting:`USER` option for each of your databases needs to |
| specify an existing user account for the database. |
| |
| * The :setting:`PASSWORD` option needs to provide the password for |
| the :setting:`USER` that has been specified. |
| |
| * The :setting:`NAME` option must be the name of an existing database to |
| which the given user has permission to connect. The unit tests will not |
| touch this database; the test runner creates a new database whose name is |
| :setting:`NAME` prefixed with ``test_``, and this test database is |
| deleted when the tests are finished. This means your user account needs |
| permission to execute ``CREATE DATABASE``. |
| |
| You will also need to ensure that your database uses UTF-8 as the default |
| character set. If your database server doesn't use UTF-8 as a default charset, |
| you will need to include a value for ``TEST_CHARSET`` in the settings |
| dictionary for the applicable database. |
| |
| Running only some of the tests |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Django's entire test suite takes a while to run, and running every single test |
| could be redundant if, say, you just added a test to Django that you want to |
| run quickly without running everything else. You can run a subset of the unit |
| tests by appending the names of the test modules to ``runtests.py`` on the |
| command line. |
| |
| For example, if you'd like to run tests only for generic relations and |
| internationalization, type: |
| |
| .. code-block:: bash |
| |
| ./runtests.py --settings=path.to.settings generic_relations i18n |
| |
| How do you find out the names of individual tests? Look in ``tests/modeltests`` |
| and ``tests/regressiontests`` -- each directory name there is the name of a |
| test. |
| |
| If you just want to run a particular class of tests, you can specify a list of |
| paths to individual test classes. For example, to run the ``TranslationTests`` |
| of the ``i18n`` module, type: |
| |
| .. code-block:: bash |
| |
| ./runtests.py --settings=path.to.settings i18n.TranslationTests |
| |
| Going beyond that, you can specify an individual test method like this: |
| |
| .. code-block:: bash |
| |
| ./runtests.py --settings=path.to.settings i18n.TranslationTests.test_lazy_objects |
| |
| Running all the tests |
| ~~~~~~~~~~~~~~~~~~~~~ |
| |
| If you want to run the full suite of tests, you'll need to install a number of |
| dependencies: |
| |
| * PyYAML_ |
| * Markdown_ |
| * Textile_ |
| * Docutils_ |
| * setuptools_ |
| * memcached_, plus a :ref:`supported Python binding <memcached>` |
| * gettext_ (:ref:`gettext_on_windows`) |
| |
| If you want to test the memcached cache backend, you'll also need to define |
| a :setting:`CACHES` setting that points at your memcached instance. |
| |
| Each of these dependencies is optional. If you're missing any of them, the |
| associated tests will be skipped. |
| |
| .. _PyYAML: http://pyyaml.org/wiki/PyYAML |
| .. _Markdown: http://pypi.python.org/pypi/Markdown/1.7 |
| .. _Textile: http://pypi.python.org/pypi/textile |
| .. _docutils: http://pypi.python.org/pypi/docutils/0.4 |
| .. _setuptools: http://pypi.python.org/pypi/setuptools/ |
| .. _memcached: http://www.danga.com/memcached/ |
| .. _gettext: http://www.gnu.org/software/gettext/manual/gettext.html |
| |
| Contrib apps |
| ------------ |
| |
| Tests for apps in ``django/contrib/`` go in their respective directories under |
| ``django/contrib/``, in a ``tests.py`` file. (You can split the tests over |
| multiple modules by using a ``tests`` directory in the normal Python way.) |
| |
| For the tests to be found, a ``models.py`` file must exist (it doesn't |
| have to have anything in it). If you have URLs that need to be |
| mapped, put them in ``tests/urls.py``. |
| |
| To run tests for just one contrib app (e.g. ``markup``), use the same |
| method as above:: |
| |
| ./runtests.py --settings=settings markup |
| |
| 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 make a request most effectively: |
| |
| * 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, the trunk must be kept stable. People should be able to run |
| production sites against the trunk at any time. Additionally, commits to trunk |
| ought to be as atomic as possible -- smaller changes are better. Thus, large |
| feature changes -- that is, changes too large to be encapsulated in a single |
| patch, or changes that need multiple eyes on them -- must happen on dedicated |
| branches. |
| |
| This means that if you want to work on a large feature -- anything that would |
| take more than a single patch, or requires large-scale refactoring -- you need |
| to do it on a feature branch. Our development process recognizes two options |
| for feature branches: |
| |
| 1. Feature branches using a distributed revision control system like |
| Git_, Mercurial_, Bazaar_, etc. |
| |
| If you're familiar with one of these tools, this is probably your best |
| option since it doesn't require any support or buy-in from the Django |
| core developers. |
| |
| However, do keep in mind that Django will continue to use Subversion for |
| the foreseeable future, and this will naturally limit the recognition of |
| your branch. Further, if your branch becomes eligible for merging to |
| trunk you'll need to find a core developer familiar with your DVCS of |
| choice who'll actually perform the merge. |
| |
| If you do decided to start a distributed branch of Django and choose to |
| make it public, please add the branch to the `Django branches`_ wiki |
| page. |
| |
| 2. Feature branches using SVN have a higher bar. If you want a branch |
| in SVN itself, you'll need a "mentor" among the :doc:`core committers |
| </internals/committers>`. This person is responsible for actually |
| creating the branch, monitoring your process (see below), and |
| ultimately merging the branch into trunk. |
| |
| If you want a feature branch in SVN, you'll need to ask in |
| `django-developers`_ for a mentor. |
| |
| .. _git: http://git-scm.com/ |
| .. _mercurial: http://mercurial.selenic.com/ |
| .. _bazaar: http://bazaar.canonical.com/ |
| .. _django branches: http://code.djangoproject.com/wiki/DjangoBranches |
| |
| Branch rules |
| ------------ |
| |
| We've got a few rules for branches born out of experience with what makes a |
| successful Django branch. |
| |
| DVCS branches are obviously not under central control, so we have no way of |
| enforcing these rules. However, if you're using a DVCS, following these rules |
| will give you the best chance of having a successful branch (read: merged back |
| to trunk). |
| |
| Developers with branches in SVN, however, **must** follow these rules. The |
| branch mentor will keep on eye on the branch and **will delete it** if these |
| rules are broken. |
| |
| * 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. |
| |
| * Merge changes from trunk no less than once a week, and preferably every |
| couple-three days. |
| |
| In our experience, doing regular trunk merges is often the difference |
| between a successful branch and one that fizzles and dies. |
| |
| If you're working on an SVN branch, you should be using `svnmerge.py`_ |
| to track merges from trunk. |
| |
| * Keep tests passing and documentation up-to-date. As with patches, |
| we'll only merge a branch that comes with tests and documentation. |
| |
| .. _svnmerge.py: http://www.orcaware.com/svn/wiki/Svnmerge.py |
| |
| 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: |
| |
| .. code-block:: bash |
| |
| 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: |
| |
| .. code-block:: bash |
| |
| 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.) |
| |
| .. _list of branch names: http://code.djangoproject.com/browser/django/branches |
| |
| 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``. |
| |
| .. _path file: http://docs.python.org/library/site.html |
| |
| How we make decisions |
| ===================== |
| |
| 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. If consensus cannot be reached, or |
| if the discussion towards a consensus fizzles out without a concrete decision, |
| we use a more formal process. |
| |
| Any core committer (see below) may call for a formal vote using the same |
| voting mechanism above. A proposition will be considered carried by the core |
| team if: |
| |
| * There are three "+1" votes from members of the core team. |
| |
| * There is no "-1" vote from any member of the core team. |
| |
| * The BDFLs haven't stepped in and executed their positive or negative |
| veto. |
| |
| When calling for a vote, the caller should specify a deadline by which |
| votes must be received. One week is generally suggested as the minimum |
| amount of time. |
| |
| Since this process allows any core committer to veto a proposal, any "-1" |
| votes (or BDFL vetos) should be accompanied by an explanation that explains |
| what it would take to convert that "-1" into at least a "+0". |
| |
| Whenever possible, these formal votes should be announced and held in |
| public on the `django-developers`_ mailing list. However, overly sensitive |
| or contentious issues -- including, most notably, votes on new core |
| committers -- may be held in private. |
| |
| Commit access |
| ============= |
| |
| Django has two types of committers: |
| |
| Core 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 high for full commit access. |
| |
| 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. |
| |
| Partial commit access is granted by the same process as full |
| committers. However, the bar is set lower; proven expertise in the area |
| in question is likely to be sufficient. |
| |
| Decisions on new committers will follow the process explained above in `how |
| we make decisions`_. |
| |
| To request commit access, please contact an existing committer privately. |
| Public requests for commit access are potential flame-war starters, and |
| will be ignored. |
| |
| .. _community page: http://www.djangoproject.com/community/ |
| .. _ticket tracker: http://code.djangoproject.com/newticket |
| .. _django-developers: http://groups.google.com/group/django-developers |
| .. _search the tracker: http://code.djangoproject.com/search |
| .. _django-users: http://groups.google.com/group/django-users |
| .. _`#django`: irc://irc.freenode.net/django |
| .. _list of tickets with patches: http://code.djangoproject.com/query?status=new&status=assigned&status=reopened&has_patch=1&order=priority |
| .. _pep8.py: http://pypi.python.org/pypi/pep8/ |
| .. _i18n branch: http://code.djangoproject.com/browser/django/branches/i18n |
| .. _`tags/releases`: http://code.djangoproject.com/browser/django/tags/releases |
| .. _`easy-pickings`: http://code.djangoproject.com/query?status=new&status=assigned&status=reopened&keywords=~easy-pickings&order=priority |