diff options
| author | Andrew Godwin <andrew@aeracode.org> | 2012-12-18 09:02:07 +0000 |
|---|---|---|
| committer | Andrew Godwin <andrew@aeracode.org> | 2012-12-18 09:02:07 +0000 |
| commit | b62e82365ad56ca930f7abb1d1dbdf9ce5a7c7c3 (patch) | |
| tree | 76bce44f4c7ee6172dcf116be6e4a26e380ef20a /docs/ref | |
| parent | 6a632e04578776e877adc5e2dc53f008c890a0d4 (diff) | |
| parent | c64b57d16688025b2d48668d5c4cb9eda7484612 (diff) | |
Merge remote-tracking branch 'core/master' into schema-alteration
Conflicts:
django/db/models/loading.py
django/db/models/options.py
Diffstat (limited to 'docs/ref')
30 files changed, 1039 insertions, 440 deletions
diff --git a/docs/ref/class-based-views/flattened-index.txt b/docs/ref/class-based-views/flattened-index.txt index cbce3690e2..aa2f51f156 100644 --- a/docs/ref/class-based-views/flattened-index.txt +++ b/docs/ref/class-based-views/flattened-index.txt @@ -116,6 +116,7 @@ ListView * :attr:`~django.views.generic.base.View.http_method_names` * :attr:`~django.views.generic.list.MultipleObjectMixin.model` * :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`] +* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_orphans` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_orphans`] * :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class` * :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`] * :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` @@ -290,6 +291,7 @@ ArchiveIndexView * :attr:`~django.views.generic.base.View.http_method_names` * :attr:`~django.views.generic.list.MultipleObjectMixin.model` * :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`] +* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_orphans` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_orphans`] * :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class` * :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`] * :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` @@ -325,6 +327,7 @@ YearArchiveView * :attr:`~django.views.generic.dates.BaseYearArchiveView.make_object_list` [:meth:`~django.views.generic.dates.BaseYearArchiveView.get_make_object_list`] * :attr:`~django.views.generic.list.MultipleObjectMixin.model` * :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`] +* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_orphans` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_orphans`] * :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class` * :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`] * :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` @@ -363,6 +366,7 @@ MonthArchiveView * :attr:`~django.views.generic.dates.MonthMixin.month` [:meth:`~django.views.generic.dates.MonthMixin.get_month`] * :attr:`~django.views.generic.dates.MonthMixin.month_format` [:meth:`~django.views.generic.dates.MonthMixin.get_month_format`] * :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`] +* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_orphans` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_orphans`] * :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class` * :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`] * :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` @@ -401,6 +405,7 @@ WeekArchiveView * :attr:`~django.views.generic.base.View.http_method_names` * :attr:`~django.views.generic.list.MultipleObjectMixin.model` * :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`] +* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_orphans` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_orphans`] * :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class` * :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`] * :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` @@ -443,6 +448,7 @@ DayArchiveView * :attr:`~django.views.generic.dates.MonthMixin.month` [:meth:`~django.views.generic.dates.MonthMixin.get_month`] * :attr:`~django.views.generic.dates.MonthMixin.month_format` [:meth:`~django.views.generic.dates.MonthMixin.get_month_format`] * :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`] +* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_orphans` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_orphans`] * :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class` * :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`] * :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` @@ -487,6 +493,7 @@ TodayArchiveView * :attr:`~django.views.generic.dates.MonthMixin.month` [:meth:`~django.views.generic.dates.MonthMixin.get_month`] * :attr:`~django.views.generic.dates.MonthMixin.month_format` [:meth:`~django.views.generic.dates.MonthMixin.get_month_format`] * :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`] +* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_orphans` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_orphans`] * :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class` * :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`] * :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` diff --git a/docs/ref/class-based-views/generic-date-based.txt b/docs/ref/class-based-views/generic-date-based.txt index c6af23e421..0ae0bcdf42 100644 --- a/docs/ref/class-based-views/generic-date-based.txt +++ b/docs/ref/class-based-views/generic-date-based.txt @@ -7,6 +7,21 @@ Generic date views Date-based generic views, provided in :mod:`django.views.generic.dates`, are views for displaying drilldown pages for date-based data. +.. note:: + + Some of the examples on this page assume that an ``Article`` model has been + defined as follows in ``myapp/models.py``:: + + from django.db import models + from django.core.urlresolvers import reverse + + class Article(models.Model): + title = models.CharField(max_length=200) + pub_date = models.DateField() + + def get_absolute_url(self): + return reverse('article-detail', kwargs={'pk': self.pk}) + ArchiveIndexView ---------------- @@ -35,6 +50,31 @@ ArchiveIndexView month or day using the attribute ``date_list_period``. This also applies to all subclass views. + **Example views.py**:: + + from django.conf.urls import patterns, url + from django.views.generic.dates import ArchiveIndexView + + from myapp.models import Article + + urlpatterns = patterns('', + url(r'^archive/$', + ArchiveIndexView.as_view(model=Article, date_field="pub_date"), + name="article_archive"), + ) + + **Example myapp/article_archive.html**: + + .. code-block:: html+django + + <ul> + {% for article in latest %} + <li>{{ article.pub_date }}: {{ article.title }}</li> + {% endfor %} + </ul> + + This will output all articles. + YearArchiveView --------------- @@ -109,6 +149,49 @@ YearArchiveView * Uses a default ``template_name_suffix`` of ``_archive_year``. + **Example views.py**:: + + from django.views.generic.dates import YearArchiveView + + from myapp.models import Article + + class ArticleYearArchiveView(YearArchiveView): + queryset = Article.objects.all() + date_field = "pub_date" + make_object_list = True + allow_future = True + + **Example urls.py**:: + + from django.conf.urls import patterns, url + + from myapp.views import ArticleYearArchiveView + + urlpatterns = patterns('', + url(r'^(?P<year>\d{4})/$', + ArticleYearArchiveView.as_view(), + name="article_year_archive"), + ) + + **Example myapp/article_archive_year.html**: + + .. code-block:: html+django + + <ul> + {% for date in date_list %} + <li>{{ date|date }}</li> + {% endfor %} + </ul> + + <div> + <h1>All Articles for {{ year|date:"Y" }}</h1> + {% for obj in object_list %} + <p> + {{ obj.title }} - {{ obj.pub_date|date:"F j, Y" }} + </p> + {% endfor %} + </div> + MonthArchiveView ---------------- @@ -162,6 +245,54 @@ MonthArchiveView * Uses a default ``template_name_suffix`` of ``_archive_month``. + **Example views.py**:: + + from django.views.generic.dates import MonthArchiveView + + from myapp.models import Article + + class ArticleMonthArchiveView(MonthArchiveView): + queryset = Article.objects.all() + date_field = "pub_date" + make_object_list = True + allow_future = True + + **Example urls.py**:: + + from django.conf.urls import patterns, url + + from myapp.views import ArticleMonthArchiveView + + urlpatterns = patterns('', + # Example: /2012/aug/ + url(r'^(?P<year>\d{4})/(?P<month>[-\w]+)/$', + ArticleMonthArchiveView.as_view(), + name="archive_month"), + # Example: /2012/08/ + url(r'^(?P<year>\d{4})/(?P<month>\d+)/$', + ArticleMonthArchiveView.as_view(month_format='%m'), + name="archive_month_numeric"), + ) + + **Example myapp/article_archive_month.html**: + + .. code-block:: html+django + + <ul> + {% for article in object_list %} + <li>{{ article.pub_date|date:"F j, Y" }}: {{ article.title }}</li> + {% endfor %} + </ul> + + <p> + {% if previous_month %} + Previous Month: {{ previous_month|date:"F Y" }} + {% endif %} + {% if next_month %} + Next Month: {{ next_month|date:"F Y" }} + {% endif %} + </p> + WeekArchiveView --------------- @@ -208,6 +339,65 @@ WeekArchiveView * Uses a default ``template_name_suffix`` of ``_archive_week``. + **Example views.py**:: + + from django.views.generic.dates import WeekArchiveView + + from myapp.models import Article + + class ArticleWeekArchiveView(WeekArchiveView): + queryset = Article.objects.all() + date_field = "pub_date" + make_object_list = True + week_format = "%W" + allow_future = True + + **Example urls.py**:: + + from django.conf.urls import patterns, url + + from myapp.views import ArticleWeekArchiveView + + urlpatterns = patterns('', + # Example: /2012/week/23/ + url(r'^(?P<year>\d{4})/week/(?P<week>\d+)/$', + ArticleWeekArchiveView.as_view(), + name="archive_week"), + ) + + **Example myapp/article_archive_week.html**: + + .. code-block:: html+django + + <h1>Week {{ week|date:'W' }}</h1> + + <ul> + {% for article in object_list %} + <li>{{ article.pub_date|date:"F j, Y" }}: {{ article.title }}</li> + {% endfor %} + </ul> + + <p> + {% if previous_week %} + Previous Week: {{ previous_week|date:"F Y" }} + {% endif %} + {% if previous_week and next_week %}--{% endif %} + {% if next_week %} + Next week: {{ next_week|date:"F Y" }} + {% endif %} + </p> + + In this example, you are outputting the week number. The default + ``week_format`` in the ``WeekArchiveView`` uses week format ``'%U'`` + which is based on the United States week system where the week begins on a + Sunday. The ``'%W'`` format uses the ISO week format and its week + begins on a Monday. The ``'%W'`` format is the same in both the + :func:`~time.strftime` and the :tfilter:`date`. + + However, the :tfilter:`date` template filter does not have an equivalent + output format that supports the US based week system. The :tfilter:`date` + filter ``'%U'`` outputs the number of seconds since the Unix epoch. + DayArchiveView -------------- @@ -265,6 +455,53 @@ DayArchiveView * Uses a default ``template_name_suffix`` of ``_archive_day``. + **Example views.py**:: + + from django.views.generic.dates import DayArchiveView + + from myapp.models import Article + + class ArticleDayArchiveView(DayArchiveView): + queryset = Article.objects.all() + date_field = "pub_date" + make_object_list = True + allow_future = True + + **Example urls.py**:: + + from django.conf.urls import patterns, url + + from myapp.views import ArticleDayArchiveView + + urlpatterns = patterns('', + # Example: /2012/nov/10/ + url(r'^(?P<year>\d{4})/(?P<month>[-\w]+)/(?P<day>\d+)/$', + ArticleDayArchiveView.as_view(), + name="archive_day"), + ) + + **Example myapp/article_archive_day.html**: + + .. code-block:: html+django + + <h1>{{ day }}</h1> + + <ul> + {% for article in object_list %} + <li>{{ article.pub_date|date:"F j, Y" }}: {{ article.title }}</li> + {% endfor %} + </ul> + + <p> + {% if previous_day %} + Previous Day: {{ previous_day }} + {% endif %} + {% if previous_day and next_day %}--{% endif %} + {% if next_day %} + Next Day: {{ next_day }} + {% endif %} + </p> + TodayArchiveView ---------------- @@ -289,6 +526,40 @@ TodayArchiveView * :class:`django.views.generic.dates.DateMixin` * :class:`django.views.generic.base.View` + **Notes** + + * Uses a default ``template_name_suffix`` of ``_archive_today``. + + **Example views.py**:: + + from django.views.generic.dates import TodayArchiveView + + from myapp.models import Article + + class ArticleTodayArchiveView(TodayArchiveView): + queryset = Article.objects.all() + date_field = "pub_date" + make_object_list = True + allow_future = True + + **Example urls.py**:: + + from django.conf.urls import patterns, url + + from myapp.views import ArticleTodayArchiveView + + urlpatterns = patterns('', + url(r'^today/$', + ArticleTodayArchiveView.as_view(), + name="archive_today"), + ) + + .. admonition:: Where is the example template for ``TodayArchiveView``? + + This view uses by default the same template as the + :class:`~DayArchiveView`, which is in the previous example. If you need + a different template, set the ``template_name`` attribute to be the + name of the new template. DateDetailView -------------- @@ -313,6 +584,32 @@ DateDetailView * :class:`django.views.generic.detail.SingleObjectMixin` * :class:`django.views.generic.base.View` + **Context** + + * Includes the single object associated with the ``model`` specified in + the ``DateDetailView``. + + **Notes** + + * Uses a default ``template_name_suffix`` of ``_detail``. + + **Example urls.py**:: + + from django.conf.urls import patterns, url + from django.views.generic.dates import DateDetailView + + urlpatterns = patterns('', + url(r'^(?P<year>\d+)/(?P<month>[-\w]+)/(?P<day>\d+)/(?P<pk>\d+)/$', + DateDetailView.as_view(model=Article, date_field="pub_date"), + name="archive_date_detail"), + ) + + **Example myapp/article_detail.html**: + + .. code-block:: html+django + + <h1>{{ object.title }}</h1> + .. note:: All of the generic views listed above have matching ``Base`` views that @@ -332,5 +629,3 @@ DateDetailView .. class:: BaseTodayArchiveView .. class:: BaseDateDetailView - - diff --git a/docs/ref/class-based-views/generic-editing.txt b/docs/ref/class-based-views/generic-editing.txt index 2fac06ee02..7ce5c1d1be 100644 --- a/docs/ref/class-based-views/generic-editing.txt +++ b/docs/ref/class-based-views/generic-editing.txt @@ -12,12 +12,11 @@ editing content: .. note:: - Some of the examples on this page assume that a model titled 'Author' - has been defined. For these cases we assume the following has been defined - in `myapp/models.py`:: + Some of the examples on this page assume that an ``Article`` model has been + defined as follows in ``myapp/models.py``:: - from django import models from django.core.urlresolvers import reverse + from django.db import models class Author(models.Model): name = models.CharField(max_length=200) diff --git a/docs/ref/class-based-views/index.txt b/docs/ref/class-based-views/index.txt index c4b632604a..a027953416 100644 --- a/docs/ref/class-based-views/index.txt +++ b/docs/ref/class-based-views/index.txt @@ -37,10 +37,11 @@ A class-based view is deployed into a URL pattern using the is modified, the actions of one user visiting your view could have an effect on subsequent users visiting the same view. -Any argument passed into :meth:`~django.views.generic.base.View.as_view()` will +Arguments passed into :meth:`~django.views.generic.base.View.as_view()` will be assigned onto the instance that is used to service a request. Using the previous example, this means that every request on ``MyView`` is able to use -``self.size``. +``self.size``. Arguments must correspond to attributes that already exist on +the class (return ``True`` on a ``hasattr`` check). Base vs Generic views --------------------- diff --git a/docs/ref/class-based-views/mixins-multiple-object.txt b/docs/ref/class-based-views/mixins-multiple-object.txt index cdb743fcbd..c85c962bce 100644 --- a/docs/ref/class-based-views/mixins-multiple-object.txt +++ b/docs/ref/class-based-views/mixins-multiple-object.txt @@ -69,8 +69,27 @@ MultipleObjectMixin An integer specifying how many objects should be displayed per page. If this is given, the view will paginate objects with :attr:`MultipleObjectMixin.paginate_by` objects per page. The view will - expect either a ``page`` query string parameter (via ``GET``) or a - ``page`` variable specified in the URLconf. + expect either a ``page`` query string parameter (via ``request.GET``) + or a ``page`` variable specified in the URLconf. + + .. attribute:: paginate_orphans + + .. versionadded:: 1.6 + + An integer specifying the number of "overflow" objects the last page + can contain. This extends the :attr:`MultipleObjectMixin.paginate_by` + limit on the last page by up to + :attr:`MultipleObjectMixin.paginate_orphans`, in order to keep the last + page from having a very small number of objects. + + .. attribute:: page_kwarg + + .. versionadded:: 1.5 + + A string specifying the name to use for the page parameter. + The view will expect this prameter to be available either as a query + string parameter (via ``request.GET``) or as a kwarg variable specified + in the URLconf. Defaults to ``page``. .. attribute:: paginator_class @@ -110,6 +129,14 @@ MultipleObjectMixin Returns an instance of the paginator to use for this view. By default, instantiates an instance of :attr:`paginator_class`. + .. method:: get_paginate_by() + + .. versionadded:: 1.6 + + An integer specifying the number of "overflow" objects the last page + can contain. By default this simply returns the value of + :attr:`MultipleObjectMixin.paginate_orphans`. + .. method:: get_allow_empty() Return a boolean specifying whether to display the page if no objects diff --git a/docs/ref/contrib/admin/actions.txt b/docs/ref/contrib/admin/actions.txt index 3f3b52983b..d7eef623d5 100644 --- a/docs/ref/contrib/admin/actions.txt +++ b/docs/ref/contrib/admin/actions.txt @@ -140,6 +140,15 @@ That's really all there is to it! If you're itching to write your own actions, you now know enough to get started. The rest of this document just covers more advanced techniques. +Handling errors in actions +-------------------------- + +If there are foreseeable error conditions that may occur while running your +action, you should gracefully inform the user of the problem. This means +handling exceptions and and using +:meth:`django.contrib.admin.ModelAdmin.message_user` to display a user friendly +description of the problem in the response. + Advanced action techniques ========================== diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 6ed929cb7d..6f79e97a3c 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -26,9 +26,10 @@ There are seven steps in activating the Django admin site: in your :setting:`INSTALLED_APPS` list, add them. 3. Add ``django.contrib.messages.context_processors.messages`` to - :setting:`TEMPLATE_CONTEXT_PROCESSORS` and - :class:`~django.contrib.messages.middleware.MessageMiddleware` to - :setting:`MIDDLEWARE_CLASSES`. (These are both active by default, so + :setting:`TEMPLATE_CONTEXT_PROCESSORS` as well as + :class:`django.contrib.auth.middleware.AuthenticationMiddleware` and + :class:`django.contrib.messages.middleware.MessageMiddleware` to + :setting:`MIDDLEWARE_CLASSES`. (These are all active by default, so you only need to do this if you've manually tweaked the settings.) 4. Determine which of your application's models should be editable in the @@ -569,8 +570,8 @@ subclass:: .. image:: _images/users_changelist.png - ``list_filter`` should be a list of elements, where each element should be - of one of the following types: + ``list_filter`` should be a list or tuple of elements, where each element + should be of one of the following types: * a field name, where the specified field should be either a ``BooleanField``, ``CharField``, ``DateField``, ``DateTimeField``, @@ -815,15 +816,36 @@ subclass:: By default the admin shows all fields as editable. Any fields in this option (which should be a ``list`` or ``tuple``) will display its data - as-is and non-editable. This option behaves nearly identical to - :attr:`ModelAdmin.list_display`. Usage is the same, however, when you - specify :attr:`ModelAdmin.fields` or :attr:`ModelAdmin.fieldsets` the - read-only fields must be present to be shown (they are ignored otherwise). + as-is and non-editable; they are also excluded from the + :class:`~django.forms.ModelForm` used for creating and editing. Note that + when specifying :attr:`ModelAdmin.fields` or :attr:`ModelAdmin.fieldsets` + the read-only fields must be present to be shown (they are ignored + otherwise). If ``readonly_fields`` is used without defining explicit ordering through :attr:`ModelAdmin.fields` or :attr:`ModelAdmin.fieldsets` they will be added last after all editable fields. + A read-only field can not only display data from a model's field, it can + also display the output of a a model's method or a method of the + ``ModelAdmin`` class itself. This is very similar to the way + :attr:`ModelAdmin.list_display` behaves. This provides an easy way to use + the admin interface to provide feedback on the status of the objects being + edited, for example:: + + class PersonAdmin(ModelAdmin): + readonly_fields = ('address_report',) + + def address_report(self, instance): + return ", ".join(instance.get_full_address()) or \ + "<span class='errors'>I can't determine this address.</span>" + + # short_description functions like a model field's verbose_name + address_report.short_description = "Address" + # in this example, we have used HTML tags in the output + address_report.allow_tags = True + + .. attribute:: ModelAdmin.save_as Set ``save_as`` to enable a "save as" feature on admin change forms. @@ -1054,6 +1076,14 @@ templates used by the :class:`ModelAdmin` views: changelist that will be linked to the change view, as described in the :attr:`ModelAdmin.list_display_links` section. +.. method:: ModelAdmin.get_list_filter(self, request) + + .. versionadded:: 1.5 + + The ``get_list_filter`` method is given the ``HttpRequest`` and is expected + to return the same kind of sequence type as for the + :attr:`~ModelAdmin.list_filter` attribute. + .. method:: ModelAdmin.get_inline_instances(self, request, obj=None) .. versionadded:: 1.5 @@ -1213,10 +1243,39 @@ templates used by the :class:`ModelAdmin` views: .. method:: ModelAdmin.get_changelist(self, request, **kwargs) - Returns the Changelist class to be used for listing. By default, + Returns the ``Changelist`` class to be used for listing. By default, ``django.contrib.admin.views.main.ChangeList`` is used. By inheriting this class you can change the behavior of the listing. +.. method:: ModelAdmin.get_changelist_form(self, request, **kwargs) + + Returns a :class:`~django.forms.ModelForm` class for use in the ``Formset`` + on the changelist page. To use a custom form, for example:: + + class MyForm(forms.ModelForm): + class Meta: + model = MyModel + + class MyModelAdmin(admin.ModelAdmin): + def get_changelist_form(self, request, **kwargs): + return MyForm + +.. method:: ModelAdmin.get_changelist_formset(self, request, **kwargs) + + Returns a :ref:`ModelFormSet <model-formsets>` class for use on the + changelist page if :attr:`~ModelAdmin.list_editable` is used. To use a + custom formset, for example:: + + from django.forms.models import BaseModelFormSet + + class MyAdminFormSet(BaseModelFormSet): + pass + + class MyModelAdmin(admin.ModelAdmin): + def get_changelist_formset(self, request, **kwargs): + kwargs['formset'] = MyAdminFormSet + return super(MyModelAdmin, self).get_changelist_formset(request, **kwargs) + .. method:: ModelAdmin.has_add_permission(self, request) Should return ``True`` if adding an object is permitted, ``False`` @@ -1252,11 +1311,19 @@ templates used by the :class:`ModelAdmin` views: return qs return qs.filter(author=request.user) -.. method:: ModelAdmin.message_user(request, message) +.. method:: ModelAdmin.message_user(request, message, level=messages.INFO, extra_tags='', fail_silently=False) + + Sends a message to the user using the :mod:`django.contrib.messages` + backend. See the :ref:`custom ModelAdmin example <custom-admin-action>`. + + .. versionadded:: 1.5 - Sends a message to the user. The default implementation creates a message - using the :mod:`django.contrib.messages` backend. See the - :ref:`custom ModelAdmin example <custom-admin-action>`. + Keyword arguments allow you to change the message level, add extra CSS + tags, or fail silently if the ``contrib.messages`` framework is not + installed. These keyword arguments match those for + :func:`django.contrib.messages.add_message`, see that function's + documentation for more details. One difference is that the level may be + passed as a string label in addition to integer/constant. .. method:: ModelAdmin.get_paginator(queryset, per_page, orphans=0, allow_empty_first_page=True) @@ -1326,6 +1393,8 @@ instances which allow you to easily customize the response data before rendering. For more details, see the :doc:`TemplateResponse documentation </ref/template-response>`. +.. _modeladmin-media-definitions: + ``ModelAdmin`` media definitions -------------------------------- @@ -1532,6 +1601,10 @@ The ``InlineModelAdmin`` class adds: Specifies whether or not inline objects can be deleted in the inline. Defaults to ``True``. +.. method:: InlineModelAdmin.get_formset(self, request, obj=None, **kwargs) + + Returns a ``BaseInlineFormSet`` class for use in admin add/change views. + See the example for :class:`ModelAdmin.get_formsets`. Working with a model with two or more foreign keys to the same parent model --------------------------------------------------------------------------- diff --git a/docs/ref/contrib/comments/index.txt b/docs/ref/contrib/comments/index.txt index 1c6ff7c7ed..8275092d2f 100644 --- a/docs/ref/contrib/comments/index.txt +++ b/docs/ref/contrib/comments/index.txt @@ -11,12 +11,6 @@ Django includes a simple, yet customizable comments framework. The built-in comments framework can be used to attach comments to any model, so you can use it for comments on blog entries, photos, book chapters, or anything else. -.. note:: - - If you used to use Django's older (undocumented) comments framework, you'll - need to upgrade. See the :doc:`upgrade guide </ref/contrib/comments/upgrade>` - for instructions. - Quick start guide ================= @@ -209,7 +203,7 @@ default version of which is included with Django. Rendering a custom comment form ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If you want more control over the look and feel of the comment form, you use use +If you want more control over the look and feel of the comment form, you may use :ttag:`get_comment_form` to get a :doc:`form object </topics/forms/index>` that you can use in the template:: @@ -350,7 +344,6 @@ More information models settings signals - upgrade custom forms moderation diff --git a/docs/ref/contrib/comments/signals.txt b/docs/ref/contrib/comments/signals.txt index 9d7c435927..8274539ed7 100644 --- a/docs/ref/contrib/comments/signals.txt +++ b/docs/ref/contrib/comments/signals.txt @@ -20,8 +20,8 @@ Sent just before a comment will be saved, after it's been sanity checked and submitted. This can be used to modify the comment (in place) with posting details or other such actions. -If any receiver returns ``False`` the comment will be discarded and a 403 (not -allowed) response will be returned. +If any receiver returns ``False`` the comment will be discarded and a 400 +response will be returned. This signal is sent at more or less the same time (just before, actually) as the ``Comment`` object's :data:`~django.db.models.signals.pre_save` signal. diff --git a/docs/ref/contrib/comments/upgrade.txt b/docs/ref/contrib/comments/upgrade.txt deleted file mode 100644 index dadb53f5fa..0000000000 --- a/docs/ref/contrib/comments/upgrade.txt +++ /dev/null @@ -1,78 +0,0 @@ -=============================================== -Upgrading from Django's previous comment system -=============================================== - -Prior versions of Django included an outdated, undocumented comment system. Users who reverse-engineered this framework will need to upgrade to use the -new comment system; this guide explains how. - -The main changes from the old system are: - -* This new system is documented. - -* It uses modern Django features like :doc:`forms </topics/forms/index>` and - :doc:`modelforms </topics/forms/modelforms>`. - -* It has a single ``Comment`` model instead of separate ``FreeComment`` and - ``Comment`` models. - -* Comments have "email" and "URL" fields. - -* No ratings, photos and karma. This should only effect World Online. - -* The ``{% comment_form %}`` tag no longer exists. Instead, there's now two - functions: ``{% get_comment_form %}``, which returns a form for posting a - new comment, and ``{% render_comment_form %}``, which renders said form - using the ``comments/form.html`` template. - -* The way comments are include in your URLconf have changed; you'll need to - replace:: - - (r'^comments/', include('django.contrib.comments.urls.comments')), - - with:: - - (r'^comments/', include('django.contrib.comments.urls')), - -Upgrading data --------------- - -The data models for Django's comment system have changed, as have the -table names. Before you transfer your existing data into the new comments -system, make sure that you have installed the new comments system as -explained in the -:doc:`quick start guide </ref/contrib/comments/index>`. -This will ensure that the new tables have been properly created. - -To transfer your data into the new comments system, you'll need to directly -run the following SQL: - -.. code-block:: sql - - BEGIN; - - INSERT INTO django_comments - (content_type_id, object_pk, site_id, user_name, user_email, user_url, - comment, submit_date, ip_address, is_public, is_removed) - SELECT - content_type_id, object_id, site_id, person_name, '', '', comment, - submit_date, ip_address, is_public, not approved - FROM comments_freecomment; - - INSERT INTO django_comments - (content_type_id, object_pk, site_id, user_id, user_name, user_email, - user_url, comment, submit_date, ip_address, is_public, is_removed) - SELECT - content_type_id, object_id, site_id, user_id, '', '', '', comment, - submit_date, ip_address, is_public, is_removed - FROM comments_comment; - - UPDATE django_comments SET user_name = ( - SELECT username FROM auth_user - WHERE django_comments.user_id = auth_user.id - ) WHERE django_comments.user_id is not NULL; - UPDATE django_comments SET user_email = ( - SELECT email FROM auth_user - WHERE django_comments.user_id = auth_user.id - ) WHERE django_comments.user_id is not NULL; - - COMMIT; diff --git a/docs/ref/contrib/formtools/form-wizard.txt b/docs/ref/contrib/formtools/form-wizard.txt index 0ced1bf155..3edc019d05 100644 --- a/docs/ref/contrib/formtools/form-wizard.txt +++ b/docs/ref/contrib/formtools/form-wizard.txt @@ -493,6 +493,21 @@ Advanced ``WizardView`` methods context = self.get_context_data(form=form, **kwargs) return self.render_to_response(context) +.. method:: WizardView.get_cleaned_data_for_step(step) + + This method returns the cleaned data for a given ``step``. Before returning + the cleaned data, the stored values are revalidated through the form. If + the data doesn't validate, ``None`` will be returned. + +.. method:: WizardView.get_all_cleaned_data() + + This method returns a merged dictionary of all form steps' ``cleaned_data`` + dictionaries. If a step contains a ``FormSet``, the key will be prefixed + with ``formset-`` and contain a list of the formset's ``cleaned_data`` + dictionaries. Note that if two or more steps have a field with the same + name, the value for that field from the latest step will overwrite the + value from any earlier steps. + Providing initial data for the forms ==================================== @@ -534,6 +549,16 @@ This storage will temporarily store the uploaded files for the wizard. The :attr:`file_storage` attribute should be a :class:`~django.core.files.storage.Storage` subclass. +Django provides a built-in storage class (see :ref:`the built-in filesystem +storage class <builtin-fs-storage>`):: + + from django.conf import settings + from django.core.files.storage import FileSystemStorage + + class CustomWizardView(WizardView): + ... + file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'photos')) + .. warning:: Please remember to take care of removing old files as the @@ -622,8 +647,11 @@ Usage of ``NamedUrlWizardView`` .. class:: NamedUrlWizardView -There is a :class:`WizardView` subclass which adds named-urls support to the wizard. -By doing this, you can have single urls for every step. +There is a :class:`WizardView` subclass which adds named-urls support to the +wizard. By doing this, you can have single urls for every step. You can also +use the :class:`NamedUrlSessionWizardView` or :class:`NamedUrlCookieWizardView` +classes which preselect the backend used for storing information (server-side +sessions and browser cookies respectively). To use the named urls, you have to change the ``urls.py``. diff --git a/docs/ref/contrib/gis/geos.txt b/docs/ref/contrib/gis/geos.txt index eb20b1f411..7d7c32781c 100644 --- a/docs/ref/contrib/gis/geos.txt +++ b/docs/ref/contrib/gis/geos.txt @@ -656,6 +656,17 @@ is returned instead. Returns the number of interior rings in this geometry. +.. admonition:: Comparing Polygons + + Note that it is possible to compare ``Polygon`` objects directly with ``<`` + or ``>``, but as the comparison is made through Polygon's + :class:`LineString`, it does not mean much (but is consistent and quick). + You can always force the comparison with the :attr:`~GEOSGeometry.area` + property:: + + >>> if poly_1.area > poly_2.area: + >>> pass + Geometry Collections ==================== diff --git a/docs/ref/contrib/gis/install/index.txt b/docs/ref/contrib/gis/install/index.txt index c710866813..100dc2edd0 100644 --- a/docs/ref/contrib/gis/install/index.txt +++ b/docs/ref/contrib/gis/install/index.txt @@ -118,7 +118,7 @@ Invoke the Django shell from your project and execute the .. code-block:: pycon - $ python manage shell + $ python manage.py shell >>> from django.contrib.gis.utils import add_srs_entry >>> add_srs_entry(900913) diff --git a/docs/ref/contrib/gis/tutorial.txt b/docs/ref/contrib/gis/tutorial.txt index ec265342b3..5000622ad4 100644 --- a/docs/ref/contrib/gis/tutorial.txt +++ b/docs/ref/contrib/gis/tutorial.txt @@ -5,28 +5,28 @@ GeoDjango Tutorial Introduction ============ -GeoDjango is an add-on for Django that turns it into a world-class geographic -Web framework. GeoDjango strives to make it as simple as possible to create -geographic Web applications, like location-based services. Some features -include: +GeoDjango is an included contrib module for Django that turns it into a +world-class geographic Web framework. GeoDjango strives to make it as simple +as possible to create geographic Web applications, like location-based services. +Its features include: * Django model fields for `OGC`_ geometries. -* Extensions to Django's ORM for the querying and manipulation of spatial data. +* Extensions to Django's ORM for querying and manipulating spatial data. * Loosely-coupled, high-level Python interfaces for GIS geometry operations and data formats. -* Editing of geometry fields inside the admin. +* Editing geometry fields from the admin. -This tutorial assumes a familiarity with Django; thus, if you're brand new to -Django please read through the :doc:`regular tutorial </intro/tutorial01>` to -introduce yourself with basic Django concepts. +This tutorial assumes familiarity with Django; thus, if you're brand new to +Django, please read through the :doc:`regular tutorial </intro/tutorial01>` to +familiarize yourself with Django first. .. note:: - GeoDjango has special prerequisites overwhat is required by Django -- + GeoDjango has additional requirements beyond what Django requires -- please consult the :ref:`installation documentation <ref-gis-install>` for more details. -This tutorial will guide you through the creation of a geographic Web +This tutorial will guide you through the creation of a geographic web application for viewing the `world borders`_. [#]_ Some of the code used in this tutorial is taken from and/or inspired by the `GeoDjango basic apps`_ project. [#]_ @@ -51,10 +51,10 @@ Create a Spatial Database MySQL and Oracle users can skip this section because spatial types are already built into the database. -First, a spatial database needs to be created for our project. If using -PostgreSQL and PostGIS, then the following commands will -create the database from a :ref:`spatial database template -<spatialdb_template>`: +First, create a spatial database for your project. + +If you are using PostGIS, create the database from the :ref:`spatial database +template <spatialdb_template>`: .. code-block:: bash @@ -62,9 +62,9 @@ create the database from a :ref:`spatial database template .. note:: - This command must be issued by a database user that has permissions to - create a database. Here is an example set of commands to create such - a user: + This command must be issued by a database user with enough privileges to + create a database. To create a user with ``CREATE DATABASE`` privileges in + PostgreSQL, use the following commands: .. code-block:: bash @@ -72,25 +72,24 @@ create the database from a :ref:`spatial database template $ createuser --createdb geo $ exit - Replace ``geo`` with the system login user name that will be - connecting to the database. For example, ``johndoe`` if that is the - system user that will be running GeoDjango. + Replace ``geo`` with your Postgres database user's username. + (In PostgreSQL, this user will also be an OS-level user.) -Users of SQLite and SpatiaLite should consult the instructions on how +If you are using SQLite and SpatiaLite, consult the instructions on how to create a :ref:`SpatiaLite database <create_spatialite_db>`. -Create GeoDjango Project +Create a New Project ------------------------ -Use the ``django-admin.py`` script like normal to create a ``geodjango`` -project: +Use the standard ``django-admin.py`` script to create a project called +``geodjango``: .. code-block:: bash $ django-admin.py startproject geodjango -With the project initialized, now create a ``world`` Django application within -the ``geodjango`` project: +This will initialize a new project. Now, create a ``world`` Django application +within the ``geodjango`` project: .. code-block:: bash @@ -101,7 +100,7 @@ Configure ``settings.py`` ------------------------- The ``geodjango`` project settings are stored in the ``geodjango/settings.py`` -file. Edit the database connection settings appropriately:: +file. Edit the database connection settings to match your setup:: DATABASES = { 'default': { @@ -113,7 +112,7 @@ file. Edit the database connection settings appropriately:: In addition, modify the :setting:`INSTALLED_APPS` setting to include :mod:`django.contrib.admin`, :mod:`django.contrib.gis`, -and ``world`` (our newly created application):: +and ``world`` (your newly created application):: INSTALLED_APPS = ( 'django.contrib.auth', @@ -135,9 +134,9 @@ Geographic Data World Borders ------------- -The world borders data is available in this `zip file`__. Create a data +The world borders data is available in this `zip file`__. Create a ``data`` directory in the ``world`` application, download the world borders data, and -unzip. On GNU/Linux platforms the following commands should do it: +unzip. On GNU/Linux platforms, use the following commands: .. code-block:: bash @@ -149,7 +148,7 @@ unzip. On GNU/Linux platforms the following commands should do it: The world borders ZIP file contains a set of data files collectively known as an `ESRI Shapefile`__, one of the most popular geospatial data formats. When -unzipped the world borders data set includes files with the following +unzipped, the world borders dataset includes files with the following extensions: * ``.shp``: Holds the vector data for the world borders geometries. @@ -165,8 +164,8 @@ __ http://en.wikipedia.org/wiki/Shapefile Use ``ogrinfo`` to examine spatial data --------------------------------------- -The GDAL ``ogrinfo`` utility is excellent for examining metadata about -shapefiles (or other vector data sources): +The GDAL ``ogrinfo`` utility allows examining the metadata of shapefiles or +other vector data sources: .. code-block:: bash @@ -175,9 +174,9 @@ shapefiles (or other vector data sources): using driver `ESRI Shapefile' successful. 1: TM_WORLD_BORDERS-0.3 (Polygon) -Here ``ogrinfo`` is telling us that the shapefile has one layer, and that such -layer contains polygon data. To find out more we'll specify the layer name -and use the ``-so`` option to get only important summary information: +``ogrinfo`` tells us that the shapefile has one layer, and that this +layer contains polygon data. To find out more, we'll specify the layer name +and use the ``-so`` option to get only the important summary information: .. code-block:: bash @@ -208,14 +207,11 @@ and use the ``-so`` option to get only important summary information: LAT: Real (7.3) This detailed summary information tells us the number of features in the layer -(246), the geographical extent, the spatial reference system ("SRS WKT"), -as well as detailed information for each attribute field. For example, -``FIPS: String (2.0)`` indicates that there's a ``FIPS`` character field -with a maximum length of 2; similarly, ``LON: Real (8.3)`` is a floating-point -field that holds a maximum of 8 digits up to three decimal places. Although -this information may be found right on the `world borders`_ Web site, this -shows you how to determine this information yourself when such metadata is not -provided. +(246), the geographic bounds of the data, the spatial reference system +("SRS WKT"), as well as type information for each attribute field. For example, +``FIPS: String (2.0)`` indicates that the ``FIPS`` character field has +a maximum length of 2. Similarly, ``LON: Real (8.3)`` is a floating-point +field that holds a maximum of 8 digits up to three decimal places. Geographic Models ================= @@ -223,8 +219,8 @@ Geographic Models Defining a Geographic Model --------------------------- -Now that we've examined our world borders data set using ``ogrinfo``, we can -create a GeoDjango model to represent this data:: +Now that you've examined your dataset using ``ogrinfo``, create a GeoDjango +model to represent this data:: from django.contrib.gis.db import models @@ -252,32 +248,30 @@ create a GeoDjango model to represent this data:: def __unicode__(self): return self.name -Two important things to note: +Please note two important things: 1. The ``models`` module is imported from :mod:`django.contrib.gis.db`. -2. The model overrides its default manager with - :class:`~django.contrib.gis.db.models.GeoManager`; this is *required* - to perform spatial queries. +2. You must override the model's default manager with + :class:`~django.contrib.gis.db.models.GeoManager` to perform spatial queries. -When declaring a geometry field on your model the default spatial reference -system is WGS84 (meaning the `SRID`__ is 4326) -- in other words, the field -coordinates are in longitude/latitude pairs in units of degrees. If you want -the coordinate system to be different, then SRID of the geometry field may be -customized by setting the ``srid`` with an integer corresponding to the -coordinate system of your choice. +The default spatial reference system for geometry fields is WGS84 (meaning +the `SRID`__ is 4326) -- in other words, the field coordinates are in +longitude, latitude pairs in units of degrees. To use a different +coordinate system, set the SRID of the geometry field with the ``srid`` +argument. Use an integer representing the coordinate system's EPSG code. __ http://en.wikipedia.org/wiki/SRID Run ``syncdb`` -------------- -After you've defined your model, it needs to be synced with the spatial -database. First, let's look at the SQL that will generate the table for the +After defining your model, you need to sync it with the database. First, +let's look at the SQL that will generate the table for the ``WorldBorder`` model:: $ python manage.py sqlall world -This management command should produce the following output: +This command should produce the following output: .. code-block:: sql @@ -302,32 +296,28 @@ This management command should produce the following output: CREATE INDEX "world_worldborder_mpoly_id" ON "world_worldborder" USING GIST ( "mpoly" GIST_GEOMETRY_OPS ); COMMIT; -If satisfied, you may then create this table in the database by running the -``syncdb`` management command:: +If this looks correct, run ``syncdb`` to create this table in the database:: $ python manage.py syncdb Creating table world_worldborder Installing custom SQL for world.WorldBorder model -The ``syncdb`` command may also prompt you to create an admin user; go ahead -and do so (not required now, may be done at any point in the future using the -``createsuperuser`` management command). +The ``syncdb`` command may also prompt you to create an admin user. Either +do so now, or later by running ``django-admin.py createsuperuser``. Importing Spatial Data ====================== -This section will show you how to take the data from the world borders -shapefile and import it into GeoDjango models using the +This section will show you how to import the world borders +shapefile into the database via GeoDjango models using the :ref:`ref-layermapping`. -There are many different ways to import data in to a spatial database -- -besides the tools included within GeoDjango, you may also use the following to -populate your spatial database: +There are many different ways to import data into a spatial database -- +besides the tools included within GeoDjango, you may also use the following: -* `ogr2ogr`_: Command-line utility, included with GDAL, that - supports loading a multitude of vector data formats into - the PostGIS, MySQL, and Oracle spatial databases. -* `shp2pgsql`_: This utility is included with PostGIS and only supports - ESRI shapefiles. +* `ogr2ogr`_: A command-line utility included with GDAL that + can import many vector data formats into PostGIS, MySQL, and Oracle databases. +* `shp2pgsql`_: This utility included with PostGIS imports ESRI shapefiles into + PostGIS. .. _ogr2ogr: http://www.gdal.org/ogr2ogr.html .. _shp2pgsql: http://postgis.refractions.net/documentation/manual-1.5/ch04.html#shp2pgsql_usage @@ -337,10 +327,9 @@ populate your spatial database: GDAL Interface -------------- -Earlier we used the ``ogrinfo`` to explore the contents of the world borders -shapefile. Included within GeoDjango is an interface to GDAL's powerful OGR -library -- in other words, you'll be able explore all the vector data sources -that OGR supports via a Pythonic API. +Earlier, you used ``ogrinfo`` to examine the contents of the world borders +shapefile. GeoDjango also includes a Pythonic interface to GDAL's powerful OGR +library that can work with all the vector data sources that OGR supports. First, invoke the Django shell: @@ -348,8 +337,8 @@ First, invoke the Django shell: $ python manage.py shell -If the :ref:`worldborders` data was downloaded like earlier in the -tutorial, then we can determine the path using Python's built-in +If you downloaded the :ref:`worldborders` data earlier in the +tutorial, then you can determine its path using Python's built-in ``os`` module:: >>> import os @@ -357,7 +346,7 @@ tutorial, then we can determine the path using Python's built-in >>> world_shp = os.path.abspath(os.path.join(os.path.dirname(world.__file__), ... 'data/TM_WORLD_BORDERS-0.3.shp')) -Now, the world borders shapefile may be opened using GeoDjango's +Now, open the world borders shapefile using GeoDjango's :class:`~django.contrib.gis.gdal.DataSource` interface:: >>> from django.contrib.gis.gdal import DataSource @@ -374,8 +363,7 @@ shapefiles are only allowed to have one layer:: >>> print(lyr) TM_WORLD_BORDERS-0.3 -You can see what the geometry type of the layer is and how many features it -contains:: +You can see the layer's geometry type and how many features it contains:: >>> print(lyr.geom_type) Polygon @@ -384,16 +372,16 @@ contains:: .. note:: - Unfortunately the shapefile data format does not allow for greater + Unfortunately, the shapefile data format does not allow for greater specificity with regards to geometry types. This shapefile, like - many others, actually includes ``MultiPolygon`` geometries in its - features. You need to watch out for this when creating your models - as a GeoDjango ``PolygonField`` will not accept a ``MultiPolygon`` - type geometry -- thus a ``MultiPolygonField`` is used in our model's - definition instead. + many others, actually includes ``MultiPolygon`` geometries, not Polygons. + It's important to use a more general field type in models: a + GeoDjango ``MultiPolygonField`` will accept a ``Polygon`` geometry, but a + ``PolygonField`` will not accept a ``MultiPolygon`` type geometry. This + is why the ``WorldBorder`` model defined above uses a ``MultiPolygonField``. The :class:`~django.contrib.gis.gdal.Layer` may also have a spatial reference -system associated with it -- if it does, the ``srs`` attribute will return a +system associated with it. If it does, the ``srs`` attribute will return a :class:`~django.contrib.gis.gdal.SpatialReference` object:: >>> srs = lyr.srs @@ -406,9 +394,9 @@ system associated with it -- if it does, the ``srs`` attribute will return a >>> srs.proj4 # PROJ.4 representation '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs ' -Here we've noticed that the shapefile is in the popular WGS84 spatial reference -system -- in other words, the data uses units of degrees longitude and -latitude. +This shapefile is in the popular WGS84 spatial reference +system -- in other words, the data uses longitude, latitude pairs in +units of degrees. In addition, shapefiles also support attribute fields that may contain additional data. Here are the fields on the World Borders layer: @@ -416,8 +404,8 @@ additional data. Here are the fields on the World Borders layer: >>> print(lyr.fields) ['FIPS', 'ISO2', 'ISO3', 'UN', 'NAME', 'AREA', 'POP2005', 'REGION', 'SUBREGION', 'LON', 'LAT'] -Here we are examining the OGR types (e.g., whether a field is an integer or -a string) associated with each of the fields: +The following code will let you examine the OGR types (e.g. integer or +string) associated with each of the fields: >>> [fld.__name__ for fld in lyr.field_types] ['OFTString', 'OFTString', 'OFTString', 'OFTInteger', 'OFTString', 'OFTInteger', 'OFTInteger', 'OFTInteger', 'OFTInteger', 'OFTReal', 'OFTReal'] @@ -446,8 +434,7 @@ And individual features may be retrieved by their feature ID:: >>> print(feat.get('NAME')) San Marino -Here the boundary geometry for San Marino is extracted and looking -exported to WKT and GeoJSON:: +Boundary geometries may be exported as WKT and GeoJSON:: >>> geom = feat.geom >>> print(geom.wkt) @@ -459,8 +446,9 @@ exported to WKT and GeoJSON:: ``LayerMapping`` ---------------- -We're going to dive right in -- create a file called ``load.py`` inside the -``world`` application, and insert the following:: +To import the data, use a LayerMapping in a Python script. +Create a file called ``load.py`` inside the ``world`` application, +with the following code:: import os from django.contrib.gis.utils import LayerMapping @@ -492,20 +480,20 @@ We're going to dive right in -- create a file called ``load.py`` inside the A few notes about what's going on: * Each key in the ``world_mapping`` dictionary corresponds to a field in the - ``WorldBorder`` model, and the value is the name of the shapefile field + ``WorldBorder`` model. The value is the name of the shapefile field that data will be loaded from. * The key ``mpoly`` for the geometry field is ``MULTIPOLYGON``, the - geometry type we wish to import as. Even if simple polygons are encountered - in the shapefile they will automatically be converted into collections prior - to insertion into the database. + geometry type GeoDjango will import the field as. Even simple polygons in + the shapefile will automatically be converted into collections prior to + insertion into the database. * The path to the shapefile is not absolute -- in other words, if you move the ``world`` application (with ``data`` subdirectory) to a different location, - then the script will still work. + the script will still work. * The ``transform`` keyword is set to ``False`` because the data in the shapefile does not need to be converted -- it's already in WGS84 (SRID=4326). -* The ``encoding`` keyword is set to the character encoding of string values in - the shapefile. This ensures that string values are read and saved correctly - from their original encoding system. +* The ``encoding`` keyword is set to the character encoding of the string + values in the shapefile. This ensures that string values are read and saved + correctly from their original encoding system. Afterwards, invoke the Django shell from the ``geodjango`` project directory: @@ -513,8 +501,8 @@ Afterwards, invoke the Django shell from the ``geodjango`` project directory: $ python manage.py shell -Next, import the ``load`` module, call the ``run`` routine, and watch ``LayerMapping`` -do the work:: +Next, import the ``load`` module, call the ``run`` routine, and watch +``LayerMapping`` do the work:: >>> from world import load >>> load.run() @@ -536,7 +524,7 @@ The general usage of the command goes as follows: $ python manage.py ogrinspect [options] <data_source> <model_name> [options] -Where ``data_source`` is the path to the GDAL-supported data source and +``data_source`` is the path to the GDAL-supported data source and ``model_name`` is the name to use for the model. Command-line options may be used to further define how the model is generated. @@ -600,9 +588,9 @@ Spatial Queries Spatial Lookups --------------- -GeoDjango extends the Django ORM and allows the use of spatial lookups. -Let's do an example where we find the ``WorldBorder`` model that contains -a point. First, fire up the management shell: +GeoDjango adds spatial lookups to the Django ORM. For example, you +can find the country in the ``WorldBorder`` table that contains +a particular point. First, fire up the management shell: .. code-block:: bash @@ -613,8 +601,8 @@ Now, define a point of interest [#]_:: >>> pnt_wkt = 'POINT(-95.3385 29.7245)' The ``pnt_wkt`` string represents the point at -95.3385 degrees longitude, -and 29.7245 degrees latitude. The geometry is in a format known as -Well Known Text (WKT), an open standard issued by the Open Geospatial +29.7245 degrees latitude. The geometry is in a format known as +Well Known Text (WKT), a standard issued by the Open Geospatial Consortium (OGC). [#]_ Import the ``WorldBorder`` model, and perform a ``contains`` lookup using the ``pnt_wkt`` as the parameter:: @@ -623,11 +611,13 @@ a ``contains`` lookup using the ``pnt_wkt`` as the parameter:: >>> qs [<WorldBorder: United States>] -Here we retrieved a ``GeoQuerySet`` that has only one model: the one -for the United States (which is what we would expect). Similarly, -a :ref:`GEOS geometry object <ref-geos>` may also be used -- here the -``intersects`` spatial lookup is combined with the ``get`` method to retrieve -only the ``WorldBorder`` instance for San Marino instead of a queryset:: +Here, you retrieved a ``GeoQuerySet`` with only one model: the border of +the United States (exactly what you would expect). + +Similarly, you may also use a :ref:`GEOS geometry object <ref-geos>`. +Here, you can combine the ``intersects`` spatial lookup with the ``get`` +method to retrieve only the ``WorldBorder`` instance for San Marino instead +of a queryset:: >>> from django.contrib.gis.geos import Point >>> pnt = Point(12.4604, 43.9420) @@ -635,16 +625,16 @@ only the ``WorldBorder`` instance for San Marino instead of a queryset:: >>> sm <WorldBorder: San Marino> -The ``contains`` and ``intersects`` lookups are just a subset of what's -available -- the :ref:`ref-gis-db-api` documentation has more. +The ``contains`` and ``intersects`` lookups are just a subset of the +available queries -- the :ref:`ref-gis-db-api` documentation has more. Automatic Spatial Transformations --------------------------------- -When querying the spatial database GeoDjango automatically transforms +When doing spatial queries, GeoDjango automatically transforms geometries if they're in a different coordinate system. In the following -example, the coordinate will be expressed in terms of `EPSG SRID 32140`__, +example, coordinates will be expressed in `EPSG SRID 32140`__, a coordinate system specific to south Texas **only** and in units of -**meters** and not degrees:: +**meters**, not degrees:: >>> from django.contrib.gis.geos import Point, GEOSGeometry >>> pnt = Point(954158.1, 4215137.1, srid=32140) @@ -654,7 +644,7 @@ WKT that includes the SRID:: >>> pnt = GEOSGeometry('SRID=32140;POINT(954158.1 4215137.1)') -When using GeoDjango's ORM, it will automatically wrap geometry values +GeoDjango's ORM will automatically wrap geometry values in transformation SQL, allowing the developer to work at a higher level of abstraction:: @@ -675,7 +665,7 @@ __ http://spatialreference.org/ref/epsg/32140/ When using :doc:`raw queries </topics/db/sql>`, you should generally wrap your geometry fields with the ``asText()`` SQL function (or ``ST_AsText`` - for PostGIS) so as the field value will be recognized by GEOS:: + for PostGIS) so that the field value will be recognized by GEOS:: City.objects.raw('SELECT id, name, asText(point) from myapp_city') @@ -684,8 +674,8 @@ __ http://spatialreference.org/ref/epsg/32140/ Lazy Geometries --------------- -Geometries come to GeoDjango in a standardized textual representation. Upon -access of the geometry field, GeoDjango creates a `GEOS geometry object +GeoDjango loads geometries in a standardized textual representation. When the +geometry field is first accessed, GeoDjango creates a `GEOS geometry object <ref-geos>`, exposing powerful functionality, such as serialization properties for popular geospatial formats:: @@ -715,14 +705,11 @@ the GEOS library:: Putting your data on the map ============================ -Google ------- - Geographic Admin ---------------- GeoDjango extends :doc:`Django's admin application </ref/contrib/admin/index>` -to enable support for editing geometry fields. +with support for editing geometry fields. Basics ^^^^^^ @@ -730,16 +717,15 @@ Basics GeoDjango also supplements the Django admin by allowing users to create and modify geometries on a JavaScript slippy map (powered by `OpenLayers`_). -Let's dive in again -- create a file called ``admin.py`` inside the -``world`` application, and insert the following:: +Let's dive right in. Create a file called ``admin.py`` inside the +``world`` application with the following code:: from django.contrib.gis import admin from models import WorldBorder admin.site.register(WorldBorder, admin.GeoModelAdmin) -Next, edit your ``urls.py`` in the ``geodjango`` application folder to look -as follows:: +Next, edit your ``urls.py`` in the ``geodjango`` application folder as follows:: from django.conf.urls import patterns, url, include from django.contrib.gis import admin @@ -775,9 +761,9 @@ With the :class:`~django.contrib.gis.admin.OSMGeoAdmin`, GeoDjango uses a `Open Street Map`_ layer in the admin. This provides more context (including street and thoroughfare details) than available with the :class:`~django.contrib.gis.admin.GeoModelAdmin` -(which uses the `Vector Map Level 0`_ WMS data set hosted at `OSGeo`_). +(which uses the `Vector Map Level 0`_ WMS dataset hosted at `OSGeo`_). -First, there are some important requirements and limitations: +First, there are some important requirements: * :class:`~django.contrib.gis.admin.OSMGeoAdmin` requires that the :ref:`spherical mercator projection be added <addgoogleprojection>` @@ -785,14 +771,19 @@ First, there are some important requirements and limitations: * The PROJ.4 datum shifting files must be installed (see the :ref:`PROJ.4 installation instructions <proj4>` for more details). -If you meet these requirements, then just substitute in the ``OSMGeoAdmin`` +If you meet these requirements, then just substitute the ``OSMGeoAdmin`` option class in your ``admin.py`` file:: admin.site.register(WorldBorder, admin.OSMGeoAdmin) .. rubric:: Footnotes -.. [#] Special thanks to Bjørn Sandvik of `thematicmapping.org <http://thematicmapping.org>`_ for providing and maintaining this data set. -.. [#] GeoDjango basic apps was written by Dane Springmeyer, Josh Livni, and Christopher Schmidt. -.. [#] Here the point is for the `University of Houston Law Center <http://www.law.uh.edu/>`_. -.. [#] Open Geospatial Consortium, Inc., `OpenGIS Simple Feature Specification For SQL <http://www.opengeospatial.org/standards/sfs>`_. +.. [#] Special thanks to Bjørn Sandvik of `thematicmapping.org + <http://thematicmapping.org>`_ for providing and maintaining this + dataset. +.. [#] GeoDjango basic apps was written by Dane Springmeyer, Josh Livni, and + Christopher Schmidt. +.. [#] This point is the `University of Houston Law Center + <http://www.law.uh.edu/>`_. +.. [#] Open Geospatial Consortium, Inc., `OpenGIS Simple Feature Specification + For SQL <http://www.opengeospatial.org/standards/sfs>`_. diff --git a/docs/ref/contrib/messages.txt b/docs/ref/contrib/messages.txt index bc921a9d33..4fa733edb5 100644 --- a/docs/ref/contrib/messages.txt +++ b/docs/ref/contrib/messages.txt @@ -341,7 +341,7 @@ This sets the minimum message that will be saved in the message storage. See MESSAGE_STORAGE --------------- -Default: ``'django.contrib.messages.storage.user_messages.FallbackStorage'`` +Default: ``'django.contrib.messages.storage.fallback.FallbackStorage'`` Controls where Django stores message data. Valid values are: diff --git a/docs/ref/contrib/sites.txt b/docs/ref/contrib/sites.txt index 790e003453..7e5448b3d3 100644 --- a/docs/ref/contrib/sites.txt +++ b/docs/ref/contrib/sites.txt @@ -127,8 +127,10 @@ For example:: def my_view(request): if settings.SITE_ID == 3: # Do something. + pass else: # Do something else. + pass Of course, it's ugly to hard-code the site IDs like that. This sort of hard-coding is best for hackish fixes that you need done quickly. The @@ -141,11 +143,13 @@ domain:: current_site = get_current_site(request) if current_site.domain == 'foo.com': # Do something + pass else: # Do something else. + pass -This has also the advantage of checking if the sites framework is installed, and -return a :class:`RequestSite` instance if it is not. +This has also the advantage of checking if the sites framework is installed, +and return a :class:`RequestSite` instance if it is not. If you don't have access to the request object, you can use the ``get_current()`` method of the :class:`~django.contrib.sites.models.Site` @@ -158,8 +162,10 @@ the :setting:`SITE_ID` setting. This example is equivalent to the previous one:: current_site = Site.objects.get_current() if current_site.domain == 'foo.com': # Do something + pass else: # Do something else. + pass Getting the current domain for display -------------------------------------- @@ -200,8 +206,8 @@ subscribing to LJWorld.com alerts." Same goes for the email's message body. Note that an even more flexible (but more heavyweight) way of doing this would be to use Django's template system. Assuming Lawrence.com and LJWorld.com have -different template directories (:setting:`TEMPLATE_DIRS`), you could simply farm out -to the template system like so:: +different template directories (:setting:`TEMPLATE_DIRS`), you could simply +farm out to the template system like so:: from django.core.mail import send_mail from django.template import loader, Context @@ -216,9 +222,9 @@ to the template system like so:: # ... -In this case, you'd have to create :file:`subject.txt` and :file:`message.txt` template -files for both the LJWorld.com and Lawrence.com template directories. That -gives you more flexibility, but it's also more complex. +In this case, you'd have to create :file:`subject.txt` and :file:`message.txt` +template files for both the LJWorld.com and Lawrence.com template directories. +That gives you more flexibility, but it's also more complex. It's a good idea to exploit the :class:`~django.contrib.sites.models.Site` objects as much as possible, to remove unneeded complexity and redundancy. @@ -240,6 +246,15 @@ To do this, you can use the sites framework. A simple example:: >>> 'http://%s%s' % (Site.objects.get_current().domain, obj.get_absolute_url()) 'http://example.com/mymodel/objects/3/' + +Default site and ``syncdb`` +=========================== + +``django.contrib.sites`` registers a +:data:`~django.db.models.signals.post_syncdb` signal handler which creates a +default site named ``example.com`` with the domain ``example.com``. For +example, this site will be created after Django creates the test database. + Caching the current ``Site`` object =================================== diff --git a/docs/ref/contrib/syndication.txt b/docs/ref/contrib/syndication.txt index 27b8fc0875..2418dba8ef 100644 --- a/docs/ref/contrib/syndication.txt +++ b/docs/ref/contrib/syndication.txt @@ -53,6 +53,7 @@ This simple example, taken from `chicagocrime.org`_, describes a feed of the latest five news items:: from django.contrib.syndication.views import Feed + from django.core.urlresolvers import reverse from chicagocrime.models import NewsItem class LatestEntriesFeed(Feed): @@ -69,6 +70,10 @@ latest five news items:: def item_description(self, item): return item.description + # item_link is only needed if NewsItem has no get_absolute_url method. + def item_link(self, item): + return reverse('news-item', args=[item.pk]) + To connect a URL to this feed, put an instance of the Feed object in your :doc:`URLconf </topics/http/urls>`. For example:: diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt index 3a52f838e7..352c0f4584 100644 --- a/docs/ref/databases.txt +++ b/docs/ref/databases.txt @@ -33,6 +33,11 @@ aggregate with a database backend that falls within the affected release range. .. _known to be faulty: http://archives.postgresql.org/pgsql-bugs/2007-07/msg00046.php .. _Release 8.2.5: http://www.postgresql.org/docs/devel/static/release-8-2-5.html +PostgreSQL connection settings +------------------------------- + +See :setting:`HOST` for details. + Optimizing PostgreSQL's configuration ------------------------------------- diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt index 7fa7539985..306db8439e 100644 --- a/docs/ref/django-admin.txt +++ b/docs/ref/django-admin.txt @@ -96,6 +96,9 @@ cleanup Can be run as a cronjob or directly to clean out old data from the database (only expired sessions at the moment). +.. versionchanged:: 1.5 + :djadmin:`cleanup` is deprecated. Use :djadmin:`clearsessions` instead. + compilemessages --------------- @@ -876,14 +879,19 @@ either the path to a directory with the app template file, or a path to a compressed file (``.tar.gz``, ``.tar.bz2``, ``.tgz``, ``.tbz``, ``.zip``) containing the app template files. +For example, this would look for an app template in the given directory when +creating the ``myapp`` app:: + + django-admin.py startapp --template=/Users/jezdez/Code/my_app_template myapp + Django will also accept URLs (``http``, ``https``, ``ftp``) to compressed archives with the app template files, downloading and extracting them on the fly. -For example, this would look for an app template in the given directory when -creating the ``myapp`` app:: +For example, taking advantage of Github's feature to expose repositories as +zip files, you can use a URL like:: - django-admin.py startapp --template=/Users/jezdez/Code/my_app_template myapp + django-admin.py startapp --template=https://github.com/githubuser/django-app-template/archive/master.zip myapp .. versionadded:: 1.4 @@ -951,6 +959,15 @@ when creating the ``myproject`` project:: django-admin.py startproject --template=/Users/jezdez/Code/my_project_template myproject +Django will also accept URLs (``http``, ``https``, ``ftp``) to compressed +archives with the project template files, downloading and extracting them on the +fly. + +For example, taking advantage of Github's feature to expose repositories as +zip files, you can use a URL like:: + + django-admin.py startproject --template=https://github.com/githubuser/django-project-template/archive/master.zip myproject + When Django copies the project template files, it also renders certain files through the template engine: the files whose extensions match the ``--extension`` option (``py`` by default) and the files whose names are passed @@ -1187,6 +1204,16 @@ This command is only available if :doc:`GeoDjango </ref/contrib/gis/index>` Please refer to its :djadmin:`description <ogrinspect>` in the GeoDjango documentation. +``django.contrib.sessions`` +--------------------------- + +clearsessions +~~~~~~~~~~~~~~~ + +.. django-admin:: clearsessions + +Can be run as a cron job or directly to clean out expired sessions. + ``django.contrib.sitemaps`` --------------------------- @@ -1456,3 +1483,12 @@ Examples:: from django.core import management management.call_command('flush', verbosity=0, interactive=False) management.call_command('loaddata', 'test_data', verbosity=0) + +Output redirection +================== + +Note that you can redirect standard output and error streams as all commands +support the ``stdout`` and ``stderr`` options. For example, you could write:: + + with open('/tmp/command_output') as f: + management.call_command('dumpdata', stdout=f) diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt index 7c8d509031..75d05c6829 100644 --- a/docs/ref/forms/fields.txt +++ b/docs/ref/forms/fields.txt @@ -683,7 +683,7 @@ For each field, we describe the default widget used if you don't specify .. attribute:: unpack_ipv4 - Unpacks IPv4 mapped addresses like ``::ffff::192.0.2.1``. + Unpacks IPv4 mapped addresses like ``::ffff:192.0.2.1``. If this option is enabled that address would be unpacked to ``192.0.2.1``. Default is disabled. Can only be used when ``protocol`` is set to ``'both'``. diff --git a/docs/ref/forms/widgets.txt b/docs/ref/forms/widgets.txt index 3c458930fa..a0ef0731ad 100644 --- a/docs/ref/forms/widgets.txt +++ b/docs/ref/forms/widgets.txt @@ -214,38 +214,49 @@ foundation for custom widgets. The 'value' given is not guaranteed to be valid input, therefore subclass implementations should program defensively. + .. method:: value_from_datadict(self, data, files, name) + + Given a dictionary of data and this widget's name, returns the value + of this widget. Returns ``None`` if a value wasn't provided. + .. class:: MultiWidget(widgets, attrs=None) A widget that is composed of multiple widgets. :class:`~django.forms.widgets.MultiWidget` works hand in hand with the :class:`~django.forms.MultiValueField`. - .. method:: render(name, value, attrs=None) + :class:`MultiWidget` has one required argument: - Argument `value` is handled differently in this method from the - subclasses of :class:`~Widget`. + .. attribute:: MultiWidget.widgets - If `value` is a list, output of :meth:`~MultiWidget.render` will be a - concatenation of rendered child widgets. If `value` is not a list, it - will be first processed by the method :meth:`~MultiWidget.decompress()` - to create the list and then processed as above. + An iterable containing the widgets needed. - Unlike in the single value widgets, method :meth:`~MultiWidget.render` - need not be implemented in the subclasses. + And one required method: .. method:: decompress(value) - Returns a list of "decompressed" values for the given value of the - multi-value field that makes use of the widget. The input value can be - assumed as valid, but not necessarily non-empty. + This method takes a single "compressed" value from the field and + returns a list of "decompressed" values. The input value can be + assumed valid, but not necessarily non-empty. This method **must be implemented** by the subclass, and since the value may be empty, the implementation must be defensive. The rationale behind "decompression" is that it is necessary to "split" - the combined value of the form field into the values of the individual - field encapsulated within the multi-value field (e.g. when displaying - the partially or fully filled-out form). + the combined value of the form field into the values for each widget. + + An example of this is how :class:`SplitDateTimeWidget` turns a + :class:`datetime` value into a list with date and time split into two + separate values:: + + class SplitDateTimeWidget(MultiWidget): + + # ... + + def decompress(self, value): + if value: + return [value.date(), value.time().replace(microsecond=0)] + return [None, None] .. tip:: @@ -254,6 +265,109 @@ foundation for custom widgets. with the opposite responsibility - to combine cleaned values of all member fields into one. + Other methods that may be useful to override include: + + .. method:: render(name, value, attrs=None) + + Argument ``value`` is handled differently in this method from the + subclasses of :class:`~Widget` because it has to figure out how to + split a single value for display in multiple widgets. + + The ``value`` argument used when rendering can be one of two things: + + * A ``list``. + * A single value (e.g., a string) that is the "compressed" representation + of a ``list`` of values. + + If `value` is a list, output of :meth:`~MultiWidget.render` will be a + concatenation of rendered child widgets. If `value` is not a list, it + will be first processed by the method :meth:`~MultiWidget.decompress()` + to create the list and then processed as above. + + In the second case -- i.e., if the value is *not* a list -- + ``render()`` will first decompress the value into a ``list`` before + rendering it. It does so by calling the ``decompress()`` method, which + :class:`MultiWidget`'s subclasses must implement (see above). + + When ``render()`` executes its HTML rendering, each value in the list + is rendered with the corresponding widget -- the first value is + rendered in the first widget, the second value is rendered in the + second widget, etc. + + Unlike in the single value widgets, method :meth:`~MultiWidget.render` + need not be implemented in the subclasses. + + .. method:: format_output(rendered_widgets) + + Given a list of rendered widgets (as strings), returns a Unicode string + representing the HTML for the whole lot. + + This hook allows you to format the HTML design of the widgets any way + you'd like. + + Here's an example widget which subclasses :class:`MultiWidget` to display + a date with the day, month, and year in different select boxes. This widget + is intended to be used with a :class:`~django.forms.DateField` rather than + a :class:`~django.forms.MultiValueField`, thus we have implemented + :meth:`~Widget.value_from_datadict`:: + + from datetime import date + from django.forms import widgets + + class DateSelectorWidget(widgets.MultiWidget): + def __init__(self, attrs=None): + # create choices for days, months, years + # example below, the rest snipped for brevity. + years = [(year, year) for year in (2011, 2012, 2013)] + _widgets = ( + widgets.Select(attrs=attrs, choices=days), + widgets.Select(attrs=attrs, choices=months), + widgets.Select(attrs=attrs, choices=years), + ) + super(DateSelectorWidget, self).__init__(_widgets, attrs) + + def decompress(self, value): + if value: + return [value.day, value.month, value.year] + return [None, None, None] + + def format_output(self, rendered_widgets): + return u''.join(rendered_widgets) + + def value_from_datadict(self, data, files, name): + datelist = [ + widget.value_from_datadict(data, files, name + '_%s' % i) + for i, widget in enumerate(self.widgets)] + try: + D = date(day=int(datelist[0]), month=int(datelist[1]), + year=int(datelist[2])) + except ValueError: + return '' + else: + return str(D) + + The constructor creates several :class:`Select` widgets in a tuple. The + ``super`` class uses this tuple to setup the widget. + + The :meth:`~MultiWidget.format_output` method is fairly vanilla here (in + fact, it's the same as what's been implemented as the default for + ``MultiWidget``), but the idea is that you could add custom HTML between + the widgets should you wish. + + The required method :meth:`~MultiWidget.decompress` breaks up a + ``datetime.date`` value into the day, month, and year values corresponding + to each widget. Note how the method handles the case where ``value`` is + ``None``. + + The default implementation of :meth:`~Widget.value_from_datadict` returns + a list of values corresponding to each ``Widget``. This is appropriate + when using a ``MultiWidget`` with a :class:`~django.forms.MultiValueField`, + but since we want to use this widget with a :class:`~django.forms.DateField` + which takes a single value, we have overridden this method to combine the + data of all the subwidgets into a ``datetime.date``. The method extracts + data from the ``POST`` dictionary and constructs and validates the date. + If it is valid, we return the string, otherwise, we return an empty string + which will cause ``form.is_valid`` to return ``False``. .. _built-in widgets: @@ -552,54 +666,6 @@ Composite widgets :attr:`~Field.choices` attribute. If it does, it will override anything you set here when the attribute is updated on the :class:`Field`. -``MultiWidget`` -~~~~~~~~~~~~~~~ - -.. class:: MultiWidget - - Wrapper around multiple other widgets. You'll probably want to use this - class with :class:`MultiValueField`. - - Its ``render()`` method is different than other widgets', because it has to - figure out how to split a single value for display in multiple widgets. - - Subclasses may implement ``format_output``, which takes the list of - rendered widgets and returns a string of HTML that formats them any way - you'd like. - - The ``value`` argument used when rendering can be one of two things: - - * A ``list``. - * A single value (e.g., a string) that is the "compressed" representation - of a ``list`` of values. - - In the second case -- i.e., if the value is *not* a list -- ``render()`` - will first decompress the value into a ``list`` before rendering it. It - does so by calling the ``decompress()`` method, which - :class:`MultiWidget`'s subclasses must implement. This method takes a - single "compressed" value and returns a ``list``. An example of this is how - :class:`SplitDateTimeWidget` turns a :class:`datetime` value into a list - with date and time split into two seperate values:: - - class SplitDateTimeWidget(MultiWidget): - - # ... - - def decompress(self, value): - if value: - return [value.date(), value.time().replace(microsecond=0)] - return [None, None] - - When ``render()`` executes its HTML rendering, each value in the list is - rendered with the corresponding widget -- the first value is rendered in - the first widget, the second value is rendered in the second widget, etc. - - :class:`MultiWidget` has one required argument: - - .. attribute:: MultiWidget.widgets - - An iterable containing the widgets needed. - ``SplitDateTimeWidget`` ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt index 809d56eaf5..cd1185585c 100644 --- a/docs/ref/models/fields.txt +++ b/docs/ref/models/fields.txt @@ -825,7 +825,7 @@ are converted to lowercase. .. attribute:: GenericIPAddressField.unpack_ipv4 - Unpacks IPv4 mapped addresses like ``::ffff::192.0.2.1``. + Unpacks IPv4 mapped addresses like ``::ffff:192.0.2.1``. If this option is enabled that address would be unpacked to ``192.0.2.1``. Default is disabled. Can only be used when ``protocol`` is set to ``'both'``. @@ -922,6 +922,11 @@ Like all :class:`CharField` subclasses, :class:`URLField` takes the optional :attr:`~CharField.max_length`argument. If you don't specify :attr:`~CharField.max_length`, a default of 200 is used. +.. versionadded:: 1.5 + +The current value of the field will be displayed as a clickable link above the +input widget. + Relationship fields =================== diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt index 1ba41148b0..6315985ba9 100644 --- a/docs/ref/models/instances.txt +++ b/docs/ref/models/instances.txt @@ -67,9 +67,9 @@ Validating objects There are three steps involved in validating a model: -1. Validate the model fields -2. Validate the model as a whole -3. Validate the field uniqueness +1. Validate the model fields - :meth:`Model.clean_fields()` +2. Validate the model as a whole - :meth:`Model.clean()` +3. Validate the field uniqueness - :meth:`Model.validate_unique()` All three steps are performed when you call a model's :meth:`~Model.full_clean()` method. @@ -97,17 +97,20 @@ not be corrected by the user. Note that ``full_clean()`` will *not* be called automatically when you call your model's :meth:`~Model.save()` method, nor as a result of -:class:`~django.forms.ModelForm` validation. You'll need to call it manually -when you want to run one-step model validation for your own manually created -models. +:class:`~django.forms.ModelForm` validation. In the case of +:class:`~django.forms.ModelForm` validation, :meth:`Model.clean_fields()`, +:meth:`Model.clean()`, and :meth:`Model.validate_unique()` are all called +individually. -Example:: +You'll need to call ``full_clean`` manually when you want to run one-step model +validation for your own manually created models. For example:: try: article.full_clean() except ValidationError as e: # Do something based on the errors contained in e.message_dict. # Display them to a user, or handle them programatically. + pass The first step ``full_clean()`` performs is to clean each individual field. @@ -375,7 +378,7 @@ If ``save()`` is passed a list of field names in keyword argument ``update_fields``, only the fields named in that list will be updated. This may be desirable if you want to update just one or a few fields on an object. There will be a slight performance benefit from preventing -all of the model fields from being updated in the database. For example: +all of the model fields from being updated in the database. For example:: product.name = 'Name changed again' product.save(update_fields=['name']) @@ -479,9 +482,13 @@ For example:: return "/people/%i/" % self.id (Whilst this code is correct and simple, it may not be the most portable way to -write this kind of method. The :func:`permalink() decorator <permalink>`, -documented below, is usually the best approach and you should read that section -before diving into code implementation.) +write this kind of method. The :func:`~django.core.urlresolvers.reverse` +function is usually the best approach.) + +For example:: + + def get_absolute_url(self): + return reverse('people.views.details', args=[str(self.id)]) One place Django uses ``get_absolute_url()`` is in the admin app. If an object defines this method, the object-editing page will have a "View on site" link @@ -526,11 +533,19 @@ in ``get_absolute_url()`` and have all your other code call that one place. The ``permalink`` decorator ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The way we wrote ``get_absolute_url()`` above is a slightly violation of the -DRY principle: the URL for this object is defined both in the URLconf file and -in the model. +.. warning:: -You can decouple your models from the URLconf using the ``permalink`` decorator: + The ``permalink`` decorator is no longer recommended. You should use + :func:`~django.core.urlresolvers.reverse` in the body of your + ``get_absolute_url`` method instead. + +In early versions of Django, there wasn't an easy way to use URLs defined in +URLconf file inside :meth:`~django.db.models.Model.get_absolute_url`. That +meant you would need to define the URL both in URLConf and +:meth:`~django.db.models.Model.get_absolute_url`. The ``permalink`` decorator +was added to overcome this DRY principle violation. However, since the +introduction of :func:`~django.core.urlresolvers.reverse` there is no +reason to use ``permalink`` any more. .. function:: permalink() @@ -541,14 +556,14 @@ correct URL, with all parameters substituted in the correct positions. The ``permalink`` decorator is a Python-level equivalent to the :ttag:`url` template tag and a high-level wrapper for the -:func:`django.core.urlresolvers.reverse()` function. +:func:`~django.core.urlresolvers.reverse` function. An example should make it clear how to use ``permalink()``. Suppose your URLconf contains a line such as:: (r'^people/(\d+)/$', 'people.views.details'), -...your model could have a :meth:`~django.db.models.Model.get_absolute_url()` +...your model could have a :meth:`~django.db.models.Model.get_absolute_url` method that looked like this:: from django.db import models @@ -616,25 +631,25 @@ the field. This method returns the "human-readable" value of the field. For example:: - from django.db import models + from django.db import models - class Person(models.Model): - SHIRT_SIZES = ( - (u'S', u'Small'), - (u'M', u'Medium'), - (u'L', u'Large'), - ) - name = models.CharField(max_length=60) - shirt_size = models.CharField(max_length=2, choices=SHIRT_SIZES) + class Person(models.Model): + SHIRT_SIZES = ( + (u'S', u'Small'), + (u'M', u'Medium'), + (u'L', u'Large'), + ) + name = models.CharField(max_length=60) + shirt_size = models.CharField(max_length=2, choices=SHIRT_SIZES) - :: +:: - >>> p = Person(name="Fred Flintstone", shirt_size="L") - >>> p.save() - >>> p.shirt_size - u'L' - >>> p.get_shirt_size_display() - u'Large' + >>> p = Person(name="Fred Flintstone", shirt_size="L") + >>> p.save() + >>> p.shirt_size + u'L' + >>> p.get_shirt_size_display() + u'Large' .. method:: Model.get_next_by_FOO(\**kwargs) .. method:: Model.get_previous_by_FOO(\**kwargs) diff --git a/docs/ref/models/options.txt b/docs/ref/models/options.txt index c5ae8398ea..a577135271 100644 --- a/docs/ref/models/options.txt +++ b/docs/ref/models/options.txt @@ -261,6 +261,21 @@ Django quotes column and table names behind the scenes. :class:`~django.db.models.ManyToManyField`, try using a signal or an explicit :attr:`through <ManyToManyField.through>` model. +``index_together`` + +.. attribute:: Options.index_together + + .. versionadded:: 1.5 + + Sets of field names that, taken together, are indexed:: + + index_together = [ + ["pub_date", "deadline"], + ] + + This list of fields will be indexed together (i.e. the appropriate + ``CREATE INDEX`` statement will be issued.) + ``verbose_name`` ---------------- diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt index 7138cd0e74..40fa2d2b2f 100644 --- a/docs/ref/models/querysets.txt +++ b/docs/ref/models/querysets.txt @@ -676,21 +676,12 @@ Note that, by default, ``select_related()`` does not follow foreign keys that have ``null=True``. Usually, using ``select_related()`` can vastly improve performance because your -app can avoid many database calls. However, in situations with deeply nested -sets of relationships ``select_related()`` can sometimes end up following "too -many" relations, and can generate queries so large that they end up being slow. +app can avoid many database calls. However, there are times you are only +interested in specific related models, or have deeply nested sets of +relationships, and in these cases ``select_related()`` can be optimized by +explicitly passing the related field names you are interested in. Only +the specified relations will be followed. -In these situations, you can use the ``depth`` argument to ``select_related()`` -to control how many "levels" of relations ``select_related()`` will actually -follow:: - - b = Book.objects.select_related(depth=1).get(id=4) - p = b.author # Doesn't hit the database. - c = p.hometown # Requires a database call. - -Sometimes you only want to access specific models that are related to your root -model, not all of the related models. In these cases, you can pass the related -field names to ``select_related()`` and it will only follow those relations. You can even do this for models that are more than one relation away by separating the field names with double underscores, just as for filters. For example, if you have this model:: @@ -730,6 +721,17 @@ You can also refer to the reverse direction of a is defined. Instead of specifying the field name, use the :attr:`related_name <django.db.models.ForeignKey.related_name>` for the field on the related object. +.. deprecated:: 1.5 + The ``depth`` parameter to ``select_related()`` has been deprecated. You + should replace it with the use of the ``(*fields)`` listing specific + related fields instead as documented above. + +A depth limit of relationships to follow can also be specified:: + + b = Book.objects.select_related(depth=1).get(id=4) + p = b.author # Doesn't hit the database. + c = p.hometown # Requires a database call. + A :class:`~django.db.models.OneToOneField` is not traversed in the reverse direction if you are performing a depth-based ``select_related()`` call. @@ -1319,10 +1321,12 @@ The above example can be rewritten using ``get_or_create()`` like so:: Any keyword arguments passed to ``get_or_create()`` — *except* an optional one called ``defaults`` — will be used in a :meth:`get()` call. If an object is -found, ``get_or_create()`` returns a tuple of that object and ``False``. If an -object is *not* found, ``get_or_create()`` will instantiate and save a new -object, returning a tuple of the new object and ``True``. The new object will -be created roughly according to this algorithm:: +found, ``get_or_create()`` returns a tuple of that object and ``False``. If +multiple objects are found, ``get_or_create`` raises +:exc:`~django.core.exceptions.MultipleObjectsReturned`. If an object is *not* +found, ``get_or_create()`` will instantiate and save a new object, returning a +tuple of the new object and ``True``. The new object will be created roughly +according to this algorithm:: defaults = kwargs.pop('defaults', {}) params = dict([(k, v) for k, v in kwargs.items() if '__' not in k]) diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index a909c12665..daa4ee9a46 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -431,10 +431,12 @@ MySQL will connect via a Unix socket to the specified socket. For example:: If you're using MySQL and this value *doesn't* start with a forward slash, then this value is assumed to be the host. -If you're using PostgreSQL, an empty string means to use a Unix domain socket -for the connection, rather than a network connection to localhost. If you -explicitly need to use a TCP/IP connection on the local machine with -PostgreSQL, specify ``localhost`` here. +If you're using PostgreSQL, by default (empty :setting:`HOST`), the connection +to the database is done through UNIX domain sockets ('local' lines in +``pg_hba.conf``). If you want to connect through TCP sockets, set +:setting:`HOST` to 'localhost' or '127.0.0.1' ('host' lines in ``pg_hba.conf``). +On Windows, you should always define :setting:`HOST`, as UNIX domain sockets +are not available. .. setting:: NAME @@ -1119,9 +1121,11 @@ Default: ``()`` List of compiled regular expression objects describing URLs that should be ignored when reporting HTTP 404 errors via email (see -:doc:`/howto/error-reporting`). Use this if your site does not provide a -commonly requested file such as ``favicon.ico`` or ``robots.txt``, or if it -gets hammered by script kiddies. +:doc:`/howto/error-reporting`). Regular expressions are matched against +:meth:`request's full paths <django.http.HttpRequest.get_full_path>` (including +query string, if any). Use this if your site does not provide a commonly +requested file such as ``favicon.ico`` or ``robots.txt``, or if it gets +hammered by script kiddies. This is only used if :setting:`SEND_BROKEN_LINK_EMAILS` is set to ``True`` and ``CommonMiddleware`` is installed (see :doc:`/topics/http/middleware`). @@ -1242,9 +1246,8 @@ Example:: '/var/local/translations/locale' ) -Note that in the paths you add to the value of this setting, if you have the -typical ``/path/to/locale/xx/LC_MESSAGES`` hierarchy, you should use the path to -the ``locale`` directory (i.e. ``'/path/to/locale'``). +Django will look within each of these paths for the ``<locale_code>/LC_MESSAGES`` +directories containing the actual translation files. .. setting:: LOGGING @@ -1373,7 +1376,7 @@ more details. MESSAGE_STORAGE --------------- -Default: ``'django.contrib.messages.storage.user_messages.LegacyFallbackStorage'`` +Default: ``'django.contrib.messages.storage.fallback.FallbackStorage'`` Controls where Django stores message data. See the :doc:`messages documentation </ref/contrib/messages>` for more details. @@ -1560,9 +1563,9 @@ for. You'll need to set a tuple with two elements -- the name of the header to look for and the required value. For example:: - SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https') + SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') -Here, we're telling Django that we trust the ``X-Forwarded-Protocol`` header +Here, we're telling Django that we trust the ``X-Forwarded-Proto`` header that comes from our proxy, and any time its value is ``'https'``, then the request is guaranteed to be secure (i.e., it originally came in via HTTPS). Obviously, you should *only* set this setting if you control your proxy or @@ -1575,16 +1578,18 @@ available in ``request.META``.) .. warning:: - **You will probably open security holes in your site if you set this without knowing what you're doing. And if you fail to set it when you should. Seriously.** + **You will probably open security holes in your site if you set this + without knowing what you're doing. And if you fail to set it when you + should. Seriously.** Make sure ALL of the following are true before setting this (assuming the values from the example above): * Your Django app is behind a proxy. - * Your proxy strips the 'X-Forwarded-Protocol' header from all incoming + * Your proxy strips the ``X-Forwarded-Proto`` header from all incoming requests. In other words, if end users include that header in their requests, the proxy will discard it. - * Your proxy sets the 'X-Forwarded-Protocol' header and sends it to Django, + * Your proxy sets the ``X-Forwarded-Proto`` header and sends it to Django, but only for requests that originally come in via HTTPS. If any of those are not true, you should keep this setting set to ``None`` @@ -1693,6 +1698,16 @@ This is useful if you have multiple Django instances running under the same hostname. They can use different cookie paths, and each instance will only see its own session cookie. +.. setting:: SESSION_CACHE_ALIAS + +SESSION_CACHE_ALIAS +------------------- + +Default: ``default`` + +If you're using :ref:`cache-based session storage <cached-sessions-backend>`, +this selects the cache to use. + .. setting:: SESSION_COOKIE_SECURE SESSION_COOKIE_SECURE @@ -2054,6 +2069,16 @@ to ensure your processes are running in the correct environment. .. _pytz: http://pytz.sourceforge.net/ +.. setting:: TRANSACTIONS_MANAGED + +TRANSACTIONS_MANAGED +-------------------- + +Default: ``False`` + +Set this to ``True`` if you want to :ref:`disable Django's transaction +management <deactivate-transaction-management>` and implement your own. + .. setting:: USE_ETAGS USE_ETAGS @@ -2198,16 +2223,6 @@ The default value for the X-Frame-Options header used by Deprecated settings =================== -.. setting:: ADMIN_MEDIA_PREFIX - -ADMIN_MEDIA_PREFIX ------------------- - -.. deprecated:: 1.4 - This setting has been obsoleted by the ``django.contrib.staticfiles`` app - integration. See the :doc:`Django 1.4 release notes</releases/1.4>` for - more information. - .. setting:: AUTH_PROFILE_MODULE AUTH_PROFILE_MODULE diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index 3b8d058fb4..57ef0cfb27 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -53,6 +53,13 @@ comment Ignores everything between ``{% comment %}`` and ``{% endcomment %}``. +Sample usage:: + + <p>Rendered text with {{ pub_date|date:"c" }}</p> + {% comment %} + <p>Commented out text with {{ create_date|date:"c" }}</p> + {% endcomment %} + .. templatetag:: csrf_token csrf_token @@ -611,7 +618,7 @@ Output the contents of the block if the two arguments equal each other. Example:: - {% ifequal user.id comment.user_id %} + {% ifequal user.pk comment.user_id %} ... {% endifequal %} @@ -947,6 +954,10 @@ Argument Outputs ``closecomment`` ``#}`` ================== ======= +Sample usage:: + + {% templatetag openblock %} url 'entry_list' {% templatetag closeblock %} + .. templatetag:: url url @@ -1024,6 +1035,16 @@ This will follow the normal :ref:`namespaced URL resolution strategy <topics-http-reversing-url-namespaces>`, including using any hints provided by the context as to the current application. +.. warning:: + + Don't forget to put quotes around the function path or pattern name! + + .. versionchanged:: 1.5 + The first parameter used not to be quoted, which was inconsistent with + other template tags. Since Django 1.5, it is evaluated according to + the usual rules: it can be a quoted string or a variable that will be + looked up in the context. + .. templatetag:: verbatim verbatim @@ -1226,7 +1247,8 @@ G Hour, 24-hour format without leading ``'0'`` to ``'23'`` h Hour, 12-hour format. ``'01'`` to ``'12'`` H Hour, 24-hour format. ``'00'`` to ``'23'`` i Minutes. ``'00'`` to ``'59'`` -I Not implemented. +I Daylight Savings Time, whether it's ``'1'`` or ``'0'`` + in effect or not. j Day of the month without leading ``'1'`` to ``'31'`` zeros. l Day of the week, textual, long. ``'Friday'`` @@ -1408,6 +1430,12 @@ applied to the result will only result in one round of escaping being done. So it is safe to use this function even in auto-escaping environments. If you want multiple escaping passes to be applied, use the :tfilter:`force_escape` filter. +For example, you can apply ``escape`` to fields when :ttag:`autoescape` is off:: + + {% autoescape off %} + {{ title|escape }} + {% endautoescape %} + .. templatefilter:: escapejs escapejs @@ -1438,6 +1466,14 @@ For example:: If ``value`` is 123456789, the output would be ``117.7 MB``. +.. admonition:: File sizes and SI units + + Strictly speaking, ``filesizeformat`` does not conform to the International + System of Units which recommends using KiB, MiB, GiB, etc. when byte sizes + are calculated in powers of 1024 (which is the case here). Instead, Django + uses traditional unit names (KB, MB, GB, etc.) corresponding to names that + are more commonly used. + .. templatefilter:: first first @@ -1504,6 +1540,17 @@ that many decimal places. For example: ``34.26000`` ``{{ value|floatformat:3 }}`` ``34.260`` ============ ============================= ========== +Particularly useful is passing 0 (zero) as the argument which will round the +float to the nearest integer. + +============ ================================ ========== +``value`` Template Output +============ ================================ ========== +``34.23234`` ``{{ value|floatformat:"0" }}`` ``34`` +``34.00000`` ``{{ value|floatformat:"0" }}`` ``34`` +``39.56000`` ``{{ value|floatformat:"0" }}`` ``40`` +============ ================================ ========== + If the argument passed to ``floatformat`` is negative, it will round a number to that many decimal places -- but only if there's a decimal part to be displayed. For example: @@ -1530,6 +1577,13 @@ string. This is useful in the rare cases where you need multiple escaping or want to apply other filters to the escaped results. Normally, you want to use the :tfilter:`escape` filter. +For example, if you want to catch the ``<p>`` HTML elements created by +the :tfilter:`linebreaks` filter:: + + {% autoescape off %} + {{ body|linebreaks|force_escape }} + {% endautoescape %} + .. templatefilter:: get_digit get_digit @@ -1899,9 +1953,9 @@ for documentation of Python string formatting For example:: - {{ value|stringformat:"s" }} + {{ value|stringformat:"E" }} -If ``value`` is ``"Joel is a slug"``, the output will be ``"Joel is a slug"``. +If ``value`` is ``10``, the output will be ``1.000000E+01``. .. templatefilter:: striptags @@ -1967,7 +2021,9 @@ Takes an optional argument that is a variable containing the date to use as the comparison point (without the argument, the comparison point is *now*). For example, if ``blog_date`` is a date instance representing midnight on 1 June 2006, and ``comment_date`` is a date instance for 08:00 on 1 June 2006, -then ``{{ blog_date|timesince:comment_date }}`` would return "8 hours". +then the following would return "8 hours":: + + {{ blog_date|timesince:comment_date }} Comparing offset-naive and offset-aware datetimes will return an empty string. @@ -1986,7 +2042,9 @@ given date or datetime. For example, if today is 1 June 2006 and Takes an optional argument that is a variable containing the date to use as the comparison point (instead of *now*). If ``from_date`` contains 22 June -2006, then ``{{ conference_date|timeuntil:from_date }}`` will return "1 week". +2006, then the following will return "1 week":: + + {{ conference_date|timeuntil:from_date }} Comparing offset-naive and offset-aware datetimes will return an empty string. diff --git a/docs/ref/unicode.txt b/docs/ref/unicode.txt index ffab647379..784ff33398 100644 --- a/docs/ref/unicode.txt +++ b/docs/ref/unicode.txt @@ -262,11 +262,11 @@ Taking care in ``get_absolute_url()`` URLs can only contain ASCII characters. If you're constructing a URL from pieces of data that might be non-ASCII, be careful to encode the results in a -way that is suitable for a URL. The ``django.db.models.permalink()`` decorator -handles this for you automatically. +way that is suitable for a URL. The :func:`~django.core.urlresolvers.reverse` +function handles this for you automatically. -If you're constructing a URL manually (i.e., *not* using the ``permalink()`` -decorator), you'll need to take care of the encoding yourself. In this case, +If you're constructing a URL manually (i.e., *not* using the ``reverse()`` +function), you'll need to take care of the encoding yourself. In this case, use the ``iri_to_uri()`` and ``urlquote()`` functions that were documented above_. For example:: diff --git a/docs/ref/urlresolvers.txt b/docs/ref/urlresolvers.txt index 1bb33c7ca1..528f172061 100644 --- a/docs/ref/urlresolvers.txt +++ b/docs/ref/urlresolvers.txt @@ -178,25 +178,17 @@ whether a view would raise a ``Http404`` error before redirecting to it:: return HttpResponseRedirect('/') return response - -permalink() ------------ - -The :func:`~django.db.models.permalink` decorator is useful for writing short -methods that return a full URL path. For example, a model's -``get_absolute_url()`` method. See :func:`django.db.models.permalink` for more. - get_script_prefix() ------------------- .. function:: get_script_prefix() -Normally, you should always use :func:`~django.core.urlresolvers.reverse` or -:func:`~django.db.models.permalink` to define URLs within your application. -However, if your application constructs part of the URL hierarchy itself, you -may occasionally need to generate URLs. In that case, you need to be able to -find the base URL of the Django project within its Web server -(normally, :func:`~django.core.urlresolvers.reverse` takes care of this for -you). In that case, you can call ``get_script_prefix()``, which will return the -script prefix portion of the URL for your Django project. If your Django -project is at the root of its Web server, this is always ``"/"``. +Normally, you should always use :func:`~django.core.urlresolvers.reverse` to +define URLs within your application. However, if your application constructs +part of the URL hierarchy itself, you may occasionally need to generate URLs. +In that case, you need to be able to find the base URL of the Django project +within its Web server (normally, :func:`~django.core.urlresolvers.reverse` +takes care of this for you). In that case, you can call +``get_script_prefix()``, which will return the script prefix portion of the URL +for your Django project. If your Django project is at the root of its web +server, this is always ``"/"``. diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt index bd3898172a..2f12c3a96c 100644 --- a/docs/ref/utils.txt +++ b/docs/ref/utils.txt @@ -305,6 +305,18 @@ The functions defined in this module share the following properties: Returns an ASCII string containing the encoded result. +.. function:: filepath_to_uri(path) + + Convert a file system path to a URI portion that is suitable for inclusion + in a URL. The path is assumed to be either UTF-8 or unicode. + + This method will encode certain characters that would normally be + recognized as special characters for URIs. Note that this method does not + encode the ' character, as it is a valid character within URIs. See + ``encodeURIComponent()`` JavaScript function for more details. + + Returns an ASCII string containing the encoded result. + ``django.utils.feedgenerator`` ============================== |
