Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge recent changes from master.

  • Loading branch information...
commit 19526563b54fa300785c49cfb625c0c6158ced67 2 parents 2c5e833 + c4aa26a
Russell Keith-Magee freakboy3742 authored
Showing with 1,844 additions and 1,161 deletions.
  1. +1 −0  AUTHORS
  2. +13 −5 django/conf/__init__.py
  3. +4 −1 django/contrib/admin/options.py
  4. +254 −118 django/contrib/admin/static/admin/js/inlines.js
  5. +9 −5 django/contrib/admin/static/admin/js/inlines.min.js
  6. +6 −58 django/contrib/admin/templates/admin/edit_inline/stacked.html
  7. +7 −58 django/contrib/admin/templates/admin/edit_inline/tabular.html
  8. +1 −1  django/contrib/admin/templatetags/admin_list.py
  9. +1 −1  django/contrib/admin/util.py
  10. +3 −3 django/contrib/auth/decorators.py
  11. +1 −1  django/contrib/auth/tests/decorators.py
  12. +6 −5 django/contrib/auth/tests/models.py
  13. +9 −9 django/contrib/auth/views.py
  14. +1 −1  django/contrib/gis/db/models/sql/where.py
  15. +5 −5 django/contrib/localflavor/hr/forms.py
  16. +11 −11 django/contrib/localflavor/ro/forms.py
  17. +6 −0 django/contrib/markup/templatetags/markup.py
  18. +10 −1 django/contrib/markup/tests.py
  19. +4 −4 django/contrib/messages/storage/cookie.py
  20. +5 −5 django/contrib/messages/tests/base.py
  21. +5 −7 django/contrib/sessions/tests.py
  22. +1 −1  django/core/cache/backends/memcached.py
  23. +1 −1  django/core/mail/backends/console.py
  24. +2 −1  django/core/management/__init__.py
  25. +5 −2 django/db/backends/__init__.py
  26. +6 −1 django/db/backends/creation.py
  27. +0 −10 django/db/backends/mysql/introspection.py
  28. +1 −4 django/db/backends/sqlite3/base.py
  29. +7 −0 django/db/models/constants.py
  30. +1 −2  django/db/models/query.py
  31. +4 −9 django/db/models/sql/compiler.py
  32. +7 −4 django/db/models/sql/constants.py
  33. +1 −1  django/db/models/sql/expressions.py
  34. +4 −2 django/db/models/sql/query.py
  35. +1 −0  django/db/models/sql/subqueries.py
  36. +2 −6 django/forms/widgets.py
  37. +35 −21 django/http/__init__.py
  38. +2 −3 django/http/multipartparser.py
  39. +32 −17 django/shortcuts/__init__.py
  40. +1 −1  django/test/testcases.py
  41. +10 −7 django/utils/_os.py
  42. +7 −0 django/utils/six.py
  43. +3 −0  django/views/generic/dates.py
  44. +2 −3 docs/README
  45. +17 −23 docs/faq/install.txt
  46. +1 −1  docs/faq/models.txt
  47. +4 −4 docs/howto/custom-model-fields.txt
  48. +3 −0  docs/internals/deprecation.txt
  49. +3 −5 docs/intro/install.txt
  50. +4 −4 docs/intro/overview.txt
  51. +4 −3 docs/intro/tutorial03.txt
  52. +2 −2 docs/intro/tutorial04.txt
  53. +35 −30 docs/ref/class-based-views/base.txt
  54. +79 −49 docs/ref/class-based-views/generic-date-based.txt
  55. +56 −1 docs/ref/class-based-views/generic-display.txt
  56. +5 −4 docs/ref/class-based-views/index.txt
  57. +114 −59 docs/ref/class-based-views/mixins-date-based.txt
  58. +2 −1  docs/ref/class-based-views/mixins-multiple-object.txt
  59. +17 −8 docs/ref/class-based-views/mixins-simple.txt
  60. +4 −4 docs/ref/contrib/comments/moderation.txt
  61. +19 −19 docs/ref/contrib/gis/install.txt
  62. +3 −0  docs/ref/contrib/markup.txt
  63. +47 −49 docs/ref/contrib/messages.txt
  64. +15 −5 docs/ref/forms/fields.txt
  65. +2 −3 docs/ref/forms/validation.txt
  66. +4 −0 docs/ref/forms/widgets.txt
  67. +10 −2 docs/ref/models/fields.txt
  68. +1 −1  docs/ref/models/instances.txt
  69. +4 −3 docs/ref/models/options.txt
  70. +50 −5 docs/ref/models/querysets.txt
  71. +13 −20 docs/ref/settings.txt
  72. +14 −0 docs/releases/1.5.txt
  73. +7 −0 docs/topics/auth.txt
  74. +44 −0 docs/topics/class-based-views/index.txt
  75. +4 −4 docs/topics/db/examples/many_to_one.txt
  76. +92 −36 docs/topics/db/multi-db.txt
  77. +12 −11 docs/topics/db/queries.txt
  78. +3 −3 docs/topics/forms/modelforms.txt
  79. +52 −50 docs/topics/http/urls.txt
  80. +5 −0 docs/topics/i18n/translation.txt
  81. +2 −4 docs/topics/install.txt
  82. +20 −5 docs/topics/python3.txt
  83. +26 −6 docs/topics/security.txt
  84. +14 −14 tests/modeltests/basic/tests.py
  85. +4 −3 tests/modeltests/empty/tests.py
  86. +17 −17 tests/modeltests/fixtures/tests.py
  87. +2 −1  tests/modeltests/many_to_many/tests.py
  88. +1 −1  tests/modeltests/many_to_one/tests.py
  89. +1 −1  tests/modeltests/raw_query/tests.py
  90. +2 −1  tests/modeltests/update_only_fields/tests.py
  91. +2 −1  tests/modeltests/validation/test_error_messages.py
  92. +4 −3 tests/regressiontests/admin_filters/tests.py
  93. +59 −2 tests/regressiontests/admin_inlines/tests.py
  94. +22 −22 tests/regressiontests/admin_scripts/tests.py
  95. +14 −2 tests/regressiontests/admin_views/admin.py
  96. +1 −0  tests/regressiontests/admin_views/customadmin.py
  97. +6 −0 tests/regressiontests/admin_views/models.py
  98. +14 −1 tests/regressiontests/admin_views/tests.py
  99. +1 −1  tests/regressiontests/backends/tests.py
  100. +3 −4 tests/regressiontests/cache/tests.py
  101. +1 −1  tests/regressiontests/comment_tests/tests/__init__.py
  102. +9 −0 tests/regressiontests/comment_tests/urls_default.py
  103. +1 −1  tests/regressiontests/file_storage/tests.py
  104. +7 −9 tests/regressiontests/file_uploads/tests.py
  105. +20 −24 tests/regressiontests/fixtures_regress/tests.py
  106. +3 −3 tests/regressiontests/forms/tests/fields.py
  107. +3 −7 tests/regressiontests/forms/tests/widgets.py
  108. +1 −3 tests/regressiontests/handlers/tests.py
  109. +42 −22 tests/regressiontests/httpwrappers/tests.py
  110. +5 −4 tests/regressiontests/i18n/commands/compilation.py
  111. +2 −2 tests/regressiontests/inline_formsets/tests.py
  112. +17 −15 tests/regressiontests/localflavor/tr/tests.py
  113. +3 −2 tests/regressiontests/m2m_regress/tests.py
  114. +3 −2 tests/regressiontests/many_to_one_regress/tests.py
  115. +64 −64 tests/regressiontests/modeladmin/tests.py
  116. +1 −4 tests/regressiontests/queries/tests.py
  117. 0  tests/regressiontests/resolve_url/__init__.py
  118. +12 −0 tests/regressiontests/resolve_url/models.py
  119. +68 −0 tests/regressiontests/resolve_url/tests.py
  120. +12 −10 tests/regressiontests/settings_tests/tests.py
  121. +34 −36 tests/regressiontests/signals_regress/tests.py
  122. +1 −1  tests/regressiontests/staticfiles_tests/tests.py
  123. +26 −25 tests/regressiontests/templates/custom.py
  124. +6 −6 tests/regressiontests/templates/loaders.py
  125. +3 −3 tests/regressiontests/test_utils/tests.py
  126. +7 −15 tests/regressiontests/transactions_regress/tests.py
  127. +4 −4 tests/regressiontests/urlpatterns_reverse/tests.py
  128. +21 −0 tests/regressiontests/utils/os_utils.py
  129. +1 −0  tests/regressiontests/utils/tests.py
  130. +3 −4 tests/regressiontests/wsgi/tests.py
  131. +1 −1  tests/runtests.py
1  AUTHORS
View
@@ -506,6 +506,7 @@ answer newbie questions, and generally made Django that much better:
Johan C. Stöver <johan@nilling.nl>
Nowell Strite <http://nowell.strite.org/>
Thomas Stromberg <tstromberg@google.com>
+ Travis Swicegood <travis@domain51.com>
Pascal Varet
SuperJared
Radek Švarz <http://www.svarz.cz/translate/>
18 django/conf/__init__.py
View
@@ -7,7 +7,6 @@
"""
import os
-import re
import time # Needed for Windows
import warnings
@@ -26,7 +25,7 @@ class LazySettings(LazyObject):
The user can manually configure settings prior to using them. Otherwise,
Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE.
"""
- def _setup(self):
+ def _setup(self, name):
"""
Load the settings module pointed to by the environment variable. This
is used the first time we need any settings at all, if the user has not
@@ -37,12 +36,21 @@ def _setup(self):
if not settings_module: # If it's set but is an empty string.
raise KeyError
except KeyError:
- # NOTE: This is arguably an EnvironmentError, but that causes
- # problems with Python's interactive help.
- raise ImportError("Settings cannot be imported, because environment variable %s is undefined." % ENVIRONMENT_VARIABLE)
+ raise ImproperlyConfigured(
+ "Requested setting %s, but settings are not configured. "
+ "You must either define the environment variable %s "
+ "or call settings.configure() before accessing settings."
+ % (name, ENVIRONMENT_VARIABLE))
self._wrapped = Settings(settings_module)
+
+ def __getattr__(self, name):
+ if self._wrapped is empty:
+ self._setup(name)
+ return getattr(self._wrapped, name)
+
+
def configure(self, default_settings=global_settings, **options):
"""
Called to manually configure the settings. The 'default_settings'
5 django/contrib/admin/options.py
View
@@ -14,9 +14,10 @@
from django.core.paginator import Paginator
from django.core.urlresolvers import reverse
from django.db import models, transaction, router
+from django.db.models.constants import LOOKUP_SEP
from django.db.models.related import RelatedObject
from django.db.models.fields import BLANK_CHOICE_DASH, FieldDoesNotExist
-from django.db.models.sql.constants import LOOKUP_SEP, QUERY_TERMS
+from django.db.models.sql.constants import QUERY_TERMS
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.template.response import SimpleTemplateResponse, TemplateResponse
@@ -1456,8 +1457,10 @@ def has_delete_permission(self, request, obj=None):
return request.user.has_perm(
self.opts.app_label + '.' + self.opts.get_delete_permission())
+
class StackedInline(InlineModelAdmin):
template = 'admin/edit_inline/stacked.html'
+
class TabularInline(InlineModelAdmin):
template = 'admin/edit_inline/tabular.html'
372 django/contrib/admin/static/admin/js/inlines.js
View
@@ -9,128 +9,264 @@
* All rights reserved.
*
* Spiced up with Code from Zain Memon's GSoC project 2009
- * and modified for Django by Jannis Leidel
+ * and modified for Django by Jannis Leidel, Travis Swicegood and Julien Phalip.
*
* Licensed under the New BSD License
* See: http://www.opensource.org/licenses/bsd-license.php
*/
(function($) {
- $.fn.formset = function(opts) {
- var options = $.extend({}, $.fn.formset.defaults, opts);
- var updateElementIndex = function(el, prefix, ndx) {
- var id_regex = new RegExp("(" + prefix + "-(\\d+|__prefix__))");
- var replacement = prefix + "-" + ndx;
- if ($(el).attr("for")) {
- $(el).attr("for", $(el).attr("for").replace(id_regex, replacement));
- }
- if (el.id) {
- el.id = el.id.replace(id_regex, replacement);
- }
- if (el.name) {
- el.name = el.name.replace(id_regex, replacement);
- }
- };
- var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").attr("autocomplete", "off");
- var nextIndex = parseInt(totalForms.val(), 10);
- var maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").attr("autocomplete", "off");
- // only show the add button if we are allowed to add more items,
+ $.fn.formset = function(opts) {
+ var options = $.extend({}, $.fn.formset.defaults, opts);
+ var $this = $(this);
+ var $parent = $this.parent();
+ var updateElementIndex = function(el, prefix, ndx) {
+ var id_regex = new RegExp("(" + prefix + "-(\\d+|__prefix__))");
+ var replacement = prefix + "-" + ndx;
+ if ($(el).attr("for")) {
+ $(el).attr("for", $(el).attr("for").replace(id_regex, replacement));
+ }
+ if (el.id) {
+ el.id = el.id.replace(id_regex, replacement);
+ }
+ if (el.name) {
+ el.name = el.name.replace(id_regex, replacement);
+ }
+ };
+ var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").attr("autocomplete", "off");
+ var nextIndex = parseInt(totalForms.val(), 10);
+ var maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").attr("autocomplete", "off");
+ // only show the add button if we are allowed to add more items,
// note that max_num = None translates to a blank string.
- var showAddButton = maxForms.val() === '' || (maxForms.val()-totalForms.val()) > 0;
- $(this).each(function(i) {
- $(this).not("." + options.emptyCssClass).addClass(options.formCssClass);
- });
- if ($(this).length && showAddButton) {
- var addButton;
- if ($(this).attr("tagName") == "TR") {
- // If forms are laid out as table rows, insert the
- // "add" button in a new table row:
- var numCols = this.eq(-1).children().length;
- $(this).parent().append('<tr class="' + options.addCssClass + '"><td colspan="' + numCols + '"><a href="javascript:void(0)">' + options.addText + "</a></tr>");
- addButton = $(this).parent().find("tr:last a");
- } else {
- // Otherwise, insert it immediately after the last form:
- $(this).filter(":last").after('<div class="' + options.addCssClass + '"><a href="javascript:void(0)">' + options.addText + "</a></div>");
- addButton = $(this).filter(":last").next().find("a");
- }
- addButton.click(function(e) {
- e.preventDefault();
- var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS");
- var template = $("#" + options.prefix + "-empty");
- var row = template.clone(true);
- row.removeClass(options.emptyCssClass)
- .addClass(options.formCssClass)
- .attr("id", options.prefix + "-" + nextIndex);
- if (row.is("tr")) {
- // If the forms are laid out in table rows, insert
- // the remove button into the last table cell:
- row.children(":last").append('<div><a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + "</a></div>");
- } else if (row.is("ul") || row.is("ol")) {
- // If they're laid out as an ordered/unordered list,
- // insert an <li> after the last list item:
- row.append('<li><a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + "</a></li>");
- } else {
- // Otherwise, just insert the remove button as the
- // last child element of the form's container:
- row.children(":first").append('<span><a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText + "</a></span>");
- }
- row.find("*").each(function() {
- updateElementIndex(this, options.prefix, totalForms.val());
- });
- // Insert the new form when it has been fully edited
- row.insertBefore($(template));
- // Update number of total forms
- $(totalForms).val(parseInt(totalForms.val(), 10) + 1);
- nextIndex += 1;
- // Hide add button in case we've hit the max, except we want to add infinitely
- if ((maxForms.val() !== '') && (maxForms.val()-totalForms.val()) <= 0) {
- addButton.parent().hide();
- }
- // The delete button of each row triggers a bunch of other things
- row.find("a." + options.deleteCssClass).click(function(e) {
- e.preventDefault();
- // Remove the parent form containing this button:
- var row = $(this).parents("." + options.formCssClass);
- row.remove();
- nextIndex -= 1;
- // If a post-delete callback was provided, call it with the deleted form:
- if (options.removed) {
- options.removed(row);
- }
- // Update the TOTAL_FORMS form count.
- var forms = $("." + options.formCssClass);
- $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);
- // Show add button again once we drop below max
- if ((maxForms.val() === '') || (maxForms.val()-forms.length) > 0) {
- addButton.parent().show();
- }
- // Also, update names and ids for all remaining form controls
- // so they remain in sequence:
- for (var i=0, formCount=forms.length; i<formCount; i++)
- {
- updateElementIndex($(forms).get(i), options.prefix, i);
- $(forms.get(i)).find("*").each(function() {
- updateElementIndex(this, options.prefix, i);
- });
- }
- });
- // If a post-add callback was supplied, call it with the added form:
- if (options.added) {
- options.added(row);
- }
- });
- }
- return this;
- };
- /* Setup plugin defaults */
- $.fn.formset.defaults = {
- prefix: "form", // The form prefix for your django formset
- addText: "add another", // Text for the add link
- deleteText: "remove", // Text for the delete link
- addCssClass: "add-row", // CSS class applied to the add link
- deleteCssClass: "delete-row", // CSS class applied to the delete link
- emptyCssClass: "empty-row", // CSS class applied to the empty row
- formCssClass: "dynamic-form", // CSS class applied to each form in a formset
- added: null, // Function called each time a new form is added
- removed: null // Function called each time a form is deleted
- };
+ var showAddButton = maxForms.val() === '' || (maxForms.val()-totalForms.val()) > 0;
+ $this.each(function(i) {
+ $(this).not("." + options.emptyCssClass).addClass(options.formCssClass);
+ });
+ if ($this.length && showAddButton) {
+ var addButton;
+ if ($this.attr("tagName") == "TR") {
+ // If forms are laid out as table rows, insert the
+ // "add" button in a new table row:
+ var numCols = this.eq(-1).children().length;
+ $parent.append('<tr class="' + options.addCssClass + '"><td colspan="' + numCols + '"><a href="javascript:void(0)">' + options.addText + "</a></tr>");
+ addButton = $parent.find("tr:last a");
+ } else {
+ // Otherwise, insert it immediately after the last form:
+ $this.filter(":last").after('<div class="' + options.addCssClass + '"><a href="javascript:void(0)">' + options.addText + "</a></div>");
+ addButton = $this.filter(":last").next().find("a");
+ }
+ addButton.click(function(e) {
+ e.preventDefault();
+ var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS");
+ var template = $("#" + options.prefix + "-empty");
+ var row = template.clone(true);
+ row.removeClass(options.emptyCssClass)
+ .addClass(options.formCssClass)
+ .attr("id", options.prefix + "-" + nextIndex);
+ if (row.is("tr")) {
+ // If the forms are laid out in table rows, insert
+ // the remove button into the last table cell:
+ row.children(":last").append('<div><a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + "</a></div>");
+ } else if (row.is("ul") || row.is("ol")) {
+ // If they're laid out as an ordered/unordered list,
+ // insert an <li> after the last list item:
+ row.append('<li><a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + "</a></li>");
+ } else {
+ // Otherwise, just insert the remove button as the
+ // last child element of the form's container:
+ row.children(":first").append('<span><a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText + "</a></span>");
+ }
+ row.find("*").each(function() {
+ updateElementIndex(this, options.prefix, totalForms.val());
+ });
+ // Insert the new form when it has been fully edited
+ row.insertBefore($(template));
+ // Update number of total forms
+ $(totalForms).val(parseInt(totalForms.val(), 10) + 1);
+ nextIndex += 1;
+ // Hide add button in case we've hit the max, except we want to add infinitely
+ if ((maxForms.val() !== '') && (maxForms.val()-totalForms.val()) <= 0) {
+ addButton.parent().hide();
+ }
+ // The delete button of each row triggers a bunch of other things
+ row.find("a." + options.deleteCssClass).click(function(e) {
+ e.preventDefault();
+ // Remove the parent form containing this button:
+ var row = $(this).parents("." + options.formCssClass);
+ row.remove();
+ nextIndex -= 1;
+ // If a post-delete callback was provided, call it with the deleted form:
+ if (options.removed) {
+ options.removed(row);
+ }
+ // Update the TOTAL_FORMS form count.
+ var forms = $("." + options.formCssClass);
+ $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);
+ // Show add button again once we drop below max
+ if ((maxForms.val() === '') || (maxForms.val()-forms.length) > 0) {
+ addButton.parent().show();
+ }
+ // Also, update names and ids for all remaining form controls
+ // so they remain in sequence:
+ for (var i=0, formCount=forms.length; i<formCount; i++)
+ {
+ updateElementIndex($(forms).get(i), options.prefix, i);
+ $(forms.get(i)).find("*").each(function() {
+ updateElementIndex(this, options.prefix, i);
+ });
+ }
+ });
+ // If a post-add callback was supplied, call it with the added form:
+ if (options.added) {
+ options.added(row);
+ }
+ });
+ }
+ return this;
+ };
+
+ /* Setup plugin defaults */
+ $.fn.formset.defaults = {
+ prefix: "form", // The form prefix for your django formset
+ addText: "add another", // Text for the add link
+ deleteText: "remove", // Text for the delete link
+ addCssClass: "add-row", // CSS class applied to the add link
+ deleteCssClass: "delete-row", // CSS class applied to the delete link
+ emptyCssClass: "empty-row", // CSS class applied to the empty row
+ formCssClass: "dynamic-form", // CSS class applied to each form in a formset
+ added: null, // Function called each time a new form is added
+ removed: null // Function called each time a form is deleted
+ };
+
+
+ // Tabular inlines ---------------------------------------------------------
+ $.fn.tabularFormset = function(options) {
+ var $rows = $(this);
+ var alternatingRows = function(row) {
+ $($rows.selector).not(".add-row").removeClass("row1 row2")
+ .filter(":even").addClass("row1").end()
+ .filter(":odd").addClass("row2");
+ };
+
+ var reinitDateTimeShortCuts = function() {
+ // Reinitialize the calendar and clock widgets by force
+ if (typeof DateTimeShortcuts != "undefined") {
+ $(".datetimeshortcuts").remove();
+ DateTimeShortcuts.init();
+ }
+ };
+
+ var updateSelectFilter = function() {
+ // If any SelectFilter widgets are a part of the new form,
+ // instantiate a new SelectFilter instance for it.
+ if (typeof SelectFilter != 'undefined'){
+ $('.selectfilter').each(function(index, value){
+ var namearr = value.name.split('-');
+ SelectFilter.init(value.id, namearr[namearr.length-1], false, options.adminStaticPrefix );
+ });
+ $('.selectfilterstacked').each(function(index, value){
+ var namearr = value.name.split('-');
+ SelectFilter.init(value.id, namearr[namearr.length-1], true, options.adminStaticPrefix );
+ });
+ }
+ };
+
+ var initPrepopulatedFields = function(row) {
+ row.find('.prepopulated_field').each(function() {
+ var field = $(this),
+ input = field.find('input, select, textarea'),
+ dependency_list = input.data('dependency_list') || [],
+ dependencies = [];
+ $.each(dependency_list, function(i, field_name) {
+ dependencies.push('#' + row.find('.field-' + field_name).find('input, select, textarea').attr('id'));
+ });
+ if (dependencies.length) {
+ input.prepopulate(dependencies, input.attr('maxlength'));
+ }
+ });
+ };
+
+ $rows.formset({
+ prefix: options.prefix,
+ addText: options.addText,
+ formCssClass: "dynamic-" + options.prefix,
+ deleteCssClass: "inline-deletelink",
+ deleteText: options.deleteText,
+ emptyCssClass: "empty-form",
+ removed: alternatingRows,
+ added: function(row) {
+ initPrepopulatedFields(row);
+ reinitDateTimeShortCuts();
+ updateSelectFilter();
+ alternatingRows(row);
+ }
+ });
+
+ return $rows;
+ };
+
+ // Stacked inlines ---------------------------------------------------------
+ $.fn.stackedFormset = function(options) {
+ var $rows = $(this);
+ var updateInlineLabel = function(row) {
+ $($rows.selector).find(".inline_label").each(function(i) {
+ var count = i + 1;
+ $(this).html($(this).html().replace(/(#\d+)/g, "#" + count));
+ });
+ };
+
+ var reinitDateTimeShortCuts = function() {
+ // Reinitialize the calendar and clock widgets by force, yuck.
+ if (typeof DateTimeShortcuts != "undefined") {
+ $(".datetimeshortcuts").remove();
+ DateTimeShortcuts.init();
+ }
+ };
+
+ var updateSelectFilter = function() {
+ // If any SelectFilter widgets were added, instantiate a new instance.
+ if (typeof SelectFilter != "undefined"){
+ $(".selectfilter").each(function(index, value){
+ var namearr = value.name.split('-');
+ SelectFilter.init(value.id, namearr[namearr.length-1], false, options.adminStaticPrefix);
+ });
+ $(".selectfilterstacked").each(function(index, value){
+ var namearr = value.name.split('-');
+ SelectFilter.init(value.id, namearr[namearr.length-1], true, options.adminStaticPrefix);
+ });
+ }
+ };
+
+ var initPrepopulatedFields = function(row) {
+ row.find('.prepopulated_field').each(function() {
+ var field = $(this),
+ input = field.find('input, select, textarea'),
+ dependency_list = input.data('dependency_list') || [],
+ dependencies = [];
+ $.each(dependency_list, function(i, field_name) {
+ dependencies.push('#' + row.find('.form-row .field-' + field_name).find('input, select, textarea').attr('id'));
+ });
+ if (dependencies.length) {
+ input.prepopulate(dependencies, input.attr('maxlength'));
+ }
+ });
+ };
+
+ $rows.formset({
+ prefix: options.prefix,
+ addText: options.addText,
+ formCssClass: "dynamic-" + options.prefix,
+ deleteCssClass: "inline-deletelink",
+ deleteText: options.deleteText,
+ emptyCssClass: "empty-form",
+ removed: updateInlineLabel,
+ added: (function(row) {
+ initPrepopulatedFields(row);
+ reinitDateTimeShortCuts();
+ updateSelectFilter();
+ updateInlineLabel(row);
+ })
+ });
+
+ return $rows;
+ };
})(django.jQuery);
14 django/contrib/admin/static/admin/js/inlines.min.js
View
@@ -1,5 +1,9 @@
-(function(b){b.fn.formset=function(g){var a=b.extend({},b.fn.formset.defaults,g),k=function(c,f,e){var d=RegExp("("+f+"-(\\d+|__prefix__))");f=f+"-"+e;b(c).attr("for")&&b(c).attr("for",b(c).attr("for").replace(d,f));if(c.id)c.id=c.id.replace(d,f);if(c.name)c.name=c.name.replace(d,f)};g=b("#id_"+a.prefix+"-TOTAL_FORMS").attr("autocomplete","off");var l=parseInt(g.val(),10),h=b("#id_"+a.prefix+"-MAX_NUM_FORMS").attr("autocomplete","off");g=h.val()===""||h.val()-g.val()>0;b(this).each(function(){b(this).not("."+
-a.emptyCssClass).addClass(a.formCssClass)});if(b(this).length&&g){var j;if(b(this).attr("tagName")=="TR"){g=this.eq(-1).children().length;b(this).parent().append('<tr class="'+a.addCssClass+'"><td colspan="'+g+'"><a href="javascript:void(0)">'+a.addText+"</a></tr>");j=b(this).parent().find("tr:last a")}else{b(this).filter(":last").after('<div class="'+a.addCssClass+'"><a href="javascript:void(0)">'+a.addText+"</a></div>");j=b(this).filter(":last").next().find("a")}j.click(function(c){c.preventDefault();
-var f=b("#id_"+a.prefix+"-TOTAL_FORMS");c=b("#"+a.prefix+"-empty");var e=c.clone(true);e.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+l);if(e.is("tr"))e.children(":last").append('<div><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></div>");else e.is("ul")||e.is("ol")?e.append('<li><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></li>"):e.children(":first").append('<span><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+
-a.deleteText+"</a></span>");e.find("*").each(function(){k(this,a.prefix,f.val())});e.insertBefore(b(c));b(f).val(parseInt(f.val(),10)+1);l+=1;h.val()!==""&&h.val()-f.val()<=0&&j.parent().hide();e.find("a."+a.deleteCssClass).click(function(d){d.preventDefault();d=b(this).parents("."+a.formCssClass);d.remove();l-=1;a.removed&&a.removed(d);d=b("."+a.formCssClass);b("#id_"+a.prefix+"-TOTAL_FORMS").val(d.length);if(h.val()===""||h.val()-d.length>0)j.parent().show();for(var i=0,m=d.length;i<m;i++){k(b(d).get(i),
-a.prefix,i);b(d.get(i)).find("*").each(function(){k(this,a.prefix,i)})}});a.added&&a.added(e)})}return this};b.fn.formset.defaults={prefix:"form",addText:"add another",deleteText:"remove",addCssClass:"add-row",deleteCssClass:"delete-row",emptyCssClass:"empty-row",formCssClass:"dynamic-form",added:null,removed:null}})(django.jQuery);
+(function(b){b.fn.formset=function(d){var a=b.extend({},b.fn.formset.defaults,d),c=b(this),d=c.parent(),i=function(a,e,g){var d=RegExp("("+e+"-(\\d+|__prefix__))"),e=e+"-"+g;b(a).attr("for")&&b(a).attr("for",b(a).attr("for").replace(d,e));a.id&&(a.id=a.id.replace(d,e));a.name&&(a.name=a.name.replace(d,e))},f=b("#id_"+a.prefix+"-TOTAL_FORMS").attr("autocomplete","off"),g=parseInt(f.val(),10),e=b("#id_"+a.prefix+"-MAX_NUM_FORMS").attr("autocomplete","off"),f=""===e.val()||0<e.val()-f.val();c.each(function(){b(this).not("."+
+a.emptyCssClass).addClass(a.formCssClass)});if(c.length&&f){var h;"TR"==c.attr("tagName")?(c=this.eq(-1).children().length,d.append('<tr class="'+a.addCssClass+'"><td colspan="'+c+'"><a href="javascript:void(0)">'+a.addText+"</a></tr>"),h=d.find("tr:last a")):(c.filter(":last").after('<div class="'+a.addCssClass+'"><a href="javascript:void(0)">'+a.addText+"</a></div>"),h=c.filter(":last").next().find("a"));h.click(function(d){d.preventDefault();var f=b("#id_"+a.prefix+"-TOTAL_FORMS"),d=b("#"+a.prefix+
+"-empty"),c=d.clone(true);c.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+g);c.is("tr")?c.children(":last").append('<div><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></div>"):c.is("ul")||c.is("ol")?c.append('<li><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></li>"):c.children(":first").append('<span><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></span>");c.find("*").each(function(){i(this,
+a.prefix,f.val())});c.insertBefore(b(d));b(f).val(parseInt(f.val(),10)+1);g=g+1;e.val()!==""&&e.val()-f.val()<=0&&h.parent().hide();c.find("a."+a.deleteCssClass).click(function(d){d.preventDefault();d=b(this).parents("."+a.formCssClass);d.remove();g=g-1;a.removed&&a.removed(d);d=b("."+a.formCssClass);b("#id_"+a.prefix+"-TOTAL_FORMS").val(d.length);(e.val()===""||e.val()-d.length>0)&&h.parent().show();for(var c=0,f=d.length;c<f;c++){i(b(d).get(c),a.prefix,c);b(d.get(c)).find("*").each(function(){i(this,
+a.prefix,c)})}});a.added&&a.added(c)})}return this};b.fn.formset.defaults={prefix:"form",addText:"add another",deleteText:"remove",addCssClass:"add-row",deleteCssClass:"delete-row",emptyCssClass:"empty-row",formCssClass:"dynamic-form",added:null,removed:null};b.fn.tabularFormset=function(d){var a=b(this),c=function(){b(a.selector).not(".add-row").removeClass("row1 row2").filter(":even").addClass("row1").end().filter(":odd").addClass("row2")};a.formset({prefix:d.prefix,addText:d.addText,formCssClass:"dynamic-"+
+d.prefix,deleteCssClass:"inline-deletelink",deleteText:d.deleteText,emptyCssClass:"empty-form",removed:c,added:function(a){a.find(".prepopulated_field").each(function(){var d=b(this).find("input, select, textarea"),c=d.data("dependency_list")||[],e=[];b.each(c,function(d,b){e.push("#"+a.find(".field-"+b).find("input, select, textarea").attr("id"))});e.length&&d.prepopulate(e,d.attr("maxlength"))});"undefined"!=typeof DateTimeShortcuts&&(b(".datetimeshortcuts").remove(),DateTimeShortcuts.init());"undefined"!=
+typeof SelectFilter&&(b(".selectfilter").each(function(a,b){var c=b.name.split("-");SelectFilter.init(b.id,c[c.length-1],false,d.adminStaticPrefix)}),b(".selectfilterstacked").each(function(a,b){var c=b.name.split("-");SelectFilter.init(b.id,c[c.length-1],true,d.adminStaticPrefix)}));c(a)}});return a};b.fn.stackedFormset=function(d){var a=b(this),c=function(){b(a.selector).find(".inline_label").each(function(a){a+=1;b(this).html(b(this).html().replace(/(#\d+)/g,"#"+a))})};a.formset({prefix:d.prefix,
+addText:d.addText,formCssClass:"dynamic-"+d.prefix,deleteCssClass:"inline-deletelink",deleteText:d.deleteText,emptyCssClass:"empty-form",removed:c,added:function(a){a.find(".prepopulated_field").each(function(){var d=b(this).find("input, select, textarea"),c=d.data("dependency_list")||[],e=[];b.each(c,function(d,b){e.push("#"+a.find(".form-row .field-"+b).find("input, select, textarea").attr("id"))});e.length&&d.prepopulate(e,d.attr("maxlength"))});"undefined"!=typeof DateTimeShortcuts&&(b(".datetimeshortcuts").remove(),
+DateTimeShortcuts.init());"undefined"!=typeof SelectFilter&&(b(".selectfilter").each(function(a,b){var c=b.name.split("-");SelectFilter.init(b.id,c[c.length-1],false,d.adminStaticPrefix)}),b(".selectfilterstacked").each(function(a,b){var c=b.name.split("-");SelectFilter.init(b.id,c[c.length-1],true,d.adminStaticPrefix)}));c(a)}});return a}})(django.jQuery);
64 django/contrib/admin/templates/admin/edit_inline/stacked.html
View
@@ -20,63 +20,11 @@
<script type="text/javascript">
(function($) {
- $(document).ready(function() {
- var rows = "#{{ inline_admin_formset.formset.prefix }}-group .inline-related";
- var updateInlineLabel = function(row) {
- $(rows).find(".inline_label").each(function(i) {
- var count = i + 1;
- $(this).html($(this).html().replace(/(#\d+)/g, "#" + count));
- });
- };
- var reinitDateTimeShortCuts = function() {
- // Reinitialize the calendar and clock widgets by force, yuck.
- if (typeof DateTimeShortcuts != "undefined") {
- $(".datetimeshortcuts").remove();
- DateTimeShortcuts.init();
- }
- };
- var updateSelectFilter = function() {
- // If any SelectFilter widgets were added, instantiate a new instance.
- if (typeof SelectFilter != "undefined"){
- $(".selectfilter").each(function(index, value){
- var namearr = value.name.split('-');
- SelectFilter.init(value.id, namearr[namearr.length-1], false, "{% static "admin/" %}");
- });
- $(".selectfilterstacked").each(function(index, value){
- var namearr = value.name.split('-');
- SelectFilter.init(value.id, namearr[namearr.length-1], true, "{% static "admin/" %}");
- });
- }
- };
- var initPrepopulatedFields = function(row) {
- row.find('.prepopulated_field').each(function() {
- var field = $(this);
- var input = field.find('input, select, textarea');
- var dependency_list = input.data('dependency_list') || [];
- var dependencies = [];
- $.each(dependency_list, function(i, field_name) {
- dependencies.push('#' + row.find('.form-row .field-' + field_name).find('input, select, textarea').attr('id'));
- });
- if (dependencies.length) {
- input.prepopulate(dependencies, input.attr('maxlength'));
- }
- });
- };
- $(rows).formset({
- prefix: "{{ inline_admin_formset.formset.prefix }}",
- addText: "{% blocktrans with verbose_name=inline_admin_formset.opts.verbose_name|title %}Add another {{ verbose_name }}{% endblocktrans %}",
- formCssClass: "dynamic-{{ inline_admin_formset.formset.prefix }}",
- deleteCssClass: "inline-deletelink",
- deleteText: "{% trans "Remove" %}",
- emptyCssClass: "empty-form",
- removed: updateInlineLabel,
- added: (function(row) {
- initPrepopulatedFields(row);
- reinitDateTimeShortCuts();
- updateSelectFilter();
- updateInlineLabel(row);
- })
- });
- });
+ $("#{{ inline_admin_formset.formset.prefix }}-group .inline-related").stackedFormset({
+ prefix: '{{ inline_admin_formset.formset.prefix }}',
+ adminStaticPrefix: '{% static "admin/" %}',
+ deleteText: "{% trans "Remove" %}",
+ addText: "{% blocktrans with verbose_name=inline_admin_formset.opts.verbose_name|title %}Add another {{ verbose_name }}{% endblocktrans %}"
+ });
})(django.jQuery);
</script>
65 django/contrib/admin/templates/admin/edit_inline/tabular.html
View
@@ -67,64 +67,13 @@
</div>
<script type="text/javascript">
+
(function($) {
- $(document).ready(function($) {
- var rows = "#{{ inline_admin_formset.formset.prefix }}-group .tabular.inline-related tbody tr";
- var alternatingRows = function(row) {
- $(rows).not(".add-row").removeClass("row1 row2")
- .filter(":even").addClass("row1").end()
- .filter(rows + ":odd").addClass("row2");
- }
- var reinitDateTimeShortCuts = function() {
- // Reinitialize the calendar and clock widgets by force
- if (typeof DateTimeShortcuts != "undefined") {
- $(".datetimeshortcuts").remove();
- DateTimeShortcuts.init();
- }
- }
- var updateSelectFilter = function() {
- // If any SelectFilter widgets are a part of the new form,
- // instantiate a new SelectFilter instance for it.
- if (typeof SelectFilter != "undefined"){
- $(".selectfilter").each(function(index, value){
- var namearr = value.name.split('-');
- SelectFilter.init(value.id, namearr[namearr.length-1], false, "{% static "admin/" %}");
- });
- $(".selectfilterstacked").each(function(index, value){
- var namearr = value.name.split('-');
- SelectFilter.init(value.id, namearr[namearr.length-1], true, "{% static "admin/" %}");
- });
- }
- }
- var initPrepopulatedFields = function(row) {
- row.find('.prepopulated_field').each(function() {
- var field = $(this);
- var input = field.find('input, select, textarea');
- var dependency_list = input.data('dependency_list') || [];
- var dependencies = [];
- $.each(dependency_list, function(i, field_name) {
- dependencies.push('#' + row.find('.field-' + field_name).find('input, select, textarea').attr('id'));
- });
- if (dependencies.length) {
- input.prepopulate(dependencies, input.attr('maxlength'));
- }
- });
- }
- $(rows).formset({
- prefix: "{{ inline_admin_formset.formset.prefix }}",
- addText: "{% blocktrans with verbose_name=inline_admin_formset.opts.verbose_name|title %}Add another {{ verbose_name }}{% endblocktrans %}",
- formCssClass: "dynamic-{{ inline_admin_formset.formset.prefix }}",
- deleteCssClass: "inline-deletelink",
- deleteText: "{% trans "Remove" %}",
- emptyCssClass: "empty-form",
- removed: alternatingRows,
- added: (function(row) {
- initPrepopulatedFields(row);
- reinitDateTimeShortCuts();
- updateSelectFilter();
- alternatingRows(row);
- })
- });
- });
+ $("#{{ inline_admin_formset.formset.prefix }}-group .tabular.inline-related tbody tr").tabularFormset({
+ prefix: "{{ inline_admin_formset.formset.prefix }}",
+ adminStaticPrefix: '{% static "admin/" %}',
+ addText: "{% blocktrans with inline_admin_formset.opts.verbose_name|title as verbose_name %}Add another {{ verbose_name }}{% endblocktrans %}",
+ deleteText: "{% trans 'Remove' %}"
+ });
})(django.jQuery);
</script>
2  django/contrib/admin/templatetags/admin_list.py
View
@@ -182,7 +182,7 @@ def items_for_result(cl, result, form):
row_class = ''
try:
f, attr, value = lookup_field(field_name, result, cl.model_admin)
- except (AttributeError, ObjectDoesNotExist):
+ except ObjectDoesNotExist:
result_repr = EMPTY_CHANGELIST_VALUE
else:
if f is None:
2  django/contrib/admin/util.py
View
@@ -4,7 +4,7 @@
import decimal
from django.db import models
-from django.db.models.sql.constants import LOOKUP_SEP
+from django.db.models.constants import LOOKUP_SEP
from django.db.models.deletion import Collector
from django.db.models.related import RelatedObject
from django.forms.forms import pretty_name
6 django/contrib/auth/decorators.py
View
@@ -8,6 +8,7 @@
from django.core.exceptions import PermissionDenied
from django.utils.decorators import available_attrs
from django.utils.encoding import force_str
+from django.shortcuts import resolve_url
def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
@@ -23,11 +24,10 @@ def _wrapped_view(request, *args, **kwargs):
if test_func(request.user):
return view_func(request, *args, **kwargs)
path = request.build_absolute_uri()
- # urlparse chokes on lazy objects in Python 3
- login_url_as_str = force_str(login_url or settings.LOGIN_URL)
+ resolved_login_url = resolve_url(login_url or settings.LOGIN_URL)
# If the login url is the same scheme and net location then just
# use the path as the "next" url.
- login_scheme, login_netloc = urlparse(login_url_as_str)[:2]
+ login_scheme, login_netloc = urlparse(resolved_login_url)[:2]
current_scheme, current_netloc = urlparse(path)[:2]
if ((not login_scheme or login_scheme == current_scheme) and
(not login_netloc or login_netloc == current_netloc)):
2  django/contrib/auth/tests/decorators.py
View
@@ -28,7 +28,7 @@ def normal_view(request):
pass
login_required(normal_view)
- def testLoginRequired(self, view_url='/login_required/', login_url=settings.LOGIN_URL):
+ def testLoginRequired(self, view_url='/login_required/', login_url='/login/'):
"""
Check that login_required works on a simple view wrapped in a
login_required decorator.
11 django/contrib/auth/tests/models.py
View
@@ -1,8 +1,9 @@
from django.conf import settings
+from django.contrib.auth.models import (Group, User, SiteProfileNotAvailable,
+ UserManager)
from django.test import TestCase, skipIfCustomUser
from django.test.utils import override_settings
-from django.contrib.auth.models import (Group, User,
- SiteProfileNotAvailable, UserManager)
+from django.utils import six
@skipIfCustomUser
@@ -14,19 +15,19 @@ def test_site_profile_not_available(self):
# calling get_profile without AUTH_PROFILE_MODULE set
del settings.AUTH_PROFILE_MODULE
- with self.assertRaisesRegexp(SiteProfileNotAvailable,
+ with six.assertRaisesRegex(self, SiteProfileNotAvailable,
"You need to set AUTH_PROFILE_MODULE in your project"):
user.get_profile()
# Bad syntax in AUTH_PROFILE_MODULE:
settings.AUTH_PROFILE_MODULE = 'foobar'
- with self.assertRaisesRegexp(SiteProfileNotAvailable,
+ with six.assertRaisesRegex(self, SiteProfileNotAvailable,
"app_label and model_name should be separated by a dot"):
user.get_profile()
# module that doesn't exist
settings.AUTH_PROFILE_MODULE = 'foo.bar'
- with self.assertRaisesRegexp(SiteProfileNotAvailable,
+ with six.assertRaisesRegex(self, SiteProfileNotAvailable,
"Unable to load the profile model"):
user.get_profile()
18 django/contrib/auth/views.py
View
@@ -7,9 +7,9 @@
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect, QueryDict
from django.template.response import TemplateResponse
-from django.utils.encoding import force_str
from django.utils.http import base36_to_int
from django.utils.translation import ugettext as _
+from django.shortcuts import resolve_url
from django.views.decorators.debug import sensitive_post_parameters
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_protect
@@ -38,16 +38,16 @@ def login(request, template_name='registration/login.html',
if request.method == "POST":
form = authentication_form(data=request.POST)
if form.is_valid():
- netloc = urlparse(redirect_to)[1]
-
# Use default setting if redirect_to is empty
if not redirect_to:
redirect_to = settings.LOGIN_REDIRECT_URL
+ redirect_to = resolve_url(redirect_to)
+ netloc = urlparse(redirect_to)[1]
# Heavier security check -- don't allow redirection to a different
# host.
- elif netloc and netloc != request.get_host():
- redirect_to = settings.LOGIN_REDIRECT_URL
+ if netloc and netloc != request.get_host():
+ redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)
# Okay, security checks complete. Log the user in.
auth_login(request, form.get_user())
@@ -112,6 +112,7 @@ def logout_then_login(request, login_url=None, current_app=None, extra_context=N
"""
if not login_url:
login_url = settings.LOGIN_URL
+ login_url = resolve_url(login_url)
return logout(request, login_url, current_app=current_app, extra_context=extra_context)
@@ -120,10 +121,9 @@ def redirect_to_login(next, login_url=None,
"""
Redirects the user to the login page, passing the given 'next' page
"""
- # urlparse chokes on lazy objects in Python 3
- login_url_as_str = force_str(login_url or settings.LOGIN_URL)
+ resolved_url = resolve_url(login_url or settings.LOGIN_URL)
- login_url_parts = list(urlparse(login_url_as_str))
+ login_url_parts = list(urlparse(resolved_url))
if redirect_field_name:
querystring = QueryDict(login_url_parts[4], mutable=True)
querystring[redirect_field_name] = next
@@ -236,7 +236,7 @@ def password_reset_complete(request,
template_name='registration/password_reset_complete.html',
current_app=None, extra_context=None):
context = {
- 'login_url': settings.LOGIN_URL
+ 'login_url': resolve_url(settings.LOGIN_URL)
}
if extra_context is not None:
context.update(extra_context)
2  django/contrib/gis/db/models/sql/where.py
View
@@ -1,5 +1,5 @@
+from django.db.models.constants import LOOKUP_SEP
from django.db.models.fields import FieldDoesNotExist
-from django.db.models.sql.constants import LOOKUP_SEP
from django.db.models.sql.expressions import SQLEvaluator
from django.db.models.sql.where import Constraint, WhereNode
from django.contrib.gis.db.models.fields import GeometryField
10 django/contrib/localflavor/hr/forms.py
View
@@ -4,6 +4,7 @@
"""
from __future__ import absolute_import, unicode_literals
+import datetime
import re
from django.contrib.localflavor.hr.hr_choices import (
@@ -91,17 +92,16 @@ def clean(self, value):
dd = int(matches.group('dd'))
mm = int(matches.group('mm'))
yyy = int(matches.group('yyy'))
- import datetime
try:
- datetime.date(yyy,mm,dd)
- except:
+ datetime.date(yyy, mm, dd)
+ except ValueError:
raise ValidationError(self.error_messages['date'])
# Validate checksum.
k = matches.group('k')
checksum = 0
- for i,j in zip(range(7,1,-1),range(6)):
- checksum+=i*(int(value[j])+int(value[13-i]))
+ for i, j in zip(range(7, 1, -1), range(6)):
+ checksum += i * (int(value[j]) + int(value[13 - i]))
m = 11 - checksum % 11
if m == 10:
raise ValidationError(self.error_messages['invalid'])
22 django/contrib/localflavor/ro/forms.py
View
@@ -4,6 +4,8 @@
"""
from __future__ import absolute_import, unicode_literals
+import datetime
+
from django.contrib.localflavor.ro.ro_counties import COUNTIES_CHOICES
from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError, Field, RegexField, Select
@@ -69,10 +71,9 @@ def clean(self, value):
if value in EMPTY_VALUES:
return ''
# check birthdate digits
- import datetime
try:
- datetime.date(int(value[1:3]),int(value[3:5]),int(value[5:7]))
- except:
+ datetime.date(int(value[1:3]), int(value[3:5]), int(value[5:7]))
+ except ValueError:
raise ValidationError(self.error_messages['invalid'])
# checksum
key = '279146358279'
@@ -118,7 +119,7 @@ def clean(self, value):
# search for county name
normalized_CC = []
for entry in COUNTIES_CHOICES:
- normalized_CC.append((entry[0],entry[1].upper()))
+ normalized_CC.append((entry[0], entry[1].upper()))
for entry in normalized_CC:
if entry[1] == value:
return entry[0]
@@ -153,8 +154,8 @@ def clean(self, value):
value = super(ROIBANField, self).clean(value)
if value in EMPTY_VALUES:
return ''
- value = value.replace('-','')
- value = value.replace(' ','')
+ value = value.replace('-', '')
+ value = value.replace(' ', '')
value = value.upper()
if value[0:2] != 'RO':
raise ValidationError(self.error_messages['invalid'])
@@ -185,10 +186,10 @@ def clean(self, value):
value = super(ROPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
return ''
- value = value.replace('-','')
- value = value.replace('(','')
- value = value.replace(')','')
- value = value.replace(' ','')
+ value = value.replace('-', '')
+ value = value.replace('(', '')
+ value = value.replace(')', '')
+ value = value.replace(' ', '')
if len(value) != 10:
raise ValidationError(self.error_messages['invalid'])
return value
@@ -202,4 +203,3 @@ class ROPostalCodeField(RegexField):
def __init__(self, max_length=6, min_length=6, *args, **kwargs):
super(ROPostalCodeField, self).__init__(r'^[0-9][0-8][0-9]{4}$',
max_length, min_length, *args, **kwargs)
-
6 django/contrib/markup/templatetags/markup.py
View
@@ -47,6 +47,9 @@ def markdown(value, arg=''):
they will be silently ignored.
"""
+ import warnings
+ warnings.warn('The markdown filter has been deprecated',
+ category=DeprecationWarning)
try:
import markdown
except ImportError:
@@ -72,6 +75,9 @@ def markdown(value, arg=''):
@register.filter(is_safe=True)
def restructuredtext(value):
+ import warnings
+ warnings.warn('The restructuredtext filter has been deprecated',
+ category=DeprecationWarning)
try:
from docutils.core import publish_parts
except ImportError:
11 django/contrib/markup/tests.py
View
@@ -1,7 +1,9 @@
# Quick tests for the markup templatetags (django.contrib.markup)
import re
+import warnings
from django.template import Template, Context
+from django import test
from django.utils import unittest
from django.utils.html import escape
@@ -21,7 +23,7 @@
except ImportError:
docutils = None
-class Templates(unittest.TestCase):
+class Templates(test.TestCase):
textile_content = """Paragraph 1
@@ -37,6 +39,13 @@ class Templates(unittest.TestCase):
.. _link: http://www.example.com/"""
+ def setUp(self):
+ self.save_warnings_state()
+ warnings.filterwarnings('ignore', category=DeprecationWarning, module='django.contrib.markup')
+
+ def tearDown(self):
+ self.restore_warnings_state()
+
@unittest.skipUnless(textile, 'textile not installed')
def test_textile(self):
t = Template("{% load markup %}{{ textile_content|textile }}")
8 django/contrib/messages/storage/cookie.py
View
@@ -46,10 +46,10 @@ class CookieStorage(BaseStorage):
Stores messages in a cookie.
"""
cookie_name = 'messages'
- # We should be able to store 4K in a cookie, but Internet Explorer
- # imposes 4K as the *total* limit for a domain. To allow other
- # cookies, we go for 3/4 of 4K.
- max_cookie_size = 3072
+ # uwsgi's default configuration enforces a maximum size of 4kb for all the
+ # HTTP headers. In order to leave some room for other cookies and headers,
+ # restrict the session cookie to 1/2 of 4kb. See #18781.
+ max_cookie_size = 2048
not_finished = '__messagesnotfinished__'
def _get(self, *args, **kwargs):
10 django/contrib/messages/tests/base.py
View
@@ -152,7 +152,7 @@ def test_full_request_response_cycle(self):
cycle.
"""
data = {
- 'messages': ['Test message %d' % x for x in range(10)],
+ 'messages': ['Test message %d' % x for x in range(5)],
}
show_url = reverse('django.contrib.messages.tests.urls.show')
for level in ('debug', 'info', 'success', 'warning', 'error'):
@@ -170,7 +170,7 @@ def test_full_request_response_cycle(self):
@override_settings(MESSAGE_LEVEL=constants.DEBUG)
def test_with_template_response(self):
data = {
- 'messages': ['Test message %d' % x for x in range(10)],
+ 'messages': ['Test message %d' % x for x in range(5)],
}
show_url = reverse('django.contrib.messages.tests.urls.show_template_response')
for level in self.levels.keys():
@@ -194,7 +194,7 @@ def test_multiple_posts(self):
before a GET.
"""
data = {
- 'messages': ['Test message %d' % x for x in range(10)],
+ 'messages': ['Test message %d' % x for x in range(5)],
}
show_url = reverse('django.contrib.messages.tests.urls.show')
messages = []
@@ -226,7 +226,7 @@ def test_middleware_disabled(self):
when one attempts to store a message.
"""
data = {
- 'messages': ['Test message %d' % x for x in range(10)],
+ 'messages': ['Test message %d' % x for x in range(5)],
}
show_url = reverse('django.contrib.messages.tests.urls.show')
for level in ('debug', 'info', 'success', 'warning', 'error'):
@@ -251,7 +251,7 @@ def test_middleware_disabled_fail_silently(self):
raised if 'fail_silently' = True
"""
data = {
- 'messages': ['Test message %d' % x for x in range(10)],
+ 'messages': ['Test message %d' % x for x in range(5)],
'fail_silently': True,
}
show_url = reverse('django.contrib.messages.tests.urls.show')
12 django/contrib/sessions/tests.py
View
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta
+from datetime import timedelta
import shutil
import string
import tempfile
@@ -302,11 +302,10 @@ def test_exists_searches_cache_first(self):
self.assertTrue(self.session.exists(self.session.session_key))
def test_load_overlong_key(self):
- with warnings.catch_warnings(record=True) as w:
- warnings.simplefilter("always")
+ # Some backends might issue a warning
+ with warnings.catch_warnings():
self.session._session_key = (string.ascii_letters + string.digits) * 20
self.assertEqual(self.session.load(), {})
- self.assertEqual(len(w), 1)
@override_settings(USE_TZ=True)
@@ -352,11 +351,10 @@ class CacheSessionTests(SessionTestsMixin, unittest.TestCase):
backend = CacheSession
def test_load_overlong_key(self):
- with warnings.catch_warnings(record=True) as w:
- warnings.simplefilter("always")
+ # Some backends might issue a warning
+ with warnings.catch_warnings():
self.session._session_key = (string.ascii_letters + string.digits) * 20
self.assertEqual(self.session.load(), {})
- self.assertEqual(len(w), 1)
class SessionMiddlewareTests(unittest.TestCase):
2  django/core/cache/backends/memcached.py
View
@@ -141,7 +141,7 @@ def __init__(self, server, params):
)
try:
import memcache
- except:
+ except ImportError:
raise InvalidCacheBackendError(
"Memcached cache backend requires either the 'memcache' or 'cmemcache' library"
)
2  django/core/mail/backends/console.py
View
@@ -21,7 +21,7 @@ def send_messages(self, email_messages):
stream_created = self.open()
for message in email_messages:
self.stream.write('%s\n' % message.message().as_string())
- self.stream.write('-'*79)
+ self.stream.write('-' * 79)
self.stream.write('\n')
self.stream.flush() # flush after each message
if stream_created:
3  django/core/management/__init__.py
View
@@ -5,6 +5,7 @@
import imp
import warnings
+from django.core.exceptions import ImproperlyConfigured
from django.core.management.base import BaseCommand, CommandError, handle_default_options
from django.core.management.color import color_style
from django.utils.importlib import import_module
@@ -105,7 +106,7 @@ def get_commands():
try:
from django.conf import settings
apps = settings.INSTALLED_APPS
- except (AttributeError, EnvironmentError, ImportError):
+ except (AttributeError, ImproperlyConfigured):
apps = []
# Find and load the management module for each installed app.
7 django/db/backends/__init__.py
View
@@ -1034,9 +1034,12 @@ def get_key_columns(self, cursor, table_name):
def get_primary_key_column(self, cursor, table_name):
"""
- Backends can override this to return the column name of the primary key for the given table.
+ Returns the name of the primary key column for the given table.
"""
- raise NotImplementedError
+ for column in six.iteritems(self.get_indexes(cursor, table_name)):
+ if column[1]['primary_key']:
+ return column[0]
+ return None
def get_indexes(self, cursor, table_name):
"""
7 django/db/backends/creation.py
View
@@ -1,8 +1,10 @@
+import hashlib
import sys
import time
from django.conf import settings
from django.db.utils import load_backend
+from django.utils.encoding import force_bytes
from django.utils.six.moves import input
# The prefix to put on the default database name when creating
@@ -27,7 +29,10 @@ def _digest(self, *args):
Generates a 32-bit digest of a set of arguments that can be used to
shorten identifying names.
"""
- return '%x' % (abs(hash(args)) % 4294967296) # 2**32
+ h = hashlib.md5()
+ for arg in args:
+ h.update(force_bytes(arg))
+ return h.hexdigest()[:8]
def sql_create_model(self, model, style, known_models=set()):
"""
10 django/db/backends/mysql/introspection.py
View
@@ -2,7 +2,6 @@
from .base import FIELD_TYPE
from django.db.backends import BaseDatabaseIntrospection
-from django.utils import six
foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)")
@@ -88,15 +87,6 @@ def get_key_columns(self, cursor, table_name):
key_columns.extend(cursor.fetchall())
return key_columns
- def get_primary_key_column(self, cursor, table_name):
- """
- Returns the name of the primary key column for the given table
- """
- for column in six.iteritems(self.get_indexes(cursor, table_name)):
- if column[1]['primary_key']:
- return column[0]
- return None
-
def get_indexes(self, cursor, table_name):
cursor.execute("SHOW INDEX FROM %s" % self.connection.ops.quote_name(table_name))
# Do a two-pass search for indexes: on first pass check which indexes
5 django/db/backends/sqlite3/base.py
View
@@ -412,7 +412,4 @@ def _sqlite_format_dtdelta(dt, conn, days, secs, usecs):
return str(dt)
def _sqlite_regexp(re_pattern, re_string):
- try:
- return bool(re.search(re_pattern, re_string))
- except:
- return False
+ return bool(re.search(re_pattern, re_string))
7 django/db/models/constants.py
View
@@ -0,0 +1,7 @@
+"""
+Constants used across the ORM in general.
+"""
+
+# Separator used to split filter strings apart.
+LOOKUP_SEP = '__'
+
3  django/db/models/query.py
View
@@ -8,6 +8,7 @@
from django.core import exceptions
from django.db import connections, router, transaction, IntegrityError
+from django.db.models.constants import LOOKUP_SEP
from django.db.models.fields import AutoField
from django.db.models.query_utils import (Q, select_related_descend,
deferred_class_factory, InvalidQuery)
@@ -1613,8 +1614,6 @@ def prefetch_related_objects(result_cache, related_lookups):
Populates prefetched objects caches for a list of results
from a QuerySet
"""
- from django.db.models.sql.constants import LOOKUP_SEP
-
if len(result_cache) == 0:
return # nothing to do
13 django/db/models/sql/compiler.py
View
@@ -3,8 +3,10 @@
from django.core.exceptions import FieldError
from django.db import transaction
from django.db.backends.util import truncate_name
+from django.db.models.constants import LOOKUP_SEP
from django.db.models.query_utils import select_related_descend
-from django.db.models.sql.constants import *
+from django.db.models.sql.constants import (SINGLE, MULTI, ORDER_DIR,
+ GET_ITERATOR_CHUNK_SIZE)
from django.db.models.sql.datastructures import EmptyResultSet
from django.db.models.sql.expressions import SQLEvaluator
from django.db.models.sql.query import get_order_dir, Query
@@ -811,7 +813,7 @@ def execute_sql(self, result_type=MULTI):
raise EmptyResultSet
except EmptyResultSet:
if result_type == MULTI:
- return empty_iter()
+ return iter([])
else:
return
@@ -1088,13 +1090,6 @@ def results_iter(self):
yield date
-def empty_iter():
- """
- Returns an iterator containing no results.
- """
- yield next(iter([]))
-
-
def order_modified_iter(cursor, trim, sentinel):
"""
Yields blocks of rows from a cursor. We use this iterator in the special
11 django/db/models/sql/constants.py
View
@@ -1,7 +1,13 @@
+"""
+Constants specific to the SQL storage portion of the ORM.
+"""
+
from collections import namedtuple
import re
-# Valid query types (a set is used for speedy lookups).
+# Valid query types (a set is used for speedy lookups). These are (currently)
+# considered SQL-specific; other storage systems may choose to use different
+# lookup types.
QUERY_TERMS = set([
'exact', 'iexact', 'contains', 'icontains', 'gt', 'gte', 'lt', 'lte', 'in',
'startswith', 'istartswith', 'endswith', 'iendswith', 'range', 'year',
@@ -12,9 +18,6 @@
# Larger values are slightly faster at the expense of more storage space.
GET_ITERATOR_CHUNK_SIZE = 100
-# Separator used to split filter strings apart.
-LOOKUP_SEP = '__'
-
# Constants to make looking up tuple values clearer.
# Join lists (indexes into the tuples that are values in the alias_map
# dictionary in the Query class).
2  django/db/models/sql/expressions.py
View
@@ -1,6 +1,6 @@
from django.core.exceptions import FieldError
+from django.db.models.constants import LOOKUP_SEP
from django.db.models.fields import FieldDoesNotExist
-from django.db.models.sql.constants import LOOKUP_SEP
class SQLEvaluator(object):
def __init__(self, expression, query, allow_joins=True):
6 django/db/models/sql/query.py
View
@@ -15,11 +15,12 @@
from django.utils import six
from django.db import connections, DEFAULT_DB_ALIAS
from django.db.models import signals
+from django.db.models.constants import LOOKUP_SEP
from django.db.models.expressions import ExpressionNode
from django.db.models.fields import FieldDoesNotExist
-from django.db.models.query_utils import InvalidQuery
from django.db.models.sql import aggregates as base_aggregates_module
-from django.db.models.sql.constants import *
+from django.db.models.sql.constants import (QUERY_TERMS, ORDER_DIR, SINGLE,
+ ORDER_PATTERN, JoinInfo)
from django.db.models.sql.datastructures import EmptyResultSet, Empty, MultiJoin
from django.db.models.sql.expressions import SQLEvaluator
from django.db.models.sql.where import (WhereNode, Constraint, EverythingNode,
@@ -28,6 +29,7 @@
__all__ = ['Query', 'RawQuery']
+
class RawQuery(object):
"""
A single raw SQL query
1  django/db/models/sql/subqueries.py
View
@@ -3,6 +3,7 @@
"""
from django.core.exceptions import FieldError
+from django.db.models.constants import LOOKUP_SEP
from django.db.models.fields import DateField, FieldDoesNotExist
from django.db.models.sql.constants import *
from django.db.models.sql.datastructures import Date
8 django/forms/widgets.py
View
@@ -507,11 +507,7 @@ def __init__(self, attrs=None, check_test=None):
def render(self, name, value, attrs=None):
final_attrs = self.build_attrs(attrs, type='checkbox', name=name)
- try:
- result = self.check_test(value)
- except: # Silently catch exceptions
- result = False
- if result:
+ if self.check_test(value):
final_attrs['checked'] = 'checked'
if not (value is True or value is False or value is None or value == ''):
# Only add the 'value' attribute if a value is non-empty.
@@ -525,7 +521,7 @@ def value_from_datadict(self, data, files, name):
return False
value = data.get(name)
# Translate true and false strings to boolean values.
- values = {'true': True, 'false': False}
+ values = {'true': True, 'false': False}
if isinstance(value, six.string_types):
value = values.get(value.lower(), value)
return value
56 django/http/__init__.py
View
@@ -2,6 +2,7 @@
import copy
import datetime
+from email.header import Header
import os
import re
import sys
@@ -560,31 +561,44 @@ def serialize(self):
else:
__str__ = serialize
- def _convert_to_ascii(self, *values):
- """Converts all values to ascii strings."""
- for value in values:
- if not isinstance(value, six.string_types):
- value = str(value)
- try:
- if six.PY3:
- # Ensure string only contains ASCII
- value.encode('us-ascii')
+ def _convert_to_charset(self, value, charset, mime_encode=False):
+ """Converts headers key/value to ascii/latin1 native strings.
+
+ `charset` must be 'ascii' or 'latin-1'. If `mime_encode` is True and
+ `value` value can't be represented in the given charset, MIME-encoding
+ is applied.
+ """
+ if not isinstance(value, (bytes, six.text_type)):
+ value = str(value)
+ try:
+ if six.PY3:
+ if isinstance(value, str):
+ # Ensure string is valid in given charset
+ value.encode(charset)
else:
- if isinstance(value, str):
- # Ensure string only contains ASCII
- value.decode('us-ascii')
- else:
- # Convert unicode to an ASCII string
- value = value.encode('us-ascii')
- except UnicodeError as e:
- e.reason += ', HTTP response headers must be in US-ASCII format'
+ # Convert bytestring using given charset
+ value = value.decode(charset)
+ else:
+ if isinstance(value, str):
+ # Ensure string is valid in given charset
+ value.decode(charset)
+ else:
+ # Convert unicode string to given charset
+ value = value.encode(charset)
+ except UnicodeError as e:
+ if mime_encode:
+ # Wrapping in str() is a workaround for #12422 under Python 2.
+ value = str(Header(value, 'utf-8').encode())
+ else:
+ e.reason += ', HTTP response headers must be in %s format' % charset
raise
- if '\n' in value or '\r' in value:
- raise BadHeaderError("Header values can't contain newlines (got %r)" % value)
- yield value
+ if str('\n') in value or str('\r') in value:
+ raise BadHeaderError("Header values can't contain newlines (got %r)" % value)
+ return value
def __setitem__(self, header, value):
- header, value = self._convert_to_ascii(header, value)
+ header = self._convert_to_charset(header, 'ascii')
+ value = self._convert_to_charset(value, 'latin1', mime_encode=True)
self._headers[header.lower()] = (header, value)
def __delitem__(self, header):
5 django/http/multipartparser.py
View
@@ -68,11 +68,10 @@ def __init__(self, META, input_data, upload_handlers, encoding=None):
if not boundary or not cgi.valid_boundary(boundary):
raise MultiPartParserError('Invalid boundary in multipart: %s' % boundary)
-
# Content-Length should contain the length of the body we are about
# to receive.
try:
- content_length = int(META.get('HTTP_CONTENT_LENGTH', META.get('CONTENT_LENGTH',0)))
+ content_length = int(META.get('HTTP_CONTENT_LENGTH', META.get('CONTENT_LENGTH', 0)))
except (ValueError, TypeError):
content_length = 0
@@ -178,7 +177,7 @@ def parse(self):
content_type = meta_data.get('content-type', ('',))[0].strip()
try:
- charset = meta_data.get('content-type', (0,{}))[1].get('charset', None)
+ charset = meta_data.get('content-type', (0, {}))[1].get('charset', None)
except:
charset = None
49 django/shortcuts/__init__.py
View
@@ -66,23 +66,7 @@ def redirect(to, *args, **kwargs):
else:
redirect_class = HttpResponseRedirect
- # If it's a model, use get_absolute_url()
- if hasattr(to, 'get_absolute_url'):
- return redirect_class(to.get_absolute_url())
-
- # Next try a reverse URL resolution.
- try:
- return redirect_class(urlresolvers.reverse(to, args=args, kwargs=kwargs))
- except urlresolvers.NoReverseMatch:
- # If this is a callable, re-raise.
- if callable(to):
- raise
- # If this doesn't "feel" like a URL, re-raise.
- if '/' not in to and '.' not in to:
- raise
-
- # Finally, fall back and assume it's a URL
- return redirect_class(to)
+ return redirect_class(resolve_url(to, *args, **kwargs))
def _get_queryset(klass):
"""
@@ -128,3 +112,34 @@ def get_list_or_404(klass, *args, **kwargs):
raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
return obj_list
+def resolve_url(to, *args, **kwargs):
+ """
+ Return a URL appropriate for the arguments passed.
+
+ The arguments could be:
+
+ * A model: the model's `get_absolute_url()` function will be called.
+
+ * A view name, possibly with arguments: `urlresolvers.reverse()` will
+ be used to reverse-resolve the name.
+
+ * A URL, which will be returned as-is.
+
+ """
+ # If it's a model, use get_absolute_url()
+ if hasattr(to, 'get_absolute_url'):
+ return to.get_absolute_url()
+
+ # Next try a reverse URL resolution.
+ try:
+ return urlresolvers.reverse(to, args=args, kwargs=kwargs)
+ except urlresolvers.NoReverseMatch:
+ # If this is a callable, re-raise.
+ if callable(to):
+ raise
+ # If this doesn't "feel" like a URL, re-raise.
+ if '/' not in to and '.' not in to:
+ raise
+
+ # Finally, fall back and assume it's a URL
+ return to
2  django/test/testcases.py
View
@@ -360,7 +360,7 @@ def assertRaisesMessage(self, expected_exception, expected_message,
args: Extra args.
kwargs: Extra kwargs.
"""
- return self.assertRaisesRegexp(expected_exception,
+ return six.assertRaisesRegex(self, expected_exception,
re.escape(expected_message), callable_obj, *args, **kwargs)
def assertFieldOutput(self, fieldclass, valid, invalid, field_args=None,
17 django/utils/_os.py
View
@@ -1,6 +1,6 @@
import os
import stat
-from os.path import join, normcase, normpath, abspath, isabs, sep
+from os.path import join, normcase, normpath, abspath, isabs, sep, dirname
from django.utils.encoding import force_text
from django.utils import six
@@ -41,13 +41,16 @@ def safe_join(base, *paths):
paths = [force_text(p) for p in paths]
final_path = abspathu(join(base, *paths))
base_path = abspathu(base)
- base_path_len = len(base_path)
# Ensure final_path starts with base_path (using normcase to ensure we
- # don't false-negative on case insensitive operating systems like Windows)
- # and that the next character after the final path is os.sep (or nothing,
- # in which case final_path must be equal to base_path).
- if not normcase(final_path).startswith(normcase(base_path)) \
- or final_path[base_path_len:base_path_len+1] not in ('', sep):
+ # don't false-negative on case insensitive operating systems like Windows),
+ # further, one of the following conditions must be true:
+ # a) The next character is the path separator (to prevent conditions like
+ # safe_join("/dir", "/../d"))
+ # b) The final path must be the same as the base path.
+ # c) The base path must be the most root path (meaning either "/" or "C:\\")
+ if (not normcase(final_path).startswith(normcase(base_path + sep)) and
+ normcase(final_path) != normcase(base_path) and
+ dirname(normcase(base_path)) != normcase(base_path)):
raise ValueError('The joined path (%s) is located outside of the base '
'path component (%s)' % (final_path, base_path))
return final_path
7 django/utils/six.py
View
@@ -370,13 +370,20 @@ def with_metaclass(meta, base=object):
if PY3:
_iterlists = "lists"
+ _assertRaisesRegex = "assertRaisesRegex"
else:
_iterlists = "iterlists"
+ _assertRaisesRegex = "assertRaisesRegexp"
+
def iterlists(d):
"""Return an iterator over the values of a MultiValueDict."""
return getattr(d, _iterlists)()
+def assertRaisesRegex(self, *args, **kwargs):
+ return getattr(self, _assertRaisesRegex)(*args, **kwargs)
+
+
add_move(MovedModule("_dummy_thread", "dummy_thread"))
add_move(MovedModule("_thread", "thread"))
3  django/views/generic/dates.py
View
@@ -372,6 +372,9 @@ def get_dated_queryset(self, ordering=None, **lookup):
return qs
def get_date_list_period(self):
+ """
+ Get the aggregation period for the list of dates: 'year', 'month', or 'day'.
+ """
return self.date_list_period
def get_date_list(self, queryset, date_type=None):
5 docs/README
View
@@ -1,9 +1,8 @@
The documentation in this tree is in plain text files and can be viewed using
any text file viewer.
-Technically speaking, it uses ReST (reStructuredText) [1], and the Sphinx
-documentation system [2]. This allows it to be built into other forms for
-easier viewing and browsing.
+It uses ReST (reStructuredText) [1], and the Sphinx documentation system [2].
+This allows it to be built into other forms for easier viewing and browsing.
To create an HTML version of the docs:
40 docs/faq/install.txt
View
@@ -16,8 +16,9 @@ How do I get started?
What are Django's prerequisites?
--------------------------------
-Django requires Python_, specifically Python 2.6.5 - 2.7.x. No other Python
-libraries are required for basic Django usage.
+Django requires Python, specifically Python 2.6.5 - 2.7.x. No other Python
+libraries are required for basic Django usage. Django 1.5 also has
+experimental support for Python 3.2 and above.
For a development environment -- if you just want to experiment with Django --
you don't need to have a separate Web server installed; Django comes with its
@@ -50,15 +51,12 @@ aren't available under older versions of Python.
Third-party applications for use with Django are, of course, free to set their
own version requirements.
-Over the next year or two Django will begin dropping support for older Python
-versions as part of a migration which will end with Django running on Python 3
-(see below for details).
-
All else being equal, we recommend that you use the latest 2.x release
(currently Python 2.7). This will let you take advantage of the numerous
-improvements and optimizations to the Python language since version 2.6, and
-will help ease the process of dropping support for older Python versions on
-the road to Python 3.
+improvements and optimizations to the Python language since version 2.6.
+
+Generally speaking, we don't recommend running Django on Python 3 yet; see
+below for more.
What Python version can I use with Django?
------------------------------------------
@@ -71,25 +69,21 @@ Django version Python versions
1.2 2.4, 2.5, 2.6, 2.7
1.3 2.4, 2.5, 2.6, 2.7
**1.4** **2.5, 2.6, 2.7**
-*1.5 (future)* *2.6, 2.7, 3.x (experimental)*
+*1.5 (future)* *2.6, 2.7* and *3.2, 3.3 (experimental)*
============== ===============
Can I use Django with Python 3?
-------------------------------
-Not at the moment. Python 3.0 introduced a number of
-backwards-incompatible changes to the Python language, and although
-these changes are generally a good thing for Python's future, it will
-be a while before most Python software catches up and is able to run
-on Python 3.0. For larger Python-based software like Django, the
-transition is expected to take at least a year or two (since it
-involves dropping support for older Python releases and so must be
-done gradually).
-
-In the meantime, Python 2.x releases will be supported and provided
-with bug fixes and security updates by the Python development team, so
-continuing to use a Python 2.x release during the transition should
-not present any risk.
+Django 1.5 introduces experimental support for Python 3.2 and 3.3. However, we
+don't yet suggest that you use Django and Python 3 in production.
+
+Python 3 support should be considered a "preview". It's offered to bootstrap
+the transition of the Django ecosystem to Python 3, and to help you start
+porting your apps for future Python 3 compatibility. But we're not yet
+confident enough to promise stability in production.
+
+Our current plan is to make Django 1.6 suitable for general use with Python 3.
Will Django run under shared hosting (like TextDrive or Dreamhost)?
-------------------------------------------------------------------
2  docs/faq/models.txt
View
@@ -11,7 +11,7 @@ Then, just do this::
>>> from django.db import connection
>>> connection.queries
- [{'sql': 'SELECT polls_polls.id,polls_polls.question,polls_polls.pub_date FROM polls_polls',
+ [{'sql': 'SELECT polls_polls.id, polls_polls.question, polls_polls.pub_date FROM polls_polls',
'time': '0.002'}]
``connection.queries`` is only available if :setting:`DEBUG` is ``True``.
8 docs/howto/custom-model-fields.txt
View
@@ -181,10 +181,10 @@ card values plus their suits; 104 characters in total.
Many of Django's model fields accept options that they don't do anything
with. For example, you can pass both
:attr:`~django.db.models.Field.editable` and
- :attr:`~django.db.models.Field.auto_now` to a
+ :attr:`~django.db.models.DateField.auto_now` to a
:class:`django.db.models.DateField` and it will simply ignore the
:attr:`~django.db.models.Field.editable` parameter
- (:attr:`~django.db.models.Field.auto_now` being set implies
+ (:attr:`~django.db.models.DateField.auto_now` being set implies
``editable=False``). No error is raised in this case.
This behavior simplifies the field classes, because they don't need to
@@ -516,8 +516,8 @@ for the first time, the ``add`` parameter will be ``True``, otherwise it will be
You only need to override this method if you want to preprocess the value
somehow, just before saving. For example, Django's
:class:`~django.db.models.DateTimeField` uses this method to set the attribute
-correctly in the case of :attr:`~django.db.models.Field.auto_now` or
-:attr:`~django.db.models.Field.auto_now_add`.
+correctly in the case of :attr:`~django.db.models.DateField.auto_now` or
+:attr:`~django.db.models.DateField.auto_now_add`.
If you do override this method, you must return the value of the attribute at
the end. You should also update the model's attribute if you make any changes
3  docs/internals/deprecation.txt
View
@@ -264,6 +264,9 @@ these changes.
in 1.4. The backward compatibility will be removed --
``HttpRequest.raw_post_data`` will no longer work.
+* ``django.contrib.markup`` will be removed following an accelerated
+ deprecation.
+
1.7
---
8 docs/intro/install.txt
View
@@ -10,11 +10,9 @@ Install Python
--------------
Being a Python Web framework, Django requires Python. It works with any Python
-version from 2.6.5 to 2.7 (due to backwards incompatibilities in Python 3.0,
-Django does not currently work with Python 3.0; see :doc:`the Django FAQ
-</faq/install>` for more information on supported Python versions and the 3.0
-transition), these versions of Python include a lightweight database called
-SQLite_ so you won't need to set up a database just yet.
+version from 2.6.5 to 2.7. It also features experimental support for versions
+3.2 and 3.3. All these versions of Python include a lightweight database
+called SQLite_ so you won't need to set up a database just yet.
.. _sqlite: http://sqlite.org/
8 docs/intro/overview.txt
View
@@ -31,7 +31,7 @@ the file ``mysite/news/models.py``::
return self.full_name
class Article(models.Model):
- pub_date = models.DateTimeField()
+ pub_date = models.DateField()
headline = models.CharField(max_length=200)
content = models.TextField()
reporter = models.ForeignKey(Reporter)
@@ -96,8 +96,8 @@ access your data. The API is created on the fly, no code generation necessary::
DoesNotExist: Reporter matching query does not exist. Lookup parameters were {'id': 2}
# Create an article.
- >>> from datetime import datetime
- >>> a = Article(pub_date=datetime.now(), headline='Django is cool',
+ >>> from datetime import date
+ >>> a = Article(pub_date=date.today(), headline='Django is cool',
... content='Yeah.', reporter=r)
>>> a.save()
@@ -140,7 +140,7 @@ as registering your model in the admin site::
from django.db import models
class Article(models.Model):
- pub_date = models.DateTimeField()
+ pub_date = models.DateField()
headline = models.CharField(max_length=200)
content = models.TextField()
reporter = models.ForeignKey(Reporter)
7 docs/intro/tutorial03.txt
View
@@ -513,11 +513,12 @@ Here's what happens if a user goes to "/polls/34/" in this system:
further processing.
Now that we've decoupled that, we need to decouple the ``polls.urls``
-URLconf by removing the leading "polls/" from each line, and removing the
-lines registering the admin site. Your ``polls/urls.py`` file should now look like
+URLconf by removing the leading "polls/" from each line, removing the
+lines registering the admin site, and removing the ``include`` import which
+is no longer used. Your ``polls/urls.py`` file should now look like
this::
- from django.conf.urls import patterns, include, url
+ from django.conf.urls import patterns, url
urlpatterns = patterns('polls.views',
url(r'^$', 'index'),
4 docs/intro/tutorial04.txt
View
@@ -218,7 +218,7 @@ Read on for details.
First, open the ``polls/urls.py`` URLconf. It looks like this, according to the
tutorial so far::
- from django.conf.urls import patterns, include, url
+ from django.conf.urls import patterns, url
urlpatterns = patterns('polls.views',
url(r'^$', 'index'),
@@ -229,7 +229,7 @@ tutorial so far::
Change it like so::
- from django.conf.urls import patterns, include, url
+ from django.conf.urls import patterns, url
from django.views.generic import DetailView, ListView
from polls.models import Poll