diff options
author | André Fabian Silva Delgado <emulatorman@lavabit.com> | 2012-10-20 23:48:42 -0200 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@lavabit.com> | 2012-10-20 23:48:42 -0200 |
commit | ea2a397658451d54c1303dca4410cda638e8e549 (patch) | |
tree | e42644eed29cd0bf051aba0f4eb6112e4e656517 | |
parent | 47583a7c89aa7314cb150caba03f13849f8c4e1a (diff) | |
parent | 53b785c979542521ba7bd7135246f1f9ba51757b (diff) |
Merge branch 'master' of ssh://parabolagnulinux.org:1863/srv/git/abslibre
-rw-r--r-- | libre/django13/PKGBUILD | 47 | ||||
-rw-r--r-- | libre/django13/PKGBUILD.orig | 40 | ||||
-rw-r--r-- | libre/django13/diff-django_branches_releases_1.3.X-from-16768-to-17460.diff | 1573 | ||||
-rw-r--r-- | libre/django13/diff-django_branches_releases_1.3.X-from-16771-to-17460.diff | 1575 | ||||
-rwxr-xr-x | libre/parabolaweb-git/Makefile | 26 | ||||
-rwxr-xr-x | libre/parabolaweb-git/PKGBUILD | 43 | ||||
-rwxr-xr-x | libre/parabolaweb-git/deps-ver.txt | 7 | ||||
-rwxr-xr-x | libre/parabolaweb-git/parabolaweb.init.sh | 52 | ||||
-rwxr-xr-x | libre/parabolaweb-git/parabolaweb.update.sh.in | 59 | ||||
-rwxr-xr-x | libre/parabolaweb-git/requirements_prod.txt | 7 | ||||
-rw-r--r-- | libre/parabolaweb-utils/PKGBUILD | 37 | ||||
-rw-r--r-- | libre/parabolaweb-utils/helper.sh | 37 | ||||
-rw-r--r-- | libre/parabolaweb-utils/parabolaweb.init.sh | 51 | ||||
-rw-r--r-- | libre/parabolaweb-utils/update-parabolaweb | 81 |
14 files changed, 3441 insertions, 194 deletions
diff --git a/libre/django13/PKGBUILD b/libre/django13/PKGBUILD new file mode 100644 index 000000000..554acccc7 --- /dev/null +++ b/libre/django13/PKGBUILD @@ -0,0 +1,47 @@ +# $Id$ +# Maintainer: Dan McGee <dan@archlinux.org> +# Contributor: Shahar Weiss <sweiss4@gmx.net> + +pkgname=django +pkgver=1.3.1 +pkgrel=2 +pkgdesc="A high-level Python Web framework." +arch=('any') +license=('BSD') +url="http://www.djangoproject.com/" +depends=('python2') +makedepends=('python2-distribute') +optdepends=('mysql-python: for MySQL backend' + 'python2-psycopg2: for PostgreSQL backend') +source=("https://www.djangoproject.com/m/releases/1.3/Django-$pkgver.tar.gz" + diff-django_branches_releases_1.3.X-from-16768-to-17460.diff) +md5sums=('62d8642fd06b9a0bf8544178f8500767' + 'd09d8f9e156b9aa1b580a1b43209b99f') +sha256sums=('af9118c4e8a063deb0b8cda901fcff2b805e7cf496c93fd43507163f3cde156b' + '8e08b5b5bbe7c042a1df4d5615a9d068ec6718fd00bef627c0a9a9e48ee58c15') + +build() { + cd "$srcdir/Django-$pkgver" + patch -Np1 -i ../diff-django_branches_releases_1.3.X-from-16768-to-17460.diff + python2 setup.py build +} + +package() { + cd "$srcdir/Django-$pkgver" + python2 setup.py install --root="$pkgdir" --optimize=1 + + install -Dm644 extras/django_bash_completion \ + "$pkgdir"/etc/bash_completion.d/django + + find "$pkgdir"/usr/lib/python2.7/site-packages/django/ -name '*.py' | \ + xargs sed -i "s|#!/usr/bin/env python$|#!/usr/bin/env python2|" + + install -Dm644 LICENSE "$pkgdir"/usr/share/licenses/$pkgname/LICENSE +} + +_pkgname=$pkgname +pkgname=django13 +pkgdesc+=" (legacy version for ParabolaWeb)" +pkgrel+=.1 +provides=("$_pkgname=$pkgver") +conflicts=("$_pkgname") diff --git a/libre/django13/PKGBUILD.orig b/libre/django13/PKGBUILD.orig new file mode 100644 index 000000000..c593c5626 --- /dev/null +++ b/libre/django13/PKGBUILD.orig @@ -0,0 +1,40 @@ +# $Id$ +# Maintainer: Dan McGee <dan@archlinux.org> +# Contributor: Shahar Weiss <sweiss4@gmx.net> + +pkgname=django +pkgver=1.3.1 +pkgrel=2 +pkgdesc="A high-level Python Web framework." +arch=('any') +license=('BSD') +url="http://www.djangoproject.com/" +depends=('python2') +makedepends=('python2-distribute') +optdepends=('mysql-python: for MySQL backend' + 'python2-psycopg2: for PostgreSQL backend') +source=("http://media.djangoproject.com/releases/1.3/Django-$pkgver.tar.gz" + diff-django_branches_releases_1.3.X-from-16771-to-17460.diff) +md5sums=('62d8642fd06b9a0bf8544178f8500767' + 'ea3d6cbde2fc2332ffe7f901cb60a974') +sha256sums=('af9118c4e8a063deb0b8cda901fcff2b805e7cf496c93fd43507163f3cde156b' + '84e2652a8249e58fdbbd43bce7cd8d6bb2159058be6a675ebe15661ca3ee9ffc') + +build() { + cd "$srcdir/Django-$pkgver" + patch -Np0 < ../diff-django_branches_releases_1.3.X-from-16771-to-17460.diff + python2 setup.py build +} + +package() { + cd "$srcdir/Django-$pkgver" + python2 setup.py install --root="$pkgdir" --optimize=1 + + install -Dm644 extras/django_bash_completion \ + "$pkgdir"/etc/bash_completion.d/django + + find "$pkgdir"/usr/lib/python2.7/site-packages/django/ -name '*.py' | \ + xargs sed -i "s|#!/usr/bin/env python$|#!/usr/bin/env python2|" + + install -Dm644 LICENSE "$pkgdir"/usr/share/licenses/$pkgname/LICENSE +} diff --git a/libre/django13/diff-django_branches_releases_1.3.X-from-16768-to-17460.diff b/libre/django13/diff-django_branches_releases_1.3.X-from-16768-to-17460.diff new file mode 100644 index 000000000..c6819c1ab --- /dev/null +++ b/libre/django13/diff-django_branches_releases_1.3.X-from-16768-to-17460.diff @@ -0,0 +1,1573 @@ +diff --git a/README b/README +index c7d225c..47bfd33 100644 +--- a/README ++++ b/README +@@ -28,7 +28,7 @@ http://code.djangoproject.com/newticket + To get more help: + + * Join the #django channel on irc.freenode.net. Lots of helpful people +- hang out there. Read the archives at http://botland.oebfare.com/logger/django/. ++ hang out there. Read the archives at http://django-irc-logs.com/. + + * Join the django-users mailing list, or read the archives, at + http://groups.google.com/group/django-users. +diff --git a/django/contrib/admin/media/css/forms.css b/django/contrib/admin/media/css/forms.css +index 1cedf24..35d0ed7 100644 +--- a/django/contrib/admin/media/css/forms.css ++++ b/django/contrib/admin/media/css/forms.css +@@ -352,9 +352,3 @@ fieldset.monospace textarea { + .empty-form { + display: none; + } +- +-/* IE7 specific bug fixes */ +- +-.submit-row input { +- float: right; +-} +\ No newline at end of file +diff --git a/django/contrib/gis/db/backends/spatialite/compiler.py b/django/contrib/gis/db/backends/spatialite/compiler.py +deleted file mode 100644 +index 3f81ae6..0000000 +--- a/django/contrib/gis/db/backends/spatialite/compiler.py ++++ /dev/null +@@ -1,32 +0,0 @@ +-from django.db.backends.util import typecast_timestamp +-from django.db.models.sql import compiler +-from django.db.models.sql.constants import MULTI +-from django.contrib.gis.db.models.sql.compiler import GeoSQLCompiler as BaseGeoSQLCompiler +- +-SQLCompiler = compiler.SQLCompiler +- +-class GeoSQLCompiler(BaseGeoSQLCompiler, SQLCompiler): +- pass +- +-class SQLInsertCompiler(compiler.SQLInsertCompiler, GeoSQLCompiler): +- pass +- +-class SQLDeleteCompiler(compiler.SQLDeleteCompiler, GeoSQLCompiler): +- pass +- +-class SQLUpdateCompiler(compiler.SQLUpdateCompiler, GeoSQLCompiler): +- pass +- +-class SQLAggregateCompiler(compiler.SQLAggregateCompiler, GeoSQLCompiler): +- pass +- +-class SQLDateCompiler(compiler.SQLDateCompiler, GeoSQLCompiler): +- """ +- This is overridden for GeoDjango to properly cast date columns, see #16757. +- """ +- def results_iter(self): +- offset = len(self.query.extra_select) +- for rows in self.execute_sql(MULTI): +- for row in rows: +- date = typecast_timestamp(str(row[offset])) +- yield date +diff --git a/django/contrib/gis/db/backends/spatialite/creation.py b/django/contrib/gis/db/backends/spatialite/creation.py +index c107d96..ee5f9db 100644 +--- a/django/contrib/gis/db/backends/spatialite/creation.py ++++ b/django/contrib/gis/db/backends/spatialite/creation.py +@@ -56,14 +56,6 @@ class SpatiaLiteCreation(DatabaseCreation): + interactive=False, + database=self.connection.alias) + +- # One effect of calling syncdb followed by flush is that the id of the +- # default site may or may not be 1, depending on how the sequence was +- # reset. If the sites app is loaded, then we coerce it. +- from django.db.models import get_model +- Site = get_model('sites', 'Site') +- if Site is not None and Site.objects.using(self.connection.alias).count() == 1: +- Site.objects.using(self.connection.alias).update(id=settings.SITE_ID) +- + from django.core.cache import get_cache + from django.core.cache.backends.db import BaseDatabaseCache + for cache_alias in settings.CACHES: +diff --git a/django/contrib/gis/db/backends/spatialite/operations.py b/django/contrib/gis/db/backends/spatialite/operations.py +index 1dc612c..e6f8409 100644 +--- a/django/contrib/gis/db/backends/spatialite/operations.py ++++ b/django/contrib/gis/db/backends/spatialite/operations.py +@@ -48,7 +48,7 @@ def get_dist_ops(operator): + return (SpatiaLiteDistance(operator),) + + class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations): +- compiler_module = 'django.contrib.gis.db.backends.spatialite.compiler' ++ compiler_module = 'django.contrib.gis.db.models.sql.compiler' + name = 'spatialite' + spatialite = True + version_regex = re.compile(r'^(?P<major>\d)\.(?P<minor1>\d)\.(?P<minor2>\d+)') +diff --git a/django/contrib/gis/db/models/sql/compiler.py b/django/contrib/gis/db/models/sql/compiler.py +index 782ce78..405a000 100644 +--- a/django/contrib/gis/db/models/sql/compiler.py ++++ b/django/contrib/gis/db/models/sql/compiler.py +@@ -1,7 +1,7 @@ + from itertools import izip +-from django.db.backends.util import truncate_name ++from django.db.backends.util import truncate_name, typecast_timestamp + from django.db.models.sql import compiler +-from django.db.models.sql.constants import TABLE_NAME ++from django.db.models.sql.constants import TABLE_NAME, MULTI + from django.db.models.sql.query import get_proxied_model + + SQLCompiler = compiler.SQLCompiler +@@ -194,7 +194,7 @@ class GeoSQLCompiler(compiler.SQLCompiler): + # We resolve the rest of the columns if we're on Oracle or if + # the `geo_values` attribute is defined. + for value, field in map(None, row[index_start:], fields): +- values.append(self.query.convert_values(value, field, connection=self.connection)) ++ values.append(self.query.convert_values(value, field, self.connection)) + else: + values.extend(row[index_start:]) + return tuple(values) +@@ -275,4 +275,24 @@ class SQLAggregateCompiler(compiler.SQLAggregateCompiler, GeoSQLCompiler): + pass + + class SQLDateCompiler(compiler.SQLDateCompiler, GeoSQLCompiler): +- pass ++ """ ++ This is overridden for GeoDjango to properly cast date columns, since ++ `GeoQuery.resolve_columns` is used for spatial values. ++ See #14648, #16757. ++ """ ++ def results_iter(self): ++ if self.connection.ops.oracle: ++ from django.db.models.fields import DateTimeField ++ fields = [DateTimeField()] ++ else: ++ needs_string_cast = self.connection.features.needs_datetime_string_cast ++ ++ offset = len(self.query.extra_select) ++ for rows in self.execute_sql(MULTI): ++ for row in rows: ++ date = row[offset] ++ if self.connection.ops.oracle: ++ date = self.resolve_columns(row, fields)[offset] ++ elif needs_string_cast: ++ date = typecast_timestamp(str(date)) ++ yield date +diff --git a/django/contrib/gis/tests/relatedapp/fixtures/initial_data.json.gz b/django/contrib/gis/tests/relatedapp/fixtures/initial_data.json.gz +index 68bf54c..8937637 100644 +Binary files a/django/contrib/gis/tests/relatedapp/fixtures/initial_data.json.gz and b/django/contrib/gis/tests/relatedapp/fixtures/initial_data.json.gz differ +diff --git a/django/contrib/gis/tests/relatedapp/models.py b/django/contrib/gis/tests/relatedapp/models.py +index 2e9a62b..aec4e15 100644 +--- a/django/contrib/gis/tests/relatedapp/models.py ++++ b/django/contrib/gis/tests/relatedapp/models.py +@@ -36,6 +36,7 @@ class Parcel(models.Model): + # These use the GeoManager but do not have any geographic fields. + class Author(models.Model): + name = models.CharField(max_length=100) ++ dob = models.DateField() + objects = models.GeoManager() + + class Article(models.Model): +diff --git a/django/contrib/gis/tests/relatedapp/tests.py b/django/contrib/gis/tests/relatedapp/tests.py +index 250783b..1a6197c 100644 +--- a/django/contrib/gis/tests/relatedapp/tests.py ++++ b/django/contrib/gis/tests/relatedapp/tests.py +@@ -1,3 +1,4 @@ ++from datetime import date + from django.test import TestCase + + from django.contrib.gis.geos import GEOSGeometry, Point, MultiPoint +@@ -281,4 +282,11 @@ class RelatedGeoModelTest(TestCase): + # evaluated as list generation swallows TypeError in CPython. + sql = str(qs.query) + ++ def test16_annotated_date_queryset(self): ++ "Ensure annotated date querysets work if spatial backend is used. See #14648." ++ birth_years = [dt.year for dt in ++ list(Author.objects.annotate(num_books=Count('books')).dates('dob', 'year'))] ++ birth_years.sort() ++ self.assertEqual([1950, 1974], birth_years) ++ + # TODO: Related tests for KML, GML, and distance lookups. +diff --git a/django/contrib/sites/management.py b/django/contrib/sites/management.py +index 1987274..9bf5a14 100644 +--- a/django/contrib/sites/management.py ++++ b/django/contrib/sites/management.py +@@ -3,15 +3,34 @@ Creates the default Site object. + """ + + from django.db.models import signals ++from django.db import connections ++from django.db import router + from django.contrib.sites.models import Site + from django.contrib.sites import models as site_app ++from django.core.management.color import no_style + + def create_default_site(app, created_models, verbosity, db, **kwargs): +- if Site in created_models: ++ # Only create the default sites in databases where Django created the table ++ if Site in created_models and router.allow_syncdb(db, Site) : ++ # The default settings set SITE_ID = 1, and some tests in Django's test ++ # suite rely on this value. However, if database sequences are reused ++ # (e.g. in the test suite after flush/syncdb), it isn't guaranteed that ++ # the next id will be 1, so we coerce it. See #15573 and #16353. This ++ # can also crop up outside of tests - see #15346. + if verbosity >= 2: + print "Creating example.com Site object" +- s = Site(domain="example.com", name="example.com") +- s.save(using=db) ++ Site(pk=1, domain="example.com", name="example.com").save(using=db) ++ ++ # We set an explicit pk instead of relying on auto-incrementation, ++ # so we need to reset the database sequence. ++ sequence_sql = connections[db].ops.sequence_reset_sql(no_style(), [Site]) ++ if sequence_sql: ++ if verbosity >= 2: ++ print "Resetting sequence" ++ cursor = connections[db].cursor() ++ for command in sequence_sql: ++ cursor.execute(command) ++ + Site.objects.clear_cache() + + signals.post_syncdb.connect(create_default_site, sender=site_app) +diff --git a/django/contrib/sites/tests.py b/django/contrib/sites/tests.py +index 17ab1f2..828badb 100644 +--- a/django/contrib/sites/tests.py ++++ b/django/contrib/sites/tests.py +@@ -15,6 +15,12 @@ class SitesFrameworkTests(TestCase): + def tearDown(self): + Site._meta.installed = self.old_Site_meta_installed + ++ def test_save_another(self): ++ # Regression for #17415 ++ # On some backends the sequence needs reset after save with explicit ID. ++ # Test that there is no sequence collisions by saving another site. ++ Site(domain="example2.com", name="example2.com").save() ++ + def test_site_manager(self): + # Make sure that get_current() does not return a deleted Site object. + s = Site.objects.get_current() +diff --git a/django/core/management/commands/shell.py b/django/core/management/commands/shell.py +index e4ce462..039ebb8 100644 +--- a/django/core/management/commands/shell.py ++++ b/django/core/management/commands/shell.py +@@ -13,9 +13,8 @@ class Command(NoArgsCommand): + + def ipython(self): + try: +- from IPython.frontend.terminal.embed import TerminalInteractiveShell +- shell = TerminalInteractiveShell() +- shell.mainloop() ++ from IPython import embed ++ embed() + except ImportError: + # IPython < 0.11 + # Explicitly pass an empty list as arguments, because otherwise +diff --git a/django/core/validators.py b/django/core/validators.py +index a93c6ac..9dcc2bc 100644 +--- a/django/core/validators.py ++++ b/django/core/validators.py +@@ -147,7 +147,8 @@ class EmailValidator(RegexValidator): + + email_re = re.compile( + r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom +- r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string ++ # quoted-string, see also http://tools.ietf.org/html/rfc2822#section-3.2.5 ++ r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' + r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE) # domain + validate_email = EmailValidator(email_re, _(u'Enter a valid e-mail address.'), 'invalid') + +diff --git a/django/db/backends/creation.py b/django/db/backends/creation.py +index 57e3f77..ef594b7 100644 +--- a/django/db/backends/creation.py ++++ b/django/db/backends/creation.py +@@ -374,15 +374,6 @@ class BaseDatabaseCreation(object): + verbosity=max(verbosity - 1, 0), + interactive=False, + database=self.connection.alias) +- +- # One effect of calling syncdb followed by flush is that the id of the +- # default site may or may not be 1, depending on how the sequence was +- # reset. If the sites app is loaded, then we coerce it. +- from django.db.models import get_model +- if 'django.contrib.sites' in settings.INSTALLED_APPS: +- Site = get_model('sites', 'Site') +- if Site is not None and Site.objects.using(self.connection.alias).count() == 1: +- Site.objects.using(self.connection.alias).update(id=settings.SITE_ID) + + from django.core.cache import get_cache + from django.core.cache.backends.db import BaseDatabaseCache +diff --git a/django/http/__init__.py b/django/http/__init__.py +index 68ac45d..07e5a46 100644 +--- a/django/http/__init__.py ++++ b/django/http/__init__.py +@@ -92,7 +92,7 @@ else: + if not _cookie_allows_colon_in_names: + def load(self, rawdata, ignore_parse_errors=False): + if ignore_parse_errors: +- self.bad_cookies = [] ++ self.bad_cookies = set() + self._BaseCookie__set = self._loose_set + super(SimpleCookie, self).load(rawdata) + if ignore_parse_errors: +@@ -106,8 +106,8 @@ else: + try: + self._strict_set(key, real_value, coded_value) + except Cookie.CookieError: +- self.bad_cookies.append(key) +- dict.__setitem__(self, key, None) ++ self.bad_cookies.add(key) ++ dict.__setitem__(self, key, Cookie.Morsel()) + + + class CompatCookie(SimpleCookie): +diff --git a/django/http/utils.py b/django/http/utils.py +index 5eea239..0180864 100644 +--- a/django/http/utils.py ++++ b/django/http/utils.py +@@ -76,7 +76,8 @@ def fix_IE_for_vary(request, response): + + # The first part of the Content-Type field will be the MIME type, + # everything after ';', such as character-set, can be ignored. +- if response['Content-Type'].split(';')[0] not in safe_mime_types: ++ mime_type = response.get('Content-Type', '').partition(';')[0] ++ if mime_type not in safe_mime_types: + try: + del response['Vary'] + except KeyError: +diff --git a/docs/howto/deployment/modpython.txt b/docs/howto/deployment/modpython.txt +index f5030e9..693f942 100644 +--- a/docs/howto/deployment/modpython.txt ++++ b/docs/howto/deployment/modpython.txt +@@ -293,11 +293,14 @@ of the admin app, but this is not the case when you use any other server + arrangement. You're responsible for setting up Apache, or whichever media + server you're using, to serve the admin files. + +-The admin files live in (:file:`django/contrib/admin/static/admin`) of the ++The admin files live in (:file:`django/contrib/admin/media/admin`) of the + Django distribution. + +-We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle +-the admin files, but here are two other approaches: ++We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle the ++admin files (this means using the :djadmin:`collectstatic` management command ++to collect the static files in :setting:`STATIC_ROOT`, and then configuring ++your webserver to serve :setting:`STATIC_ROOT` at :setting:`STATIC_URL`), but ++here are two other approaches: + + 1. Create a symbolic link to the admin static files from within your + document root. +diff --git a/docs/howto/deployment/modwsgi.txt b/docs/howto/deployment/modwsgi.txt +index de3a5b6..fdf9d27 100644 +--- a/docs/howto/deployment/modwsgi.txt ++++ b/docs/howto/deployment/modwsgi.txt +@@ -127,11 +127,14 @@ of the admin app, but this is not the case when you use any other server + arrangement. You're responsible for setting up Apache, or whichever media + server you're using, to serve the admin files. + +-The admin files live in (:file:`django/contrib/admin/static/admin`) of the ++The admin files live in (:file:`django/contrib/admin/media/admin`) of the + Django distribution. + +-We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle +-the admin files, but here are two other approaches: ++We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle the ++admin files (this means using the :djadmin:`collectstatic` management command ++to collect the static files in :setting:`STATIC_ROOT`, and then configuring ++your webserver to serve :setting:`STATIC_ROOT` at :setting:`STATIC_URL`), but ++here are two other approaches: + + 1. Create a symbolic link to the admin static files from within your + document root. +diff --git a/docs/index.txt b/docs/index.txt +index 0cf066e..20a7cec 100644 +--- a/docs/index.txt ++++ b/docs/index.txt +@@ -28,7 +28,7 @@ Having trouble? We'd like to help! + .. _archives of the django-users mailing list: http://groups.google.com/group/django-users/ + .. _post a question: http://groups.google.com/group/django-users/ + .. _#django IRC channel: irc://irc.freenode.net/django +-.. _IRC logs: http://botland.oebfare.com/logger/django/ ++.. _IRC logs: http://django-irc-logs.com/ + .. _ticket tracker: http://code.djangoproject.com/ + + First steps +diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt +index 3f0f998..ca29d15 100644 +--- a/docs/internals/deprecation.txt ++++ b/docs/internals/deprecation.txt +@@ -177,6 +177,12 @@ their deprecation, as per the :ref:`Django deprecation policy + required to end with a trailing slash to ensure there is a consistent + way to combine paths in templates. + ++ * Translations located under the so-called *project path* will be ++ ignored during the translation building process performed at runtime. ++ The :setting:`LOCALE_PATHS` setting can be used for the same task by ++ including the filesystem path to a ``locale`` directory containing ++ non-app-specific translations in its value. ++ + * 2.0 + * ``django.views.defaults.shortcut()``. This function has been moved + to ``django.contrib.contenttypes.views.shortcut()`` as part of the +diff --git a/docs/internals/release-process.txt b/docs/internals/release-process.txt +index 2a56f0b..799a59e 100644 +--- a/docs/internals/release-process.txt ++++ b/docs/internals/release-process.txt +@@ -99,6 +99,13 @@ varying levels: + * Security fixes will be applied to the current trunk and the previous two + minor releases. + ++* Documentation fixes will generally be more freely backported to the last ++ release branch (at the discretion of the committer), and don't need to meet ++ the "critical fixes only" bar as it's highly advantageous to have the docs ++ for the last release be up-to-date and correct, and the downside of ++ backporting (risk of introducing regressions) is much less of a concern ++ with doc fixes. ++ + As a concrete example, consider a moment in time halfway between the release of + Django 1.3 and 1.4. At this point in time: + +@@ -111,6 +118,9 @@ Django 1.3 and 1.4. At this point in time: + ``1.2.X`` branch. Security fixes will trigger the release of ``1.3.1``, + ``1.2.1``, etc. + ++* Documentation fixes will be applied to trunk, and if easily backported, to ++ the ``1.3.X`` branch. ++ + .. _release-process: + + Release process +diff --git a/docs/intro/index.txt b/docs/intro/index.txt +index bc61be7..19290a5 100644 +--- a/docs/intro/index.txt ++++ b/docs/intro/index.txt +@@ -31,6 +31,6 @@ place: read this material to quickly get up and running. + + .. _python: http://python.org/ + .. _list of Python resources for non-programmers: http://wiki.python.org/moin/BeginnersGuide/NonProgrammers +- .. _dive into python: http://diveintopython.org/ ++ .. _dive into python: http://diveintopython.net/ + .. _dead-tree version: http://www.amazon.com/exec/obidos/ASIN/1590593561/ref=nosim/jacobian20 + .. _books about Python: http://wiki.python.org/moin/PythonBooks +\ No newline at end of file +diff --git a/docs/intro/tutorial01.txt b/docs/intro/tutorial01.txt +index 2f2e049..4dc1e5c 100644 +--- a/docs/intro/tutorial01.txt ++++ b/docs/intro/tutorial01.txt +@@ -59,7 +59,7 @@ This will create a ``mysite`` directory in your current directory. + can be run as a program. To do this, open Terminal.app and navigate (using + the ``cd`` command) to the directory where :doc:`django-admin.py + </ref/django-admin>` is installed, then run the command +- ``chmod +x django-admin.py``. ++ ``sudo chmod +x django-admin.py``. + + .. note:: + +@@ -692,10 +692,9 @@ Save these changes and start a new Python interactive shell by running + + For more information on model relations, see :doc:`Accessing related objects + </ref/models/relations>`. For more on how to use double underscores to perform +-field lookups via the API, see `Field lookups`__. For full details on the +-database API, see our :doc:`Database API reference </topics/db/queries>`. +- +-__ http://docs.djangoproject.com/en/1.2/topics/db/queries/#field-lookups ++field lookups via the API, see :ref:`Field lookups <field-lookups-intro>`. For ++full details on the database API, see our :doc:`Database API reference ++</topics/db/queries>`. + + When you're comfortable with the API, read :doc:`part 2 of this tutorial + </intro/tutorial02>` to get Django's automatic admin working. +diff --git a/docs/intro/tutorial02.txt b/docs/intro/tutorial02.txt +index 4bd31fb..1e837e6 100644 +--- a/docs/intro/tutorial02.txt ++++ b/docs/intro/tutorial02.txt +@@ -40,22 +40,22 @@ activate the admin site for your installation, do these three things: + + .. parsed-literal:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + # Uncomment the next two lines to enable the admin: + **from django.contrib import admin** + **admin.autodiscover()** + + urlpatterns = patterns('', +- # Example: +- # (r'^mysite/', include('mysite.foo.urls')), ++ # Examples: ++ # url(r'^$', 'mysite.views.home', name='home'), ++ # url(r'^mysite/', include('mysite.foo.urls')), + +- # Uncomment the admin/doc line below and add 'django.contrib.admindocs' +- # to INSTALLED_APPS to enable admin documentation: +- # (r'^admin/doc/', include('django.contrib.admindocs.urls')), ++ # Uncomment the admin/doc line below to enable admin documentation: ++ # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), + + # Uncomment the next line to enable the admin: +- **(r'^admin/', include(admin.site.urls)),** ++ **url(r'^admin/', include(admin.site.urls)),** + ) + + (The bold lines are the ones that needed to be uncommented.) +diff --git a/docs/intro/tutorial03.txt b/docs/intro/tutorial03.txt +index 41a62a7..566ba55 100644 +--- a/docs/intro/tutorial03.txt ++++ b/docs/intro/tutorial03.txt +@@ -78,17 +78,17 @@ point at that file:: + + Time for an example. Edit ``mysite/urls.py`` so it looks like this:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + from django.contrib import admin + admin.autodiscover() + + urlpatterns = patterns('', +- (r'^polls/$', 'polls.views.index'), +- (r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), +- (r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), +- (r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), +- (r'^admin/', include(admin.site.urls)), ++ url(r'^polls/$', 'polls.views.index'), ++ url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), ++ url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), ++ url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), ++ url(r'^admin/', include(admin.site.urls)), + ) + + This is worth a review. When somebody requests a page from your Web site -- say, +@@ -112,7 +112,7 @@ what you can do with them. And there's no need to add URL cruft such as ``.php`` + -- unless you have a sick sense of humor, in which case you can do something + like this:: + +- (r'^polls/latest\.php$', 'polls.views.index'), ++ url(r'^polls/latest\.php$', 'polls.views.index'), + + But, don't do that. It's silly. + +@@ -357,22 +357,23 @@ the list is empty. + Write a 404 (page not found) view + ================================= + +-When you raise :exc:`~django.http.Http404` from within a view, Django will load +-a special view devoted to handling 404 errors. It finds it by looking for the +-variable ``handler404``, which is a string in Python dotted syntax -- the same +-format the normal URLconf callbacks use. A 404 view itself has nothing special: +-It's just a normal view. +- +-You normally won't have to bother with writing 404 views. By default, URLconfs +-have the following line up top:: +- +- from django.conf.urls.defaults import * ++When you raise :exc:`~django.http.Http404` from within a view, Django ++will load a special view devoted to handling 404 errors. It finds it ++by looking for the variable ``handler404`` in your root URLconf (and ++only in your root URLconf; setting ``handler404`` anywhere else will ++have no effect), which is a string in Python dotted syntax -- the same ++format the normal URLconf callbacks use. A 404 view itself has nothing ++special: It's just a normal view. + +-That takes care of setting ``handler404`` in the current module. As you can see +-in ``django/conf/urls/defaults.py``, ``handler404`` is set to +-:func:`django.views.defaults.page_not_found` by default. ++You normally won't have to bother with writing 404 views. If you don't set ++``handler404``, the built-in view :func:`django.views.defaults.page_not_found` ++is used by default. In this case, you still have one obligation: To create a ++``404.html`` template in the root of your template directory. The default 404 ++view will use that template for all 404 errors. If :setting:`DEBUG` is set to ++``False`` (in your settings module) and if you didn't create a ``404.html`` ++file, an ``Http500`` is raised instead. So remember to create a ``404.html``. + +-Four more things to note about 404 views: ++A couple more things to note about 404 views: + + * If :setting:`DEBUG` is set to ``True`` (in your settings module) then your + 404 view will never be used (and thus the ``404.html`` template will never +@@ -381,21 +382,12 @@ Four more things to note about 404 views: + * The 404 view is also called if Django doesn't find a match after checking + every regular expression in the URLconf. + +- * If you don't define your own 404 view -- and simply use the default, which +- is recommended -- you still have one obligation: To create a ``404.html`` +- template in the root of your template directory. The default 404 view will +- use that template for all 404 errors. +- +- * If :setting:`DEBUG` is set to ``False`` (in your settings module) and if +- you didn't create a ``404.html`` file, an ``Http500`` is raised instead. +- So remember to create a ``404.html``. +- + Write a 500 (server error) view + =============================== + +-Similarly, URLconfs may define a ``handler500``, which points to a view to call +-in case of server errors. Server errors happen when you have runtime errors in +-view code. ++Similarly, your root URLconf may define a ``handler500``, which points ++to a view to call in case of server errors. Server errors happen when ++you have runtime errors in view code. + + Use the template system + ======================= +@@ -432,10 +424,10 @@ Take some time to play around with the views and template system. As you edit + the URLconf, you may notice there's a fair bit of redundancy in it:: + + urlpatterns = patterns('', +- (r'^polls/$', 'polls.views.index'), +- (r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), +- (r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), +- (r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), ++ url(r'^polls/$', 'polls.views.index'), ++ url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), ++ url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), ++ url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), + ) + + Namely, ``polls.views`` is in every callback. +@@ -445,10 +437,10 @@ common prefixes. You can factor out the common prefixes and add them as the + first argument to :func:`~django.conf.urls.defaults.patterns`, like so:: + + urlpatterns = patterns('polls.views', +- (r'^polls/$', 'index'), +- (r'^polls/(?P<poll_id>\d+)/$', 'detail'), +- (r'^polls/(?P<poll_id>\d+)/results/$', 'results'), +- (r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), ++ url(r'^polls/$', 'index'), ++ url(r'^polls/(?P<poll_id>\d+)/$', 'detail'), ++ url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'), ++ url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), + ) + + This is functionally identical to the previous formatting. It's just a bit +@@ -459,20 +451,20 @@ callback in your URLconf, you can concatenate multiple + :func:`~django.conf.urls.defaults.patterns`. Your full ``mysite/urls.py`` might + now look like this:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + from django.contrib import admin + admin.autodiscover() + + urlpatterns = patterns('polls.views', +- (r'^polls/$', 'index'), +- (r'^polls/(?P<poll_id>\d+)/$', 'detail'), +- (r'^polls/(?P<poll_id>\d+)/results/$', 'results'), +- (r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), ++ url(r'^polls/$', 'index'), ++ url(r'^polls/(?P<poll_id>\d+)/$', 'detail'), ++ url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'), ++ url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), + ) + + urlpatterns += patterns('', +- (r'^admin/', include(admin.site.urls)), ++ url(r'^admin/', include(admin.site.urls)), + ) + + Decoupling the URLconfs +@@ -502,8 +494,8 @@ Copy the file ``mysite/urls.py`` to ``polls/urls.py``. Then, change + admin.autodiscover() + + urlpatterns = patterns('', +- (r'^polls/', include('polls.urls')), +- (r'^admin/', include(admin.site.urls)), ++ url(r'^polls/', include('polls.urls')), ++ url(r'^admin/', include(admin.site.urls)), + ) + + :func:`~django.conf.urls.defaults.include` simply references another URLconf. +@@ -526,13 +518,13 @@ 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 + this:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + urlpatterns = patterns('polls.views', +- (r'^$', 'index'), +- (r'^(?P<poll_id>\d+)/$', 'detail'), +- (r'^(?P<poll_id>\d+)/results/$', 'results'), +- (r'^(?P<poll_id>\d+)/vote/$', 'vote'), ++ url(r'^$', 'index'), ++ url(r'^(?P<poll_id>\d+)/$', 'detail'), ++ url(r'^(?P<poll_id>\d+)/results/$', 'results'), ++ url(r'^(?P<poll_id>\d+)/vote/$', 'vote'), + ) + + The idea behind :func:`~django.conf.urls.defaults.include` and URLconf +diff --git a/docs/intro/tutorial04.txt b/docs/intro/tutorial04.txt +index ded5cb2..4c2f2d4 100644 +--- a/docs/intro/tutorial04.txt ++++ b/docs/intro/tutorial04.txt +@@ -218,13 +218,13 @@ 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.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + urlpatterns = patterns('polls.views', +- (r'^$', 'index'), +- (r'^(?P<poll_id>\d+)/$', 'detail'), +- (r'^(?P<poll_id>\d+)/results/$', 'results'), +- (r'^(?P<poll_id>\d+)/vote/$', 'vote'), ++ url(r'^$', 'index'), ++ url(r'^(?P<poll_id>\d+)/$', 'detail'), ++ url(r'^(?P<poll_id>\d+)/results/$', 'results'), ++ url(r'^(?P<poll_id>\d+)/vote/$', 'vote'), + ) + + Change it like so:: +@@ -234,12 +234,12 @@ Change it like so:: + from polls.models import Poll + + urlpatterns = patterns('', +- (r'^$', ++ url(r'^$', + ListView.as_view( + queryset=Poll.objects.order_by('-pub_date')[:5], + context_object_name='latest_poll_list', + template_name='polls/index.html')), +- (r'^(?P<pk>\d+)/$', ++ url(r'^(?P<pk>\d+)/$', + DetailView.as_view( + model=Poll, + template_name='polls/detail.html')), +@@ -248,7 +248,7 @@ Change it like so:: + model=Poll, + template_name='polls/results.html'), + name='poll_results'), +- (r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), ++ url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), + ) + + We're using two generic views here: +diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt +index beff94e..7394c3a 100644 +--- a/docs/ref/contrib/admin/index.txt ++++ b/docs/ref/contrib/admin/index.txt +@@ -19,8 +19,10 @@ There are six steps in activating the Django admin site: + 1. Add ``'django.contrib.admin'`` to your :setting:`INSTALLED_APPS` + setting. + +- 2. Admin has two dependencies - :mod:`django.contrib.auth` and +- :mod:`django.contrib.contenttypes`. If these applications are not ++ 2. The admin has four dependencies - :mod:`django.contrib.auth`, ++ :mod:`django.contrib.contenttypes`, ++ :mod:`django.contrib.messages` and ++ :mod:`django.contrib.sessions`. If these applications are not + in your :setting:`INSTALLED_APPS` list, add them. + + 3. Determine which of your application's models should be editable in the +@@ -542,7 +544,7 @@ subclass:: + Fields in ``list_filter`` can also span relations using the ``__`` lookup:: + + class UserAdminWithLookup(UserAdmin): +- list_filter = ('groups__name') ++ list_filter = ('groups__name',) + + .. attribute:: ModelAdmin.list_per_page + +diff --git a/docs/ref/contrib/gis/geoip.txt b/docs/ref/contrib/gis/geoip.txt +index 6503be7..f5c45e1 100644 +--- a/docs/ref/contrib/gis/geoip.txt ++++ b/docs/ref/contrib/gis/geoip.txt +@@ -144,7 +144,7 @@ parameters. + Returns a dictionary of city information for the given query. Some + of the values in the dictionary may be undefined (``None``). + +-.. method:: GeoIPcountry(query) ++.. method:: GeoIP.country(query) + + Returns a dictionary with the country code and country for the given + query. +diff --git a/docs/ref/contrib/messages.txt b/docs/ref/contrib/messages.txt +index ca3212d..ee7e01c 100644 +--- a/docs/ref/contrib/messages.txt ++++ b/docs/ref/contrib/messages.txt +@@ -210,6 +210,10 @@ If you're using the context processor, your template should be rendered with a + ``RequestContext``. Otherwise, ensure ``messages`` is available to + the template context. + ++Even if you know there is only just one message, you should still iterate over ++the ``messages`` sequence, because otherwise the message storage will not be cleared ++for the next request. ++ + Creating custom message levels + ------------------------------ + +diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt +index 89bc43f..58b86ea 100644 +--- a/docs/ref/django-admin.txt ++++ b/docs/ref/django-admin.txt +@@ -1156,7 +1156,7 @@ variable. + Note that this option is unnecessary in ``manage.py``, because it takes care of + setting the Python path for you. + +-.. _import search path: http://diveintopython.org/getting_to_know_python/everything_is_an_object.html ++.. _import search path: http://diveintopython.net/getting_to_know_python/everything_is_an_object.html + + .. django-admin-option:: --settings + +diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt +index 3728a09..52c0869 100644 +--- a/docs/ref/models/instances.txt ++++ b/docs/ref/models/instances.txt +@@ -470,7 +470,7 @@ the URL. For example, if your URLconf contained a line such as:: + + Similarly, if you had a URLconf entry that looked like:: + +- (r'/archive/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/$', archive_view) ++ (r'/archive/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', archive_view) + + ...you could reference this using ``permalink()`` as follows:: + +@@ -478,8 +478,8 @@ Similarly, if you had a URLconf entry that looked like:: + def get_absolute_url(self): + return ('archive_view', (), { + 'year': self.created.year, +- 'month': self.created.month, +- 'day': self.created.day}) ++ 'month': self.created.strftime('%m'), ++ 'day': self.created.strftime('%d')}) + + Notice that we specify an empty sequence for the second parameter in this case, + because we only want to pass keyword parameters, not positional ones. +diff --git a/docs/ref/models/options.txt b/docs/ref/models/options.txt +index 4530439..c1beab0 100644 +--- a/docs/ref/models/options.txt ++++ b/docs/ref/models/options.txt +@@ -166,6 +166,13 @@ Django quotes column and table names behind the scenes. + >>> answer.get_previous_in_order() + <Answer: 1> + ++.. admonition:: Changing order_with_respect_to ++ ++ ``order_with_respect_to`` adds an additional field/database column ++ named ``_order``, so be sure to handle that as you would any other ++ change to your models if you add or change ``order_with_respect_to`` ++ after your initial :djadmin:`syncdb`. ++ + ``ordering`` + ------------ + +@@ -238,6 +245,12 @@ Django quotes column and table names behind the scenes. + + unique_together = ("driver", "restaurant") + ++ A :class:`~django.db.models.ManyToManyField` cannot be included in ++ unique_together (it's not even clear what that would mean). If you ++ need to validate uniqueness related to a ++ :class:`~django.db.models.ManyToManyField`, look at signals or ++ using an explicit :attr:`through <ManyToManyField.through>` model. ++ + ``verbose_name`` + ---------------- + +diff --git a/docs/ref/signals.txt b/docs/ref/signals.txt +index e83142e..ad25dce 100644 +--- a/docs/ref/signals.txt ++++ b/docs/ref/signals.txt +@@ -352,12 +352,16 @@ post_syncdb + .. data:: django.db.models.signals.post_syncdb + :module: + +-Sent by :djadmin:`syncdb` after it installs an application. ++Sent by :djadmin:`syncdb` command after it installs an application, and ++:djadmin:`flush` command. + + Any handlers that listen to this signal need to be written in a particular + place: a ``management`` module in one of your :setting:`INSTALLED_APPS`. If + handlers are registered anywhere else they may not be loaded by +-:djadmin:`syncdb`. ++:djadmin:`syncdb`. It is important that handlers of this signal perform ++idempotent changes (e.g. no database alterations) as this may cause the ++:djadmin:`flush` management command to fail if it also ran during the ++:djadmin:`syncdb` command. + + Arguments sent with this signal: + +diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt +index 7d24c1d..6c7057a 100644 +--- a/docs/ref/templates/builtins.txt ++++ b/docs/ref/templates/builtins.txt +@@ -1868,7 +1868,7 @@ slice + Returns a slice of the list. + + Uses the same syntax as Python's list slicing. See +-http://diveintopython.org/native_data_types/lists.html#odbchelper.list.slice ++http://diveintopython.net/native_data_types/lists.html#odbchelper.list.slice + for an introduction. + + Example:: +diff --git a/docs/releases/0.95.txt b/docs/releases/0.95.txt +index 7409bff..3632c31 100644 +--- a/docs/releases/0.95.txt ++++ b/docs/releases/0.95.txt +@@ -92,15 +92,15 @@ changes is described in the `Removing The Magic`_ wiki page. There is also an + easy checklist_ for reference when undertaking the porting operation. + + .. _Removing The Magic: http://code.djangoproject.com/wiki/RemovingTheMagic +-.. _checklist: http://code.djangoproject.com/wiki/MagicRemovalCheatSheet1 ++.. _checklist: http://code.djangoproject.com/wiki/MagicRemovalCheatSheet + + Problem reports and getting help + ================================ + +-Need help resolving a problem with Django? The documentation in the distribution +-is also available online_ at the `Django Web site`_. The :doc:`FAQ </faq/index>` +-document is especially recommended, as it contains a number of issues that come +-up time and again. ++Need help resolving a problem with Django? The documentation in the ++distribution is also available :doc:`online </index>` at the `Django Web ++site`_. The :doc:`FAQ </faq/index>` document is especially recommended, as it ++contains a number of issues that come up time and again. + + For more personalized help, the `django-users`_ mailing list is a very active + list, with more than 2,000 subscribers who can help you solve any sort of +@@ -113,7 +113,6 @@ there's a #django channel on irc.freenode.net that is regularly populated by + Django users and developers from around the world. Friendly people are usually + available at any hour of the day -- to help, or just to chat. + +-.. _online: http://www.djangoproject.com/documentation/0.95/ + .. _Django Web site: http://www.djangoproject.com/ + .. _django-users: http://groups.google.com/group/django-users + +diff --git a/docs/releases/0.96.txt b/docs/releases/0.96.txt +index 1224360..8874ccb 100644 +--- a/docs/releases/0.96.txt ++++ b/docs/releases/0.96.txt +@@ -50,12 +50,10 @@ aside from any necessary security fixes, it will not be actively + maintained, and it will be removed in a future release of Django. + + Also, note that some features, like the new :setting:`DATABASE_OPTIONS` +-setting (see the `databases documentation`_ for details), are only +-available on the "mysql" backend, and will not be made available for ++setting (see the :doc:`databases documentation </ref/databases>` for details), ++are only available on the "mysql" backend, and will not be made available for + "mysql_old". + +-.. _databases documentation: http://www.djangoproject.com/documentation/0.96/databases/ +- + Database constraint names changed + --------------------------------- + +@@ -164,10 +162,8 @@ Although the ``newforms`` library will continue to evolve, it's ready for use + for most common cases. We recommend that anyone new to form handling skip the + old forms system and start with the new. + +-For more information about ``django.newforms``, read the `newforms +-documentation`_. +- +-.. _newforms documentation: http://www.djangoproject.com/documentation/0.96/newforms/ ++For more information about ``django.newforms``, read the :doc:`newforms ++documentation </topics/forms/index>`. + + URLconf improvements + -------------------- +@@ -216,19 +212,15 @@ The test framework + ------------------ + + Django now includes a test framework so you can start transmuting fear into +-boredom (with apologies to Kent Beck). You can write tests based on doctest_ +-or unittest_ and test your views with a simple test client. ++boredom (with apologies to Kent Beck). You can write tests based on ++:mod:`doctest` or :mod:`unittest` and test your views with a simple test client. + + There is also new support for "fixtures" -- initial data, stored in any of the +-supported `serialization formats`_, that will be loaded into your database at the +-start of your tests. This makes testing with real data much easier. +- +-See `the testing documentation`_ for the full details. ++supported :doc:`serialization formats </topics/serialization>`, that will be ++loaded into your database at the start of your tests. This makes testing with ++real data much easier. + +-.. _doctest: http://docs.python.org/library/doctest.html +-.. _unittest: http://docs.python.org/library/unittest.html +-.. _the testing documentation: http://www.djangoproject.com/documentation/0.96/testing/ +-.. _serialization formats: http://www.djangoproject.com/documentation/0.96/serialization/ ++See :doc:`the testing documentation </topics/testing>` for the full details. + + Improvements to the admin interface + ----------------------------------- +diff --git a/docs/releases/1.0.1.txt b/docs/releases/1.0.1.txt +index 780dc53..3550e7c 100644 +--- a/docs/releases/1.0.1.txt ++++ b/docs/releases/1.0.1.txt +@@ -6,10 +6,10 @@ Welcome to Django 1.0.1! + + This is the first "bugfix" release in the Django 1.0 series, improving + the stability and performance of the Django 1.0 codebase. As such, +-Django 1.0.1 contains no new features (and, pursuant to `our +-compatibility policy`_, maintains backwards compatibility with Django +-1.0), but does contain a number of fixes and other +-improvements. Django 1.0.1 is a recommended upgrade for any ++Django 1.0.1 contains no new features (and, pursuant to :doc:`our ++compatibility policy </misc/api-stability/>`, maintains backwards ++compatibility with Django 1.0), but does contain a number of fixes ++and other improvements. Django 1.0.1 is a recommended upgrade for any + development or deployment currently using or targeting Django 1.0. + + +@@ -46,8 +46,9 @@ highlights: + + * A fix to the application of autoescaping for literal strings passed + to the ``join`` template filter. Previously, literal strings passed +- to ``join`` were automatically escaped, contrary to `the documented +- behavior for autoescaping and literal strings`_. Literal strings ++ to ``join`` were automatically escaped, contrary to :ref:`the ++ documented behavior for autoescaping and literal strings ++ <string-literals-and-automatic-escaping>`. Literal strings + passed to ``join`` are no longer automatically escaped, meaning you + must now manually escape them; this is an incompatibility if you + were relying on this bug, but not if you were relying on escaping +@@ -60,6 +61,4 @@ highlights: + documentation, including both corrections to existing documents and + expanded and new documentation. + +-.. _our compatibility policy: http://docs.djangoproject.com/en/dev/misc/api-stability/ + .. _the Subversion log of the 1.0.X branch: http://code.djangoproject.com/log/django/branches/releases/1.0.X +-.. _the documented behavior for autoescaping and literal strings: http://docs.djangoproject.com/en/dev/topics/templates/#string-literals-and-automatic-escaping +diff --git a/docs/releases/1.2.6.txt b/docs/releases/1.2.6.txt +new file mode 100644 +index 0000000..cfd1d9c +--- /dev/null ++++ b/docs/releases/1.2.6.txt +@@ -0,0 +1,16 @@ ++========================== ++Django 1.2.6 release notes ++========================== ++ ++*September 9, 2011* ++ ++Welcome to Django 1.2.6! ++ ++This is the sixth bugfix/security release in the Django 1.2 series, fixing ++several security issues present in Django 1.2.5. Django 1.2.6 is a ++recommended upgrade for all users of any Django release in the 1.2.X series. ++ ++For a full list of issues addressed in this release, see the `security ++advisory`_. ++ ++.. _security advisory: https://www.djangoproject.com/weblog/2011/sep/09/security-releases-issued/ +diff --git a/docs/releases/1.2.7.txt b/docs/releases/1.2.7.txt +new file mode 100644 +index 0000000..c0cf698 +--- /dev/null ++++ b/docs/releases/1.2.7.txt +@@ -0,0 +1,16 @@ ++========================== ++Django 1.2.7 release notes ++========================== ++ ++*September 10, 2011* ++ ++Welcome to Django 1.2.7! ++ ++This is the seventh bugfix/security release in the Django 1.2 series. It ++replaces Django 1.2.6 due to problems with the 1.2.6 release tarball. ++Django 1.2.7 is a recommended upgrade for all users of any Django release in ++the 1.2.X series. ++ ++For more information, see the `release advisory`_. ++ ++.. _release advisory: https://www.djangoproject.com/weblog/2011/sep/10/127/ +diff --git a/docs/releases/1.3.1.txt b/docs/releases/1.3.1.txt +new file mode 100644 +index 0000000..4c28916 +--- /dev/null ++++ b/docs/releases/1.3.1.txt +@@ -0,0 +1,16 @@ ++========================== ++Django 1.3.1 release notes ++========================== ++ ++*September 9, 2011* ++ ++Welcome to Django 1.3.1! ++ ++This is the first security release in the Django 1.3 series, fixing several ++security issues in Django 1.3. Django 1.3.1 is a recommended upgrade for ++all users of Django 1.3. ++ ++For a full list of issues addressed in this release, see the `security ++advisory`_. ++ ++.. _security advisory: https://www.djangoproject.com/weblog/2011/sep/09/security-releases-issued/ +diff --git a/docs/releases/index.txt b/docs/releases/index.txt +index 8d23c28..40fe5b0 100644 +--- a/docs/releases/index.txt ++++ b/docs/releases/index.txt +@@ -19,6 +19,7 @@ Final releases + .. toctree:: + :maxdepth: 1 + ++ 1.3.1 + 1.3 + + 1.2 release +@@ -26,6 +27,8 @@ Final releases + .. toctree:: + :maxdepth: 1 + ++ 1.2.7 ++ 1.2.6 + 1.2.5 + 1.2.4 + 1.2.2 +diff --git a/docs/topics/auth.txt b/docs/topics/auth.txt +index 635f18f..5a2608a 100644 +--- a/docs/topics/auth.txt ++++ b/docs/topics/auth.txt +@@ -1251,16 +1251,19 @@ can or cannot do with Task instances, specific to your application:: + ... + class Meta: + permissions = ( +- ("can_view", "Can see available tasks"), +- ("can_change_status", "Can change the status of tasks"), +- ("can_close", "Can remove a task by setting its status as closed"), ++ ("view_task", "Can see available tasks"), ++ ("change_task_status", "Can change the status of tasks"), ++ ("close_task", "Can remove a task by setting its status as closed"), + ) + + The only thing this does is create those extra permissions when you run + :djadmin:`manage.py syncdb <syncdb>`. Your code is in charge of checking the + value of these permissions when an user is trying to access the functionality + provided by the application (viewing tasks, changing the status of tasks, +-closing tasks.) ++closing tasks.) Continuing the above example, the following checks if a user may ++view tasks:: ++ ++ user.has_perm('app.view_task') + + API reference + ------------- +diff --git a/docs/topics/cache.txt b/docs/topics/cache.txt +index 8ef4ea2..9b68353 100644 +--- a/docs/topics/cache.txt ++++ b/docs/topics/cache.txt +@@ -99,8 +99,9 @@ To use Memcached with Django: + on your chosen memcached binding) + + * Set :setting:`LOCATION <CACHES-LOCATION>` to ``ip:port`` values, +- where ``ip`` is the IP address of the Memcached daemon and +- ``port`` is the port on which Memcached is running. ++ where ``ip`` is the IP address of the Memcached daemon and ``port`` is the ++ port on which Memcached is running, or to a ``unix:path`` value, where ++ ``path`` is the path to a Memcached Unix socket file. + + In this example, Memcached is running on localhost (127.0.0.1) port 11211, using + the ``python-memcached`` binding:: +@@ -112,6 +113,16 @@ the ``python-memcached`` binding:: + } + } + ++In this example, Memcached is available through a local Unix socket file ++:file:`/tmp/memcached.sock` using the ``python-memcached`` binding:: ++ ++ CACHES = { ++ 'default': { ++ 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', ++ 'LOCATION': 'unix:/tmp/memcached.sock', ++ } ++ } ++ + One excellent feature of Memcached is its ability to share cache over multiple + servers. This means you can run Memcached daemons on multiple machines, and the + program will treat the group of machines as a *single* cache, without the need +@@ -526,9 +537,10 @@ you may expect. But once a particular URL (e.g., ``/foo/23/``) has been + requested, subsequent requests to that URL will use the cache. + + ``cache_page`` can also take an optional keyword argument, ``cache``, +-which directs the decorator to use a specific cache alias when caching view +-results. By default, the ``default`` alias will be used, but you can specify +-any cache alias you want:: ++which directs the decorator to use a specific cache (from your ++:setting:`CACHES` setting) when caching view results. By default, the ++``default`` cache will be used, but you can specify any cache you ++want:: + + @cache_page(60 * 15, cache="special_cache") + def my_view(request): +diff --git a/docs/topics/class-based-views.txt b/docs/topics/class-based-views.txt +index 3831046..4da48ec 100644 +--- a/docs/topics/class-based-views.txt ++++ b/docs/topics/class-based-views.txt +@@ -380,7 +380,7 @@ Next, we'll write the ``PublisherBookListView`` view itself:: + class PublisherBookListView(ListView): + + context_object_name = "book_list" +- template_name = "books/books_by_publisher.html", ++ template_name = "books/books_by_publisher.html" + + def get_queryset(self): + publisher = get_object_or_404(Publisher, name__iexact=self.args[0]) +@@ -396,7 +396,7 @@ use it in the template:: + class PublisherBookListView(ListView): + + context_object_name = "book_list" +- template_name = "books/books_by_publisher.html", ++ template_name = "books/books_by_publisher.html" + + def get_queryset(self): + self.publisher = get_object_or_404(Publisher, name__iexact=self.args[0]) +diff --git a/docs/topics/db/models.txt b/docs/topics/db/models.txt +index 0e18205..af76344 100644 +--- a/docs/topics/db/models.txt ++++ b/docs/topics/db/models.txt +@@ -324,11 +324,10 @@ whatever you want. For example:: + should work; all are optional. + + For details on accessing backwards-related objects, see the +- `Following relationships backward example`_. +- ++ :ref:`Following relationships backward example <backwards-related-objects>`. ++ + For sample code, see the `Many-to-one relationship model tests`_. + +- .. _Following relationships backward example: http://docs.djangoproject.com/en/dev/topics/db/queries/#backwards-related-objects + .. _Many-to-one relationship model tests: http://code.djangoproject.com/browser/django/trunk/tests/modeltests/many_to_one + + Many-to-many relationships +diff --git a/docs/topics/db/sql.txt b/docs/topics/db/sql.txt +index fe71736..d9b8b1a 100644 +--- a/docs/topics/db/sql.txt ++++ b/docs/topics/db/sql.txt +@@ -236,6 +236,30 @@ alias:: + # Your code here... + transaction.commit_unless_managed(using='my_db_alias') + ++By default, the Python DB API will return results without their field ++names, which means you end up with a ``list`` of values, rather than a ++``dict``. At a small performance cost, you can return results as a ++``dict`` by using something like this:: ++ ++ def dictfetchall(cursor): ++ "Returns all rows from a cursor as a dict" ++ desc = cursor.description ++ return [ ++ dict(zip([col[0] for col in desc], row)) ++ for row in cursor.fetchall() ++ ] ++ ++Here is an example of the difference between the two:: ++ ++ >>> cursor.execute("SELECT id, parent_id from test LIMIT 2"); ++ >>> cursor.fetchall() ++ ((54360982L, None), (54360880L, None)) ++ ++ >>> cursor.execute("SELECT id, parent_id from test LIMIT 2"); ++ >>> dictfetchall(cursor) ++ [{'parent_id': None, 'id': 54360982L}, {'parent_id': None, 'id': 54360880L}] ++ ++ + .. _transactions-and-raw-sql: + + Transactions and raw SQL +diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt +index 07bc5e3..24e000e 100644 +--- a/docs/topics/forms/modelforms.txt ++++ b/docs/topics/forms/modelforms.txt +@@ -332,13 +332,17 @@ Since the Author model has only 3 fields, 'name', 'title', and + .. note:: + + If you specify ``fields`` or ``exclude`` when creating a form with +- ``ModelForm``, then the fields that are not in the resulting form will not +- be set by the form's ``save()`` method. Django will prevent any attempt to +- save an incomplete model, so if the model does not allow the missing fields +- to be empty, and does not provide a default value for the missing fields, +- any attempt to ``save()`` a ``ModelForm`` with missing fields will fail. +- To avoid this failure, you must instantiate your model with initial values +- for the missing, but required fields:: ++ ``ModelForm``, then the fields that are not in the resulting form ++ will not be set by the form's ``save()`` method. Also, if you ++ manually add the excluded fields back to the form, they will not ++ be initialized from the model instance. ++ ++ Django will prevent any attempt to save an incomplete model, so if ++ the model does not allow the missing fields to be empty, and does ++ not provide a default value for the missing fields, any attempt to ++ ``save()`` a ``ModelForm`` with missing fields will fail. To ++ avoid this failure, you must instantiate your model with initial ++ values for the missing, but required fields:: + + author = Author(title='Mr') + form = PartialAuthorForm(request.POST, instance=author) +@@ -633,6 +637,12 @@ database. If a given instance's data didn't change in the bound data, the + instance won't be saved to the database and won't be included in the return + value (``instances``, in the above example). + ++When fields are missing from the form (for example because they have ++been excluded), these fields will not be set by the ``save()`` ++method. You can find more information about this restriction, which ++also holds for regular ``ModelForms``, in `Using a subset of fields on ++the form`_. ++ + Pass ``commit=False`` to return the unsaved model instances:: + + # don't save to the database +diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt +index 1caa801..7a0e724 100644 +--- a/docs/topics/http/urls.txt ++++ b/docs/topics/http/urls.txt +@@ -54,6 +54,10 @@ algorithm the system follows to determine which Python code to execute: + :class:`~django.http.HttpRequest` as its first argument and any values + captured in the regex as remaining arguments. + ++ 5. If no regex matches, or if an exception is raised during any ++ point in this process, Django invokes an appropriate ++ error-handling view. See `Error handling`_ below. ++ + Example + ======= + +@@ -99,10 +103,10 @@ Example requests: + * ``/articles/2003`` would not match any of these patterns, because each + pattern requires that the URL end with a slash. + +- * ``/articles/2003/03/3/`` would match the final pattern. Django would call +- the function ``news.views.article_detail(request, '2003', '03', '3')``. ++ * ``/articles/2003/03/03/`` would match the final pattern. Django would call ++ the function ``news.views.article_detail(request, '2003', '03', '03')``. + +-.. _Dive Into Python's explanation: http://diveintopython.org/regular_expressions/street_addresses.html#re.matching.2.3 ++.. _Dive Into Python's explanation: http://diveintopython.net/regular_expressions/street_addresses.html#re.matching.2.3 + + Named groups + ============ +@@ -123,7 +127,7 @@ Here's the above example URLconf, rewritten to use named groups:: + (r'^articles/2003/$', 'news.views.special_case_2003'), + (r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'), + (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'news.views.month_archive'), +- (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d+)/$', 'news.views.article_detail'), ++ (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', 'news.views.article_detail'), + ) + + This accomplishes exactly the same thing as the previous example, with one +@@ -134,8 +138,8 @@ arguments rather than positional arguments. For example: + ``news.views.month_archive(request, year='2005', month='03')``, instead + of ``news.views.month_archive(request, '2005', '03')``. + +- * A request to ``/articles/2003/03/3/`` would call the function +- ``news.views.article_detail(request, year='2003', month='03', day='3')``. ++ * A request to ``/articles/2003/03/03/`` would call the function ++ ``news.views.article_detail(request, year='2003', month='03', day='03')``. + + In practice, this means your URLconfs are slightly more explicit and less prone + to argument-order bugs -- and you can reorder the arguments in your views' +@@ -246,6 +250,31 @@ The ``prefix`` parameter has the same meaning as the first argument to + ``patterns()`` and is only relevant when you're passing a string as the + ``view`` parameter. + ++include ++------- ++ ++.. function:: include(<module or pattern_list>) ++ ++A function that takes a full Python import path to another URLconf module that ++should be "included" in this place. ++ ++:func:`include` also accepts as an argument an iterable that returns URL ++patterns. ++ ++See `Including other URLconfs`_ below. ++ ++Error handling ++============== ++ ++When Django can't find a regex matching the requested URL, or when an ++exception is raised, Django will invoke an error-handling view. The ++views to use for these cases are specified by two variables which can ++be set in your root URLconf. Setting these variables in any other ++URLconf will have no effect. ++ ++See the documentation on :ref:`customizing error views ++<customizing-error-views>` for more details. ++ + handler404 + ---------- + +@@ -275,19 +304,6 @@ value should suffice. + .. versionchanged:: 1.2 + Previous versions of Django only accepted strings representing import paths. + +-include +-------- +- +-.. function:: include(<module or pattern_list>) +- +-A function that takes a full Python import path to another URLconf module that +-should be "included" in this place. +- +-:func:`include` also accepts as an argument an iterable that returns URL +-patterns. +- +-See `Including other URLconfs`_ below. +- + Notes on capturing text in URLs + =============================== + +@@ -420,8 +436,8 @@ directly the pattern list as returned by `patterns`_ instead. For example:: + from django.conf.urls.defaults import * + + extra_patterns = patterns('', +- url(r'reports/(?P<id>\d+)/$', 'credit.views.report', name='credit-reports'), +- url(r'charge/$', 'credit.views.charge', name='credit-charge'), ++ url(r'^reports/(?P<id>\d+)/$', 'credit.views.report', name='credit-reports'), ++ url(r'^charge/$', 'credit.views.charge', name='credit-charge'), + ) + + urlpatterns = patterns('', +diff --git a/docs/topics/http/views.txt b/docs/topics/http/views.txt +index 99359ab..83a52cb 100644 +--- a/docs/topics/http/views.txt ++++ b/docs/topics/http/views.txt +@@ -122,6 +122,8 @@ In order to use the ``Http404`` exception to its fullest, you should create a + template that is displayed when a 404 error is raised. This template should be + called ``404.html`` and located in the top level of your template tree. + ++.. _customizing-error-views: ++ + Customizing error views + ======================= + +diff --git a/docs/topics/i18n/internationalization.txt b/docs/topics/i18n/internationalization.txt +index 5d50fa7..a83299c 100644 +--- a/docs/topics/i18n/internationalization.txt ++++ b/docs/topics/i18n/internationalization.txt +@@ -477,7 +477,7 @@ for use within the translation block. Examples:: + + You can use multiple expressions inside a single ``blocktrans`` tag:: + +- {% blocktrans with book_t=book|title and author_t=author|title %} ++ {% blocktrans with book_t=book|title author_t=author|title %} + This is {{ book_t }} by {{ author_t }} + {% endblocktrans %} + +diff --git a/docs/topics/settings.txt b/docs/topics/settings.txt +index 61ddf8c..bda51f2 100644 +--- a/docs/topics/settings.txt ++++ b/docs/topics/settings.txt +@@ -39,7 +39,7 @@ The value of ``DJANGO_SETTINGS_MODULE`` should be in Python path syntax, e.g. + ``mysite.settings``. Note that the settings module should be on the + Python `import search path`_. + +-.. _import search path: http://diveintopython.org/getting_to_know_python/everything_is_an_object.html ++.. _import search path: http://diveintopython.net/getting_to_know_python/everything_is_an_object.html + + The django-admin.py utility + --------------------------- +diff --git a/docs/topics/templates.txt b/docs/topics/templates.txt +index 83269ae..fc2cd3f 100644 +--- a/docs/topics/templates.txt ++++ b/docs/topics/templates.txt +@@ -555,6 +555,8 @@ variable that needs escaping. When auto-escaping is on, there's no danger of + the ``escape`` filter *double-escaping* data -- the ``escape`` filter does not + affect auto-escaped variables. + ++.. _string-literals-and-automatic-escaping: ++ + String literals and automatic escaping + -------------------------------------- + +diff --git a/docs/topics/testing.txt b/docs/topics/testing.txt +index 0a86f0d..8262b57 100644 +--- a/docs/topics/testing.txt ++++ b/docs/topics/testing.txt +@@ -1586,7 +1586,7 @@ skipUnlessDBFeature + Skip the decorated test if the named database feature is *not* + supported. + +-For example, the following test will not be executed if the database ++For example, the following test will only be executed if the database + supports transactions (e.g., it would run under PostgreSQL, but *not* + under MySQL with MyISAM tables):: + +diff --git a/tests/modeltests/validators/tests.py b/tests/modeltests/validators/tests.py +index e585262..4bd5827 100644 +--- a/tests/modeltests/validators/tests.py ++++ b/tests/modeltests/validators/tests.py +@@ -28,6 +28,9 @@ TEST_DATA = ( + (validate_email, 'abc', ValidationError), + (validate_email, 'a @x.cz', ValidationError), + (validate_email, 'something@@somewhere.com', ValidationError), ++ # Quoted-string format (CR not allowed) ++ (validate_email, '"\\\011"@here.com', None), ++ (validate_email, '"\\\012"@here.com', ValidationError), + + (validate_slug, 'slug-ok', None), + (validate_slug, 'longer-slug-still-ok', None), +diff --git a/tests/regressiontests/httpwrappers/tests.py b/tests/regressiontests/httpwrappers/tests.py +index 2e2932f..6aabfe6 100644 +--- a/tests/regressiontests/httpwrappers/tests.py ++++ b/tests/regressiontests/httpwrappers/tests.py +@@ -281,3 +281,9 @@ class CookieTests(unittest.TestCase): + Test that a single non-standard cookie name doesn't affect all cookies. Ticket #13007. + """ + self.assertTrue('good_cookie' in parse_cookie('good_cookie=yes;bad:cookie=yes').keys()) ++ ++ def test_repeated_nonstandard_keys(self): ++ """ ++ Test that a repeated non-standard name doesn't affect all cookies. Ticket #15852 ++ """ ++ self.assertTrue('good_cookie' in parse_cookie('a,=b; a,=c; good_cookie=yes').keys()) +diff --git a/tests/regressiontests/utils/http.py b/tests/regressiontests/utils/http.py +index 83a4a7f..666d04f 100644 +--- a/tests/regressiontests/utils/http.py ++++ b/tests/regressiontests/utils/http.py +@@ -1,5 +1,7 @@ + from django.utils import http + from django.utils import unittest ++from django.http import HttpResponse, utils ++from django.test import RequestFactory + + class TestUtilsHttp(unittest.TestCase): + +@@ -21,3 +23,49 @@ class TestUtilsHttp(unittest.TestCase): + self.assertFalse(http.same_origin('http://foo.com', 'http://foo.com.evil.com')) + # Different port + self.assertFalse(http.same_origin('http://foo.com:8000', 'http://foo.com:8001')) ++ ++ def test_fix_IE_for_vary(self): ++ """ ++ Regression for #16632. ++ ++ `fix_IE_for_vary` shouldn't crash when there's no Content-Type header. ++ """ ++ ++ # functions to generate responses ++ def response_with_unsafe_content_type(): ++ r = HttpResponse(content_type="text/unsafe") ++ r['Vary'] = 'Cookie' ++ return r ++ ++ def no_content_response_with_unsafe_content_type(): ++ # 'Content-Type' always defaulted, so delete it ++ r = response_with_unsafe_content_type() ++ del r['Content-Type'] ++ return r ++ ++ # request with & without IE user agent ++ rf = RequestFactory() ++ request = rf.get('/') ++ ie_request = rf.get('/', HTTP_USER_AGENT='MSIE') ++ ++ # not IE, unsafe_content_type ++ response = response_with_unsafe_content_type() ++ utils.fix_IE_for_vary(request, response) ++ self.assertTrue('Vary' in response) ++ ++ # IE, unsafe_content_type ++ response = response_with_unsafe_content_type() ++ utils.fix_IE_for_vary(ie_request, response) ++ self.assertFalse('Vary' in response) ++ ++ # not IE, no_content ++ response = no_content_response_with_unsafe_content_type() ++ utils.fix_IE_for_vary(request, response) ++ self.assertTrue('Vary' in response) ++ ++ # IE, no_content ++ response = no_content_response_with_unsafe_content_type() ++ utils.fix_IE_for_vary(ie_request, response) ++ self.assertFalse('Vary' in response) ++ ++ diff --git a/libre/django13/diff-django_branches_releases_1.3.X-from-16771-to-17460.diff b/libre/django13/diff-django_branches_releases_1.3.X-from-16771-to-17460.diff new file mode 100644 index 000000000..ebbf80993 --- /dev/null +++ b/libre/django13/diff-django_branches_releases_1.3.X-from-16771-to-17460.diff @@ -0,0 +1,1575 @@ +Index: django/http/__init__.py +=================================================================== +--- django/http/__init__.py (revision 16771) ++++ django/http/__init__.py (revision 17460) +@@ -92,7 +92,7 @@ + if not _cookie_allows_colon_in_names: + def load(self, rawdata, ignore_parse_errors=False): + if ignore_parse_errors: +- self.bad_cookies = [] ++ self.bad_cookies = set() + self._BaseCookie__set = self._loose_set + super(SimpleCookie, self).load(rawdata) + if ignore_parse_errors: +@@ -106,8 +106,8 @@ + try: + self._strict_set(key, real_value, coded_value) + except Cookie.CookieError: +- self.bad_cookies.append(key) +- dict.__setitem__(self, key, None) ++ self.bad_cookies.add(key) ++ dict.__setitem__(self, key, Cookie.Morsel()) + + + class CompatCookie(SimpleCookie): +Index: django/http/utils.py +=================================================================== +--- django/http/utils.py (revision 16771) ++++ django/http/utils.py (revision 17460) +@@ -76,7 +76,8 @@ + + # The first part of the Content-Type field will be the MIME type, + # everything after ';', such as character-set, can be ignored. +- if response['Content-Type'].split(';')[0] not in safe_mime_types: ++ mime_type = response.get('Content-Type', '').partition(';')[0] ++ if mime_type not in safe_mime_types: + try: + del response['Vary'] + except KeyError: +Index: django/db/backends/creation.py +=================================================================== +--- django/db/backends/creation.py (revision 16771) ++++ django/db/backends/creation.py (revision 17460) +@@ -374,15 +374,6 @@ + verbosity=max(verbosity - 1, 0), + interactive=False, + database=self.connection.alias) +- +- # One effect of calling syncdb followed by flush is that the id of the +- # default site may or may not be 1, depending on how the sequence was +- # reset. If the sites app is loaded, then we coerce it. +- from django.db.models import get_model +- if 'django.contrib.sites' in settings.INSTALLED_APPS: +- Site = get_model('sites', 'Site') +- if Site is not None and Site.objects.using(self.connection.alias).count() == 1: +- Site.objects.using(self.connection.alias).update(id=settings.SITE_ID) + + from django.core.cache import get_cache + from django.core.cache.backends.db import BaseDatabaseCache +Index: django/core/validators.py +=================================================================== +--- django/core/validators.py (revision 16771) ++++ django/core/validators.py (revision 17460) +@@ -147,7 +147,8 @@ + + email_re = re.compile( + r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom +- r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string ++ # quoted-string, see also http://tools.ietf.org/html/rfc2822#section-3.2.5 ++ r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' + r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE) # domain + validate_email = EmailValidator(email_re, _(u'Enter a valid e-mail address.'), 'invalid') + +Index: django/core/management/commands/shell.py +=================================================================== +--- django/core/management/commands/shell.py (revision 16771) ++++ django/core/management/commands/shell.py (revision 17460) +@@ -13,9 +13,8 @@ + + def ipython(self): + try: +- from IPython.frontend.terminal.embed import TerminalInteractiveShell +- shell = TerminalInteractiveShell() +- shell.mainloop() ++ from IPython import embed ++ embed() + except ImportError: + # IPython < 0.11 + # Explicitly pass an empty list as arguments, because otherwise +Index: django/contrib/gis/db/models/sql/compiler.py +=================================================================== +--- django/contrib/gis/db/models/sql/compiler.py (revision 16771) ++++ django/contrib/gis/db/models/sql/compiler.py (revision 17460) +@@ -1,7 +1,7 @@ + from itertools import izip +-from django.db.backends.util import truncate_name ++from django.db.backends.util import truncate_name, typecast_timestamp + from django.db.models.sql import compiler +-from django.db.models.sql.constants import TABLE_NAME ++from django.db.models.sql.constants import TABLE_NAME, MULTI + from django.db.models.sql.query import get_proxied_model + + SQLCompiler = compiler.SQLCompiler +@@ -194,7 +194,7 @@ + # We resolve the rest of the columns if we're on Oracle or if + # the `geo_values` attribute is defined. + for value, field in map(None, row[index_start:], fields): +- values.append(self.query.convert_values(value, field, connection=self.connection)) ++ values.append(self.query.convert_values(value, field, self.connection)) + else: + values.extend(row[index_start:]) + return tuple(values) +@@ -275,4 +275,24 @@ + pass + + class SQLDateCompiler(compiler.SQLDateCompiler, GeoSQLCompiler): +- pass ++ """ ++ This is overridden for GeoDjango to properly cast date columns, since ++ `GeoQuery.resolve_columns` is used for spatial values. ++ See #14648, #16757. ++ """ ++ def results_iter(self): ++ if self.connection.ops.oracle: ++ from django.db.models.fields import DateTimeField ++ fields = [DateTimeField()] ++ else: ++ needs_string_cast = self.connection.features.needs_datetime_string_cast ++ ++ offset = len(self.query.extra_select) ++ for rows in self.execute_sql(MULTI): ++ for row in rows: ++ date = row[offset] ++ if self.connection.ops.oracle: ++ date = self.resolve_columns(row, fields)[offset] ++ elif needs_string_cast: ++ date = typecast_timestamp(str(date)) ++ yield date +Index: django/contrib/gis/db/backends/spatialite/compiler.py +=================================================================== +--- django/contrib/gis/db/backends/spatialite/compiler.py (revision 16771) ++++ django/contrib/gis/db/backends/spatialite/compiler.py (revision 17460) +@@ -1,32 +0,0 @@ +-from django.db.backends.util import typecast_timestamp +-from django.db.models.sql import compiler +-from django.db.models.sql.constants import MULTI +-from django.contrib.gis.db.models.sql.compiler import GeoSQLCompiler as BaseGeoSQLCompiler +- +-SQLCompiler = compiler.SQLCompiler +- +-class GeoSQLCompiler(BaseGeoSQLCompiler, SQLCompiler): +- pass +- +-class SQLInsertCompiler(compiler.SQLInsertCompiler, GeoSQLCompiler): +- pass +- +-class SQLDeleteCompiler(compiler.SQLDeleteCompiler, GeoSQLCompiler): +- pass +- +-class SQLUpdateCompiler(compiler.SQLUpdateCompiler, GeoSQLCompiler): +- pass +- +-class SQLAggregateCompiler(compiler.SQLAggregateCompiler, GeoSQLCompiler): +- pass +- +-class SQLDateCompiler(compiler.SQLDateCompiler, GeoSQLCompiler): +- """ +- This is overridden for GeoDjango to properly cast date columns, see #16757. +- """ +- def results_iter(self): +- offset = len(self.query.extra_select) +- for rows in self.execute_sql(MULTI): +- for row in rows: +- date = typecast_timestamp(str(row[offset])) +- yield date +Index: django/contrib/gis/db/backends/spatialite/operations.py +=================================================================== +--- django/contrib/gis/db/backends/spatialite/operations.py (revision 16771) ++++ django/contrib/gis/db/backends/spatialite/operations.py (revision 17460) +@@ -48,7 +48,7 @@ + return (SpatiaLiteDistance(operator),) + + class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations): +- compiler_module = 'django.contrib.gis.db.backends.spatialite.compiler' ++ compiler_module = 'django.contrib.gis.db.models.sql.compiler' + name = 'spatialite' + spatialite = True + version_regex = re.compile(r'^(?P<major>\d)\.(?P<minor1>\d)\.(?P<minor2>\d+)') +Index: django/contrib/gis/db/backends/spatialite/creation.py +=================================================================== +--- django/contrib/gis/db/backends/spatialite/creation.py (revision 16771) ++++ django/contrib/gis/db/backends/spatialite/creation.py (revision 17460) +@@ -56,14 +56,6 @@ + interactive=False, + database=self.connection.alias) + +- # One effect of calling syncdb followed by flush is that the id of the +- # default site may or may not be 1, depending on how the sequence was +- # reset. If the sites app is loaded, then we coerce it. +- from django.db.models import get_model +- Site = get_model('sites', 'Site') +- if Site is not None and Site.objects.using(self.connection.alias).count() == 1: +- Site.objects.using(self.connection.alias).update(id=settings.SITE_ID) +- + from django.core.cache import get_cache + from django.core.cache.backends.db import BaseDatabaseCache + for cache_alias in settings.CACHES: +Index: django/contrib/gis/tests/relatedapp/fixtures/initial_data.json.gz +=================================================================== +Cannot display: file marked as a binary type. +svn:mime-type = application/octet-stream +Index: django/contrib/gis/tests/relatedapp/tests.py +=================================================================== +--- django/contrib/gis/tests/relatedapp/tests.py (revision 16771) ++++ django/contrib/gis/tests/relatedapp/tests.py (revision 17460) +@@ -1,3 +1,4 @@ ++from datetime import date + from django.test import TestCase + + from django.contrib.gis.geos import GEOSGeometry, Point, MultiPoint +@@ -281,4 +282,11 @@ + # evaluated as list generation swallows TypeError in CPython. + sql = str(qs.query) + ++ def test16_annotated_date_queryset(self): ++ "Ensure annotated date querysets work if spatial backend is used. See #14648." ++ birth_years = [dt.year for dt in ++ list(Author.objects.annotate(num_books=Count('books')).dates('dob', 'year'))] ++ birth_years.sort() ++ self.assertEqual([1950, 1974], birth_years) ++ + # TODO: Related tests for KML, GML, and distance lookups. +Index: django/contrib/gis/tests/relatedapp/models.py +=================================================================== +--- django/contrib/gis/tests/relatedapp/models.py (revision 16771) ++++ django/contrib/gis/tests/relatedapp/models.py (revision 17460) +@@ -36,6 +36,7 @@ + # These use the GeoManager but do not have any geographic fields. + class Author(models.Model): + name = models.CharField(max_length=100) ++ dob = models.DateField() + objects = models.GeoManager() + + class Article(models.Model): +Index: django/contrib/sites/management.py +=================================================================== +--- django/contrib/sites/management.py (revision 16771) ++++ django/contrib/sites/management.py (revision 17460) +@@ -3,15 +3,34 @@ + """ + + from django.db.models import signals ++from django.db import connections ++from django.db import router + from django.contrib.sites.models import Site + from django.contrib.sites import models as site_app ++from django.core.management.color import no_style + + def create_default_site(app, created_models, verbosity, db, **kwargs): +- if Site in created_models: ++ # Only create the default sites in databases where Django created the table ++ if Site in created_models and router.allow_syncdb(db, Site) : ++ # The default settings set SITE_ID = 1, and some tests in Django's test ++ # suite rely on this value. However, if database sequences are reused ++ # (e.g. in the test suite after flush/syncdb), it isn't guaranteed that ++ # the next id will be 1, so we coerce it. See #15573 and #16353. This ++ # can also crop up outside of tests - see #15346. + if verbosity >= 2: + print "Creating example.com Site object" +- s = Site(domain="example.com", name="example.com") +- s.save(using=db) ++ Site(pk=1, domain="example.com", name="example.com").save(using=db) ++ ++ # We set an explicit pk instead of relying on auto-incrementation, ++ # so we need to reset the database sequence. ++ sequence_sql = connections[db].ops.sequence_reset_sql(no_style(), [Site]) ++ if sequence_sql: ++ if verbosity >= 2: ++ print "Resetting sequence" ++ cursor = connections[db].cursor() ++ for command in sequence_sql: ++ cursor.execute(command) ++ + Site.objects.clear_cache() + + signals.post_syncdb.connect(create_default_site, sender=site_app) +Index: django/contrib/sites/tests.py +=================================================================== +--- django/contrib/sites/tests.py (revision 16771) ++++ django/contrib/sites/tests.py (revision 17460) +@@ -15,6 +15,12 @@ + def tearDown(self): + Site._meta.installed = self.old_Site_meta_installed + ++ def test_save_another(self): ++ # Regression for #17415 ++ # On some backends the sequence needs reset after save with explicit ID. ++ # Test that there is no sequence collisions by saving another site. ++ Site(domain="example2.com", name="example2.com").save() ++ + def test_site_manager(self): + # Make sure that get_current() does not return a deleted Site object. + s = Site.objects.get_current() +Index: django/contrib/admin/media/css/forms.css +=================================================================== +--- django/contrib/admin/media/css/forms.css (revision 16771) ++++ django/contrib/admin/media/css/forms.css (revision 17460) +@@ -352,9 +352,3 @@ + .empty-form { + display: none; + } +- +-/* IE7 specific bug fixes */ +- +-.submit-row input { +- float: right; +-} +\ No newline at end of file +Index: tests/modeltests/validators/tests.py +=================================================================== +--- tests/modeltests/validators/tests.py (revision 16771) ++++ tests/modeltests/validators/tests.py (revision 17460) +@@ -28,6 +28,9 @@ + (validate_email, 'abc', ValidationError), + (validate_email, 'a @x.cz', ValidationError), + (validate_email, 'something@@somewhere.com', ValidationError), ++ # Quoted-string format (CR not allowed) ++ (validate_email, '"\\\011"@here.com', None), ++ (validate_email, '"\\\012"@here.com', ValidationError), + + (validate_slug, 'slug-ok', None), + (validate_slug, 'longer-slug-still-ok', None), +Index: tests/regressiontests/utils/http.py +=================================================================== +--- tests/regressiontests/utils/http.py (revision 16771) ++++ tests/regressiontests/utils/http.py (revision 17460) +@@ -1,5 +1,7 @@ + from django.utils import http + from django.utils import unittest ++from django.http import HttpResponse, utils ++from django.test import RequestFactory + + class TestUtilsHttp(unittest.TestCase): + +@@ -21,3 +23,49 @@ + self.assertFalse(http.same_origin('http://foo.com', 'http://foo.com.evil.com')) + # Different port + self.assertFalse(http.same_origin('http://foo.com:8000', 'http://foo.com:8001')) ++ ++ def test_fix_IE_for_vary(self): ++ """ ++ Regression for #16632. ++ ++ `fix_IE_for_vary` shouldn't crash when there's no Content-Type header. ++ """ ++ ++ # functions to generate responses ++ def response_with_unsafe_content_type(): ++ r = HttpResponse(content_type="text/unsafe") ++ r['Vary'] = 'Cookie' ++ return r ++ ++ def no_content_response_with_unsafe_content_type(): ++ # 'Content-Type' always defaulted, so delete it ++ r = response_with_unsafe_content_type() ++ del r['Content-Type'] ++ return r ++ ++ # request with & without IE user agent ++ rf = RequestFactory() ++ request = rf.get('/') ++ ie_request = rf.get('/', HTTP_USER_AGENT='MSIE') ++ ++ # not IE, unsafe_content_type ++ response = response_with_unsafe_content_type() ++ utils.fix_IE_for_vary(request, response) ++ self.assertTrue('Vary' in response) ++ ++ # IE, unsafe_content_type ++ response = response_with_unsafe_content_type() ++ utils.fix_IE_for_vary(ie_request, response) ++ self.assertFalse('Vary' in response) ++ ++ # not IE, no_content ++ response = no_content_response_with_unsafe_content_type() ++ utils.fix_IE_for_vary(request, response) ++ self.assertTrue('Vary' in response) ++ ++ # IE, no_content ++ response = no_content_response_with_unsafe_content_type() ++ utils.fix_IE_for_vary(ie_request, response) ++ self.assertFalse('Vary' in response) ++ ++ +Index: tests/regressiontests/httpwrappers/tests.py +=================================================================== +--- tests/regressiontests/httpwrappers/tests.py (revision 16771) ++++ tests/regressiontests/httpwrappers/tests.py (revision 17460) +@@ -281,3 +281,9 @@ + Test that a single non-standard cookie name doesn't affect all cookies. Ticket #13007. + """ + self.assertTrue('good_cookie' in parse_cookie('good_cookie=yes;bad:cookie=yes').keys()) ++ ++ def test_repeated_nonstandard_keys(self): ++ """ ++ Test that a repeated non-standard name doesn't affect all cookies. Ticket #15852 ++ """ ++ self.assertTrue('good_cookie' in parse_cookie('a,=b; a,=c; good_cookie=yes').keys()) +Index: docs/index.txt +=================================================================== +--- docs/index.txt (revision 16771) ++++ docs/index.txt (revision 17460) +@@ -28,7 +28,7 @@ + .. _archives of the django-users mailing list: http://groups.google.com/group/django-users/ + .. _post a question: http://groups.google.com/group/django-users/ + .. _#django IRC channel: irc://irc.freenode.net/django +-.. _IRC logs: http://botland.oebfare.com/logger/django/ ++.. _IRC logs: http://django-irc-logs.com/ + .. _ticket tracker: http://code.djangoproject.com/ + + First steps +Index: docs/intro/tutorial01.txt +=================================================================== +--- docs/intro/tutorial01.txt (revision 16771) ++++ docs/intro/tutorial01.txt (revision 17460) +@@ -59,7 +59,7 @@ + can be run as a program. To do this, open Terminal.app and navigate (using + the ``cd`` command) to the directory where :doc:`django-admin.py + </ref/django-admin>` is installed, then run the command +- ``chmod +x django-admin.py``. ++ ``sudo chmod +x django-admin.py``. + + .. note:: + +@@ -692,10 +692,9 @@ + + For more information on model relations, see :doc:`Accessing related objects + </ref/models/relations>`. For more on how to use double underscores to perform +-field lookups via the API, see `Field lookups`__. For full details on the +-database API, see our :doc:`Database API reference </topics/db/queries>`. ++field lookups via the API, see :ref:`Field lookups <field-lookups-intro>`. For ++full details on the database API, see our :doc:`Database API reference ++</topics/db/queries>`. + +-__ http://docs.djangoproject.com/en/1.2/topics/db/queries/#field-lookups +- + When you're comfortable with the API, read :doc:`part 2 of this tutorial + </intro/tutorial02>` to get Django's automatic admin working. +Index: docs/intro/tutorial02.txt +=================================================================== +--- docs/intro/tutorial02.txt (revision 16771) ++++ docs/intro/tutorial02.txt (revision 17460) +@@ -40,22 +40,22 @@ + + .. parsed-literal:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + # Uncomment the next two lines to enable the admin: + **from django.contrib import admin** + **admin.autodiscover()** + + urlpatterns = patterns('', +- # Example: +- # (r'^mysite/', include('mysite.foo.urls')), ++ # Examples: ++ # url(r'^$', 'mysite.views.home', name='home'), ++ # url(r'^mysite/', include('mysite.foo.urls')), + +- # Uncomment the admin/doc line below and add 'django.contrib.admindocs' +- # to INSTALLED_APPS to enable admin documentation: +- # (r'^admin/doc/', include('django.contrib.admindocs.urls')), ++ # Uncomment the admin/doc line below to enable admin documentation: ++ # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), + + # Uncomment the next line to enable the admin: +- **(r'^admin/', include(admin.site.urls)),** ++ **url(r'^admin/', include(admin.site.urls)),** + ) + + (The bold lines are the ones that needed to be uncommented.) +Index: docs/intro/tutorial03.txt +=================================================================== +--- docs/intro/tutorial03.txt (revision 16771) ++++ docs/intro/tutorial03.txt (revision 17460) +@@ -78,17 +78,17 @@ + + Time for an example. Edit ``mysite/urls.py`` so it looks like this:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + from django.contrib import admin + admin.autodiscover() + + urlpatterns = patterns('', +- (r'^polls/$', 'polls.views.index'), +- (r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), +- (r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), +- (r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), +- (r'^admin/', include(admin.site.urls)), ++ url(r'^polls/$', 'polls.views.index'), ++ url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), ++ url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), ++ url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), ++ url(r'^admin/', include(admin.site.urls)), + ) + + This is worth a review. When somebody requests a page from your Web site -- say, +@@ -112,7 +112,7 @@ + -- unless you have a sick sense of humor, in which case you can do something + like this:: + +- (r'^polls/latest\.php$', 'polls.views.index'), ++ url(r'^polls/latest\.php$', 'polls.views.index'), + + But, don't do that. It's silly. + +@@ -357,23 +357,24 @@ + Write a 404 (page not found) view + ================================= + +-When you raise :exc:`~django.http.Http404` from within a view, Django will load +-a special view devoted to handling 404 errors. It finds it by looking for the +-variable ``handler404``, which is a string in Python dotted syntax -- the same +-format the normal URLconf callbacks use. A 404 view itself has nothing special: +-It's just a normal view. ++When you raise :exc:`~django.http.Http404` from within a view, Django ++will load a special view devoted to handling 404 errors. It finds it ++by looking for the variable ``handler404`` in your root URLconf (and ++only in your root URLconf; setting ``handler404`` anywhere else will ++have no effect), which is a string in Python dotted syntax -- the same ++format the normal URLconf callbacks use. A 404 view itself has nothing ++special: It's just a normal view. + +-You normally won't have to bother with writing 404 views. By default, URLconfs +-have the following line up top:: ++You normally won't have to bother with writing 404 views. If you don't set ++``handler404``, the built-in view :func:`django.views.defaults.page_not_found` ++is used by default. In this case, you still have one obligation: To create a ++``404.html`` template in the root of your template directory. The default 404 ++view will use that template for all 404 errors. If :setting:`DEBUG` is set to ++``False`` (in your settings module) and if you didn't create a ``404.html`` ++file, an ``Http500`` is raised instead. So remember to create a ``404.html``. + +- from django.conf.urls.defaults import * ++A couple more things to note about 404 views: + +-That takes care of setting ``handler404`` in the current module. As you can see +-in ``django/conf/urls/defaults.py``, ``handler404`` is set to +-:func:`django.views.defaults.page_not_found` by default. +- +-Four more things to note about 404 views: +- + * If :setting:`DEBUG` is set to ``True`` (in your settings module) then your + 404 view will never be used (and thus the ``404.html`` template will never + be rendered) because the traceback will be displayed instead. +@@ -381,21 +382,12 @@ + * The 404 view is also called if Django doesn't find a match after checking + every regular expression in the URLconf. + +- * If you don't define your own 404 view -- and simply use the default, which +- is recommended -- you still have one obligation: To create a ``404.html`` +- template in the root of your template directory. The default 404 view will +- use that template for all 404 errors. +- +- * If :setting:`DEBUG` is set to ``False`` (in your settings module) and if +- you didn't create a ``404.html`` file, an ``Http500`` is raised instead. +- So remember to create a ``404.html``. +- + Write a 500 (server error) view + =============================== + +-Similarly, URLconfs may define a ``handler500``, which points to a view to call +-in case of server errors. Server errors happen when you have runtime errors in +-view code. ++Similarly, your root URLconf may define a ``handler500``, which points ++to a view to call in case of server errors. Server errors happen when ++you have runtime errors in view code. + + Use the template system + ======================= +@@ -432,10 +424,10 @@ + the URLconf, you may notice there's a fair bit of redundancy in it:: + + urlpatterns = patterns('', +- (r'^polls/$', 'polls.views.index'), +- (r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), +- (r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), +- (r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), ++ url(r'^polls/$', 'polls.views.index'), ++ url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), ++ url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), ++ url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), + ) + + Namely, ``polls.views`` is in every callback. +@@ -445,10 +437,10 @@ + first argument to :func:`~django.conf.urls.defaults.patterns`, like so:: + + urlpatterns = patterns('polls.views', +- (r'^polls/$', 'index'), +- (r'^polls/(?P<poll_id>\d+)/$', 'detail'), +- (r'^polls/(?P<poll_id>\d+)/results/$', 'results'), +- (r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), ++ url(r'^polls/$', 'index'), ++ url(r'^polls/(?P<poll_id>\d+)/$', 'detail'), ++ url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'), ++ url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), + ) + + This is functionally identical to the previous formatting. It's just a bit +@@ -459,20 +451,20 @@ + :func:`~django.conf.urls.defaults.patterns`. Your full ``mysite/urls.py`` might + now look like this:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + from django.contrib import admin + admin.autodiscover() + + urlpatterns = patterns('polls.views', +- (r'^polls/$', 'index'), +- (r'^polls/(?P<poll_id>\d+)/$', 'detail'), +- (r'^polls/(?P<poll_id>\d+)/results/$', 'results'), +- (r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), ++ url(r'^polls/$', 'index'), ++ url(r'^polls/(?P<poll_id>\d+)/$', 'detail'), ++ url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'), ++ url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), + ) + + urlpatterns += patterns('', +- (r'^admin/', include(admin.site.urls)), ++ url(r'^admin/', include(admin.site.urls)), + ) + + Decoupling the URLconfs +@@ -502,8 +494,8 @@ + admin.autodiscover() + + urlpatterns = patterns('', +- (r'^polls/', include('polls.urls')), +- (r'^admin/', include(admin.site.urls)), ++ url(r'^polls/', include('polls.urls')), ++ url(r'^admin/', include(admin.site.urls)), + ) + + :func:`~django.conf.urls.defaults.include` simply references another URLconf. +@@ -526,13 +518,13 @@ + lines registering the admin site. Your ``polls/urls.py`` file should now look like + this:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + urlpatterns = patterns('polls.views', +- (r'^$', 'index'), +- (r'^(?P<poll_id>\d+)/$', 'detail'), +- (r'^(?P<poll_id>\d+)/results/$', 'results'), +- (r'^(?P<poll_id>\d+)/vote/$', 'vote'), ++ url(r'^$', 'index'), ++ url(r'^(?P<poll_id>\d+)/$', 'detail'), ++ url(r'^(?P<poll_id>\d+)/results/$', 'results'), ++ url(r'^(?P<poll_id>\d+)/vote/$', 'vote'), + ) + + The idea behind :func:`~django.conf.urls.defaults.include` and URLconf +Index: docs/intro/index.txt +=================================================================== +--- docs/intro/index.txt (revision 16771) ++++ docs/intro/index.txt (revision 17460) +@@ -31,6 +31,6 @@ + + .. _python: http://python.org/ + .. _list of Python resources for non-programmers: http://wiki.python.org/moin/BeginnersGuide/NonProgrammers +- .. _dive into python: http://diveintopython.org/ ++ .. _dive into python: http://diveintopython.net/ + .. _dead-tree version: http://www.amazon.com/exec/obidos/ASIN/1590593561/ref=nosim/jacobian20 + .. _books about Python: http://wiki.python.org/moin/PythonBooks +\ No newline at end of file +Index: docs/intro/tutorial04.txt +=================================================================== +--- docs/intro/tutorial04.txt (revision 16771) ++++ docs/intro/tutorial04.txt (revision 17460) +@@ -218,13 +218,13 @@ + First, open the ``polls/urls.py`` URLconf. It looks like this, according to the + tutorial so far:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + urlpatterns = patterns('polls.views', +- (r'^$', 'index'), +- (r'^(?P<poll_id>\d+)/$', 'detail'), +- (r'^(?P<poll_id>\d+)/results/$', 'results'), +- (r'^(?P<poll_id>\d+)/vote/$', 'vote'), ++ url(r'^$', 'index'), ++ url(r'^(?P<poll_id>\d+)/$', 'detail'), ++ url(r'^(?P<poll_id>\d+)/results/$', 'results'), ++ url(r'^(?P<poll_id>\d+)/vote/$', 'vote'), + ) + + Change it like so:: +@@ -234,12 +234,12 @@ + from polls.models import Poll + + urlpatterns = patterns('', +- (r'^$', ++ url(r'^$', + ListView.as_view( + queryset=Poll.objects.order_by('-pub_date')[:5], + context_object_name='latest_poll_list', + template_name='polls/index.html')), +- (r'^(?P<pk>\d+)/$', ++ url(r'^(?P<pk>\d+)/$', + DetailView.as_view( + model=Poll, + template_name='polls/detail.html')), +@@ -248,7 +248,7 @@ + model=Poll, + template_name='polls/results.html'), + name='poll_results'), +- (r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), ++ url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), + ) + + We're using two generic views here: +Index: docs/internals/release-process.txt +=================================================================== +--- docs/internals/release-process.txt (revision 16771) ++++ docs/internals/release-process.txt (revision 17460) +@@ -99,6 +99,13 @@ + * Security fixes will be applied to the current trunk and the previous two + minor releases. + ++* Documentation fixes will generally be more freely backported to the last ++ release branch (at the discretion of the committer), and don't need to meet ++ the "critical fixes only" bar as it's highly advantageous to have the docs ++ for the last release be up-to-date and correct, and the downside of ++ backporting (risk of introducing regressions) is much less of a concern ++ with doc fixes. ++ + As a concrete example, consider a moment in time halfway between the release of + Django 1.3 and 1.4. At this point in time: + +@@ -111,6 +118,9 @@ + ``1.2.X`` branch. Security fixes will trigger the release of ``1.3.1``, + ``1.2.1``, etc. + ++* Documentation fixes will be applied to trunk, and if easily backported, to ++ the ``1.3.X`` branch. ++ + .. _release-process: + + Release process +Index: docs/internals/deprecation.txt +=================================================================== +--- docs/internals/deprecation.txt (revision 16771) ++++ docs/internals/deprecation.txt (revision 17460) +@@ -177,6 +177,12 @@ + required to end with a trailing slash to ensure there is a consistent + way to combine paths in templates. + ++ * Translations located under the so-called *project path* will be ++ ignored during the translation building process performed at runtime. ++ The :setting:`LOCALE_PATHS` setting can be used for the same task by ++ including the filesystem path to a ``locale`` directory containing ++ non-app-specific translations in its value. ++ + * 2.0 + * ``django.views.defaults.shortcut()``. This function has been moved + to ``django.contrib.contenttypes.views.shortcut()`` as part of the +Index: docs/howto/deployment/modpython.txt +=================================================================== +--- docs/howto/deployment/modpython.txt (revision 16771) ++++ docs/howto/deployment/modpython.txt (revision 17460) +@@ -293,11 +293,14 @@ + arrangement. You're responsible for setting up Apache, or whichever media + server you're using, to serve the admin files. + +-The admin files live in (:file:`django/contrib/admin/static/admin`) of the ++The admin files live in (:file:`django/contrib/admin/media/admin`) of the + Django distribution. + +-We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle +-the admin files, but here are two other approaches: ++We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle the ++admin files (this means using the :djadmin:`collectstatic` management command ++to collect the static files in :setting:`STATIC_ROOT`, and then configuring ++your webserver to serve :setting:`STATIC_ROOT` at :setting:`STATIC_URL`), but ++here are two other approaches: + + 1. Create a symbolic link to the admin static files from within your + document root. +Index: docs/howto/deployment/modwsgi.txt +=================================================================== +--- docs/howto/deployment/modwsgi.txt (revision 16771) ++++ docs/howto/deployment/modwsgi.txt (revision 17460) +@@ -127,11 +127,14 @@ + arrangement. You're responsible for setting up Apache, or whichever media + server you're using, to serve the admin files. + +-The admin files live in (:file:`django/contrib/admin/static/admin`) of the ++The admin files live in (:file:`django/contrib/admin/media/admin`) of the + Django distribution. + +-We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle +-the admin files, but here are two other approaches: ++We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle the ++admin files (this means using the :djadmin:`collectstatic` management command ++to collect the static files in :setting:`STATIC_ROOT`, and then configuring ++your webserver to serve :setting:`STATIC_ROOT` at :setting:`STATIC_URL`), but ++here are two other approaches: + + 1. Create a symbolic link to the admin static files from within your + document root. +Index: docs/topics/auth.txt +=================================================================== +--- docs/topics/auth.txt (revision 16771) ++++ docs/topics/auth.txt (revision 17460) +@@ -1251,17 +1251,20 @@ + ... + class Meta: + permissions = ( +- ("can_view", "Can see available tasks"), +- ("can_change_status", "Can change the status of tasks"), +- ("can_close", "Can remove a task by setting its status as closed"), ++ ("view_task", "Can see available tasks"), ++ ("change_task_status", "Can change the status of tasks"), ++ ("close_task", "Can remove a task by setting its status as closed"), + ) + + The only thing this does is create those extra permissions when you run + :djadmin:`manage.py syncdb <syncdb>`. Your code is in charge of checking the + value of these permissions when an user is trying to access the functionality + provided by the application (viewing tasks, changing the status of tasks, +-closing tasks.) ++closing tasks.) Continuing the above example, the following checks if a user may ++view tasks:: + ++ user.has_perm('app.view_task') ++ + API reference + ------------- + +Index: docs/topics/http/urls.txt +=================================================================== +--- docs/topics/http/urls.txt (revision 16771) ++++ docs/topics/http/urls.txt (revision 17460) +@@ -54,6 +54,10 @@ + :class:`~django.http.HttpRequest` as its first argument and any values + captured in the regex as remaining arguments. + ++ 5. If no regex matches, or if an exception is raised during any ++ point in this process, Django invokes an appropriate ++ error-handling view. See `Error handling`_ below. ++ + Example + ======= + +@@ -99,10 +103,10 @@ + * ``/articles/2003`` would not match any of these patterns, because each + pattern requires that the URL end with a slash. + +- * ``/articles/2003/03/3/`` would match the final pattern. Django would call +- the function ``news.views.article_detail(request, '2003', '03', '3')``. ++ * ``/articles/2003/03/03/`` would match the final pattern. Django would call ++ the function ``news.views.article_detail(request, '2003', '03', '03')``. + +-.. _Dive Into Python's explanation: http://diveintopython.org/regular_expressions/street_addresses.html#re.matching.2.3 ++.. _Dive Into Python's explanation: http://diveintopython.net/regular_expressions/street_addresses.html#re.matching.2.3 + + Named groups + ============ +@@ -123,7 +127,7 @@ + (r'^articles/2003/$', 'news.views.special_case_2003'), + (r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'), + (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'news.views.month_archive'), +- (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d+)/$', 'news.views.article_detail'), ++ (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', 'news.views.article_detail'), + ) + + This accomplishes exactly the same thing as the previous example, with one +@@ -134,8 +138,8 @@ + ``news.views.month_archive(request, year='2005', month='03')``, instead + of ``news.views.month_archive(request, '2005', '03')``. + +- * A request to ``/articles/2003/03/3/`` would call the function +- ``news.views.article_detail(request, year='2003', month='03', day='3')``. ++ * A request to ``/articles/2003/03/03/`` would call the function ++ ``news.views.article_detail(request, year='2003', month='03', day='03')``. + + In practice, this means your URLconfs are slightly more explicit and less prone + to argument-order bugs -- and you can reorder the arguments in your views' +@@ -246,6 +250,31 @@ + ``patterns()`` and is only relevant when you're passing a string as the + ``view`` parameter. + ++include ++------- ++ ++.. function:: include(<module or pattern_list>) ++ ++A function that takes a full Python import path to another URLconf module that ++should be "included" in this place. ++ ++:func:`include` also accepts as an argument an iterable that returns URL ++patterns. ++ ++See `Including other URLconfs`_ below. ++ ++Error handling ++============== ++ ++When Django can't find a regex matching the requested URL, or when an ++exception is raised, Django will invoke an error-handling view. The ++views to use for these cases are specified by two variables which can ++be set in your root URLconf. Setting these variables in any other ++URLconf will have no effect. ++ ++See the documentation on :ref:`customizing error views ++<customizing-error-views>` for more details. ++ + handler404 + ---------- + +@@ -275,19 +304,6 @@ + .. versionchanged:: 1.2 + Previous versions of Django only accepted strings representing import paths. + +-include +-------- +- +-.. function:: include(<module or pattern_list>) +- +-A function that takes a full Python import path to another URLconf module that +-should be "included" in this place. +- +-:func:`include` also accepts as an argument an iterable that returns URL +-patterns. +- +-See `Including other URLconfs`_ below. +- + Notes on capturing text in URLs + =============================== + +@@ -420,8 +436,8 @@ + from django.conf.urls.defaults import * + + extra_patterns = patterns('', +- url(r'reports/(?P<id>\d+)/$', 'credit.views.report', name='credit-reports'), +- url(r'charge/$', 'credit.views.charge', name='credit-charge'), ++ url(r'^reports/(?P<id>\d+)/$', 'credit.views.report', name='credit-reports'), ++ url(r'^charge/$', 'credit.views.charge', name='credit-charge'), + ) + + urlpatterns = patterns('', +Index: docs/topics/http/views.txt +=================================================================== +--- docs/topics/http/views.txt (revision 16771) ++++ docs/topics/http/views.txt (revision 17460) +@@ -122,6 +122,8 @@ + template that is displayed when a 404 error is raised. This template should be + called ``404.html`` and located in the top level of your template tree. + ++.. _customizing-error-views: ++ + Customizing error views + ======================= + +Index: docs/topics/i18n/internationalization.txt +=================================================================== +--- docs/topics/i18n/internationalization.txt (revision 16771) ++++ docs/topics/i18n/internationalization.txt (revision 17460) +@@ -477,7 +477,7 @@ + + You can use multiple expressions inside a single ``blocktrans`` tag:: + +- {% blocktrans with book_t=book|title and author_t=author|title %} ++ {% blocktrans with book_t=book|title author_t=author|title %} + This is {{ book_t }} by {{ author_t }} + {% endblocktrans %} + +Index: docs/topics/cache.txt +=================================================================== +--- docs/topics/cache.txt (revision 16771) ++++ docs/topics/cache.txt (revision 17460) +@@ -99,8 +99,9 @@ + on your chosen memcached binding) + + * Set :setting:`LOCATION <CACHES-LOCATION>` to ``ip:port`` values, +- where ``ip`` is the IP address of the Memcached daemon and +- ``port`` is the port on which Memcached is running. ++ where ``ip`` is the IP address of the Memcached daemon and ``port`` is the ++ port on which Memcached is running, or to a ``unix:path`` value, where ++ ``path`` is the path to a Memcached Unix socket file. + + In this example, Memcached is running on localhost (127.0.0.1) port 11211, using + the ``python-memcached`` binding:: +@@ -112,6 +113,16 @@ + } + } + ++In this example, Memcached is available through a local Unix socket file ++:file:`/tmp/memcached.sock` using the ``python-memcached`` binding:: ++ ++ CACHES = { ++ 'default': { ++ 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', ++ 'LOCATION': 'unix:/tmp/memcached.sock', ++ } ++ } ++ + One excellent feature of Memcached is its ability to share cache over multiple + servers. This means you can run Memcached daemons on multiple machines, and the + program will treat the group of machines as a *single* cache, without the need +@@ -526,9 +537,10 @@ + requested, subsequent requests to that URL will use the cache. + + ``cache_page`` can also take an optional keyword argument, ``cache``, +-which directs the decorator to use a specific cache alias when caching view +-results. By default, the ``default`` alias will be used, but you can specify +-any cache alias you want:: ++which directs the decorator to use a specific cache (from your ++:setting:`CACHES` setting) when caching view results. By default, the ++``default`` cache will be used, but you can specify any cache you ++want:: + + @cache_page(60 * 15, cache="special_cache") + def my_view(request): +Index: docs/topics/db/models.txt +=================================================================== +--- docs/topics/db/models.txt (revision 16771) ++++ docs/topics/db/models.txt (revision 17460) +@@ -324,11 +324,10 @@ + should work; all are optional. + + For details on accessing backwards-related objects, see the +- `Following relationships backward example`_. +- ++ :ref:`Following relationships backward example <backwards-related-objects>`. ++ + For sample code, see the `Many-to-one relationship model tests`_. + +- .. _Following relationships backward example: http://docs.djangoproject.com/en/dev/topics/db/queries/#backwards-related-objects + .. _Many-to-one relationship model tests: http://code.djangoproject.com/browser/django/trunk/tests/modeltests/many_to_one + + Many-to-many relationships +Index: docs/topics/db/sql.txt +=================================================================== +--- docs/topics/db/sql.txt (revision 16771) ++++ docs/topics/db/sql.txt (revision 17460) +@@ -236,6 +236,30 @@ + # Your code here... + transaction.commit_unless_managed(using='my_db_alias') + ++By default, the Python DB API will return results without their field ++names, which means you end up with a ``list`` of values, rather than a ++``dict``. At a small performance cost, you can return results as a ++``dict`` by using something like this:: ++ ++ def dictfetchall(cursor): ++ "Returns all rows from a cursor as a dict" ++ desc = cursor.description ++ return [ ++ dict(zip([col[0] for col in desc], row)) ++ for row in cursor.fetchall() ++ ] ++ ++Here is an example of the difference between the two:: ++ ++ >>> cursor.execute("SELECT id, parent_id from test LIMIT 2"); ++ >>> cursor.fetchall() ++ ((54360982L, None), (54360880L, None)) ++ ++ >>> cursor.execute("SELECT id, parent_id from test LIMIT 2"); ++ >>> dictfetchall(cursor) ++ [{'parent_id': None, 'id': 54360982L}, {'parent_id': None, 'id': 54360880L}] ++ ++ + .. _transactions-and-raw-sql: + + Transactions and raw SQL +Index: docs/topics/forms/modelforms.txt +=================================================================== +--- docs/topics/forms/modelforms.txt (revision 16771) ++++ docs/topics/forms/modelforms.txt (revision 17460) +@@ -332,14 +332,18 @@ + .. note:: + + If you specify ``fields`` or ``exclude`` when creating a form with +- ``ModelForm``, then the fields that are not in the resulting form will not +- be set by the form's ``save()`` method. Django will prevent any attempt to +- save an incomplete model, so if the model does not allow the missing fields +- to be empty, and does not provide a default value for the missing fields, +- any attempt to ``save()`` a ``ModelForm`` with missing fields will fail. +- To avoid this failure, you must instantiate your model with initial values +- for the missing, but required fields:: ++ ``ModelForm``, then the fields that are not in the resulting form ++ will not be set by the form's ``save()`` method. Also, if you ++ manually add the excluded fields back to the form, they will not ++ be initialized from the model instance. + ++ Django will prevent any attempt to save an incomplete model, so if ++ the model does not allow the missing fields to be empty, and does ++ not provide a default value for the missing fields, any attempt to ++ ``save()`` a ``ModelForm`` with missing fields will fail. To ++ avoid this failure, you must instantiate your model with initial ++ values for the missing, but required fields:: ++ + author = Author(title='Mr') + form = PartialAuthorForm(request.POST, instance=author) + form.save() +@@ -633,6 +637,12 @@ + instance won't be saved to the database and won't be included in the return + value (``instances``, in the above example). + ++When fields are missing from the form (for example because they have ++been excluded), these fields will not be set by the ``save()`` ++method. You can find more information about this restriction, which ++also holds for regular ``ModelForms``, in `Using a subset of fields on ++the form`_. ++ + Pass ``commit=False`` to return the unsaved model instances:: + + # don't save to the database +Index: docs/topics/class-based-views.txt +=================================================================== +--- docs/topics/class-based-views.txt (revision 16771) ++++ docs/topics/class-based-views.txt (revision 17460) +@@ -380,7 +380,7 @@ + class PublisherBookListView(ListView): + + context_object_name = "book_list" +- template_name = "books/books_by_publisher.html", ++ template_name = "books/books_by_publisher.html" + + def get_queryset(self): + publisher = get_object_or_404(Publisher, name__iexact=self.args[0]) +@@ -396,7 +396,7 @@ + class PublisherBookListView(ListView): + + context_object_name = "book_list" +- template_name = "books/books_by_publisher.html", ++ template_name = "books/books_by_publisher.html" + + def get_queryset(self): + self.publisher = get_object_or_404(Publisher, name__iexact=self.args[0]) +Index: docs/topics/testing.txt +=================================================================== +--- docs/topics/testing.txt (revision 16771) ++++ docs/topics/testing.txt (revision 17460) +@@ -1586,7 +1586,7 @@ + Skip the decorated test if the named database feature is *not* + supported. + +-For example, the following test will not be executed if the database ++For example, the following test will only be executed if the database + supports transactions (e.g., it would run under PostgreSQL, but *not* + under MySQL with MyISAM tables):: + +Index: docs/topics/templates.txt +=================================================================== +--- docs/topics/templates.txt (revision 16771) ++++ docs/topics/templates.txt (revision 17460) +@@ -555,6 +555,8 @@ + the ``escape`` filter *double-escaping* data -- the ``escape`` filter does not + affect auto-escaped variables. + ++.. _string-literals-and-automatic-escaping: ++ + String literals and automatic escaping + -------------------------------------- + +Index: docs/topics/settings.txt +=================================================================== +--- docs/topics/settings.txt (revision 16771) ++++ docs/topics/settings.txt (revision 17460) +@@ -39,7 +39,7 @@ + ``mysite.settings``. Note that the settings module should be on the + Python `import search path`_. + +-.. _import search path: http://diveintopython.org/getting_to_know_python/everything_is_an_object.html ++.. _import search path: http://diveintopython.net/getting_to_know_python/everything_is_an_object.html + + The django-admin.py utility + --------------------------- +Index: docs/releases/1.2.6.txt +=================================================================== +--- docs/releases/1.2.6.txt (revision 0) ++++ docs/releases/1.2.6.txt (revision 17460) +@@ -0,0 +1,16 @@ ++========================== ++Django 1.2.6 release notes ++========================== ++ ++*September 9, 2011* ++ ++Welcome to Django 1.2.6! ++ ++This is the sixth bugfix/security release in the Django 1.2 series, fixing ++several security issues present in Django 1.2.5. Django 1.2.6 is a ++recommended upgrade for all users of any Django release in the 1.2.X series. ++ ++For a full list of issues addressed in this release, see the `security ++advisory`_. ++ ++.. _security advisory: https://www.djangoproject.com/weblog/2011/sep/09/security-releases-issued/ +Index: docs/releases/1.2.7.txt +=================================================================== +--- docs/releases/1.2.7.txt (revision 0) ++++ docs/releases/1.2.7.txt (revision 17460) +@@ -0,0 +1,16 @@ ++========================== ++Django 1.2.7 release notes ++========================== ++ ++*September 10, 2011* ++ ++Welcome to Django 1.2.7! ++ ++This is the seventh bugfix/security release in the Django 1.2 series. It ++replaces Django 1.2.6 due to problems with the 1.2.6 release tarball. ++Django 1.2.7 is a recommended upgrade for all users of any Django release in ++the 1.2.X series. ++ ++For more information, see the `release advisory`_. ++ ++.. _release advisory: https://www.djangoproject.com/weblog/2011/sep/10/127/ +Index: docs/releases/index.txt +=================================================================== +--- docs/releases/index.txt (revision 16771) ++++ docs/releases/index.txt (revision 17460) +@@ -19,6 +19,7 @@ + .. toctree:: + :maxdepth: 1 + ++ 1.3.1 + 1.3 + + 1.2 release +@@ -26,6 +27,8 @@ + .. toctree:: + :maxdepth: 1 + ++ 1.2.7 ++ 1.2.6 + 1.2.5 + 1.2.4 + 1.2.2 +Index: docs/releases/0.95.txt +=================================================================== +--- docs/releases/0.95.txt (revision 16771) ++++ docs/releases/0.95.txt (revision 17460) +@@ -92,15 +92,15 @@ + easy checklist_ for reference when undertaking the porting operation. + + .. _Removing The Magic: http://code.djangoproject.com/wiki/RemovingTheMagic +-.. _checklist: http://code.djangoproject.com/wiki/MagicRemovalCheatSheet1 ++.. _checklist: http://code.djangoproject.com/wiki/MagicRemovalCheatSheet + + Problem reports and getting help + ================================ + +-Need help resolving a problem with Django? The documentation in the distribution +-is also available online_ at the `Django Web site`_. The :doc:`FAQ </faq/index>` +-document is especially recommended, as it contains a number of issues that come +-up time and again. ++Need help resolving a problem with Django? The documentation in the ++distribution is also available :doc:`online </index>` at the `Django Web ++site`_. The :doc:`FAQ </faq/index>` document is especially recommended, as it ++contains a number of issues that come up time and again. + + For more personalized help, the `django-users`_ mailing list is a very active + list, with more than 2,000 subscribers who can help you solve any sort of +@@ -113,7 +113,6 @@ + Django users and developers from around the world. Friendly people are usually + available at any hour of the day -- to help, or just to chat. + +-.. _online: http://www.djangoproject.com/documentation/0.95/ + .. _Django Web site: http://www.djangoproject.com/ + .. _django-users: http://groups.google.com/group/django-users + +Index: docs/releases/0.96.txt +=================================================================== +--- docs/releases/0.96.txt (revision 16771) ++++ docs/releases/0.96.txt (revision 17460) +@@ -50,12 +50,10 @@ + maintained, and it will be removed in a future release of Django. + + Also, note that some features, like the new :setting:`DATABASE_OPTIONS` +-setting (see the `databases documentation`_ for details), are only +-available on the "mysql" backend, and will not be made available for ++setting (see the :doc:`databases documentation </ref/databases>` for details), ++are only available on the "mysql" backend, and will not be made available for + "mysql_old". + +-.. _databases documentation: http://www.djangoproject.com/documentation/0.96/databases/ +- + Database constraint names changed + --------------------------------- + +@@ -164,11 +162,9 @@ + for most common cases. We recommend that anyone new to form handling skip the + old forms system and start with the new. + +-For more information about ``django.newforms``, read the `newforms +-documentation`_. ++For more information about ``django.newforms``, read the :doc:`newforms ++documentation </topics/forms/index>`. + +-.. _newforms documentation: http://www.djangoproject.com/documentation/0.96/newforms/ +- + URLconf improvements + -------------------- + +@@ -216,20 +212,16 @@ + ------------------ + + Django now includes a test framework so you can start transmuting fear into +-boredom (with apologies to Kent Beck). You can write tests based on doctest_ +-or unittest_ and test your views with a simple test client. ++boredom (with apologies to Kent Beck). You can write tests based on ++:mod:`doctest` or :mod:`unittest` and test your views with a simple test client. + + There is also new support for "fixtures" -- initial data, stored in any of the +-supported `serialization formats`_, that will be loaded into your database at the +-start of your tests. This makes testing with real data much easier. ++supported :doc:`serialization formats </topics/serialization>`, that will be ++loaded into your database at the start of your tests. This makes testing with ++real data much easier. + +-See `the testing documentation`_ for the full details. ++See :doc:`the testing documentation </topics/testing>` for the full details. + +-.. _doctest: http://docs.python.org/library/doctest.html +-.. _unittest: http://docs.python.org/library/unittest.html +-.. _the testing documentation: http://www.djangoproject.com/documentation/0.96/testing/ +-.. _serialization formats: http://www.djangoproject.com/documentation/0.96/serialization/ +- + Improvements to the admin interface + ----------------------------------- + +Index: docs/releases/1.0.1.txt +=================================================================== +--- docs/releases/1.0.1.txt (revision 16771) ++++ docs/releases/1.0.1.txt (revision 17460) +@@ -6,10 +6,10 @@ + + This is the first "bugfix" release in the Django 1.0 series, improving + the stability and performance of the Django 1.0 codebase. As such, +-Django 1.0.1 contains no new features (and, pursuant to `our +-compatibility policy`_, maintains backwards compatibility with Django +-1.0), but does contain a number of fixes and other +-improvements. Django 1.0.1 is a recommended upgrade for any ++Django 1.0.1 contains no new features (and, pursuant to :doc:`our ++compatibility policy </misc/api-stability/>`, maintains backwards ++compatibility with Django 1.0), but does contain a number of fixes ++and other improvements. Django 1.0.1 is a recommended upgrade for any + development or deployment currently using or targeting Django 1.0. + + +@@ -46,8 +46,9 @@ + + * A fix to the application of autoescaping for literal strings passed + to the ``join`` template filter. Previously, literal strings passed +- to ``join`` were automatically escaped, contrary to `the documented +- behavior for autoescaping and literal strings`_. Literal strings ++ to ``join`` were automatically escaped, contrary to :ref:`the ++ documented behavior for autoescaping and literal strings ++ <string-literals-and-automatic-escaping>`. Literal strings + passed to ``join`` are no longer automatically escaped, meaning you + must now manually escape them; this is an incompatibility if you + were relying on this bug, but not if you were relying on escaping +@@ -60,6 +61,4 @@ + documentation, including both corrections to existing documents and + expanded and new documentation. + +-.. _our compatibility policy: http://docs.djangoproject.com/en/dev/misc/api-stability/ + .. _the Subversion log of the 1.0.X branch: http://code.djangoproject.com/log/django/branches/releases/1.0.X +-.. _the documented behavior for autoescaping and literal strings: http://docs.djangoproject.com/en/dev/topics/templates/#string-literals-and-automatic-escaping +Index: docs/releases/1.3.1.txt +=================================================================== +--- docs/releases/1.3.1.txt (revision 0) ++++ docs/releases/1.3.1.txt (revision 17460) +@@ -0,0 +1,16 @@ ++========================== ++Django 1.3.1 release notes ++========================== ++ ++*September 9, 2011* ++ ++Welcome to Django 1.3.1! ++ ++This is the first security release in the Django 1.3 series, fixing several ++security issues in Django 1.3. Django 1.3.1 is a recommended upgrade for ++all users of Django 1.3. ++ ++For a full list of issues addressed in this release, see the `security ++advisory`_. ++ ++.. _security advisory: https://www.djangoproject.com/weblog/2011/sep/09/security-releases-issued/ +Index: docs/ref/models/instances.txt +=================================================================== +--- docs/ref/models/instances.txt (revision 16771) ++++ docs/ref/models/instances.txt (revision 17460) +@@ -470,7 +470,7 @@ + + Similarly, if you had a URLconf entry that looked like:: + +- (r'/archive/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/$', archive_view) ++ (r'/archive/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', archive_view) + + ...you could reference this using ``permalink()`` as follows:: + +@@ -478,8 +478,8 @@ + def get_absolute_url(self): + return ('archive_view', (), { + 'year': self.created.year, +- 'month': self.created.month, +- 'day': self.created.day}) ++ 'month': self.created.strftime('%m'), ++ 'day': self.created.strftime('%d')}) + + Notice that we specify an empty sequence for the second parameter in this case, + because we only want to pass keyword parameters, not positional ones. +Index: docs/ref/models/options.txt +=================================================================== +--- docs/ref/models/options.txt (revision 16771) ++++ docs/ref/models/options.txt (revision 17460) +@@ -166,6 +166,13 @@ + >>> answer.get_previous_in_order() + <Answer: 1> + ++.. admonition:: Changing order_with_respect_to ++ ++ ``order_with_respect_to`` adds an additional field/database column ++ named ``_order``, so be sure to handle that as you would any other ++ change to your models if you add or change ``order_with_respect_to`` ++ after your initial :djadmin:`syncdb`. ++ + ``ordering`` + ------------ + +@@ -238,6 +245,12 @@ + + unique_together = ("driver", "restaurant") + ++ A :class:`~django.db.models.ManyToManyField` cannot be included in ++ unique_together (it's not even clear what that would mean). If you ++ need to validate uniqueness related to a ++ :class:`~django.db.models.ManyToManyField`, look at signals or ++ using an explicit :attr:`through <ManyToManyField.through>` model. ++ + ``verbose_name`` + ---------------- + +Index: docs/ref/templates/builtins.txt +=================================================================== +--- docs/ref/templates/builtins.txt (revision 16771) ++++ docs/ref/templates/builtins.txt (revision 17460) +@@ -1868,7 +1868,7 @@ + Returns a slice of the list. + + Uses the same syntax as Python's list slicing. See +-http://diveintopython.org/native_data_types/lists.html#odbchelper.list.slice ++http://diveintopython.net/native_data_types/lists.html#odbchelper.list.slice + for an introduction. + + Example:: +Index: docs/ref/contrib/gis/geoip.txt +=================================================================== +--- docs/ref/contrib/gis/geoip.txt (revision 16771) ++++ docs/ref/contrib/gis/geoip.txt (revision 17460) +@@ -144,7 +144,7 @@ + Returns a dictionary of city information for the given query. Some + of the values in the dictionary may be undefined (``None``). + +-.. method:: GeoIPcountry(query) ++.. method:: GeoIP.country(query) + + Returns a dictionary with the country code and country for the given + query. +Index: docs/ref/contrib/messages.txt +=================================================================== +--- docs/ref/contrib/messages.txt (revision 16771) ++++ docs/ref/contrib/messages.txt (revision 17460) +@@ -210,6 +210,10 @@ + ``RequestContext``. Otherwise, ensure ``messages`` is available to + the template context. + ++Even if you know there is only just one message, you should still iterate over ++the ``messages`` sequence, because otherwise the message storage will not be cleared ++for the next request. ++ + Creating custom message levels + ------------------------------ + +Index: docs/ref/contrib/admin/index.txt +=================================================================== +--- docs/ref/contrib/admin/index.txt (revision 16771) ++++ docs/ref/contrib/admin/index.txt (revision 17460) +@@ -19,8 +19,10 @@ + 1. Add ``'django.contrib.admin'`` to your :setting:`INSTALLED_APPS` + setting. + +- 2. Admin has two dependencies - :mod:`django.contrib.auth` and +- :mod:`django.contrib.contenttypes`. If these applications are not ++ 2. The admin has four dependencies - :mod:`django.contrib.auth`, ++ :mod:`django.contrib.contenttypes`, ++ :mod:`django.contrib.messages` and ++ :mod:`django.contrib.sessions`. If these applications are not + in your :setting:`INSTALLED_APPS` list, add them. + + 3. Determine which of your application's models should be editable in the +@@ -542,7 +544,7 @@ + Fields in ``list_filter`` can also span relations using the ``__`` lookup:: + + class UserAdminWithLookup(UserAdmin): +- list_filter = ('groups__name') ++ list_filter = ('groups__name',) + + .. attribute:: ModelAdmin.list_per_page + +Index: docs/ref/django-admin.txt +=================================================================== +--- docs/ref/django-admin.txt (revision 16771) ++++ docs/ref/django-admin.txt (revision 17460) +@@ -1156,7 +1156,7 @@ + Note that this option is unnecessary in ``manage.py``, because it takes care of + setting the Python path for you. + +-.. _import search path: http://diveintopython.org/getting_to_know_python/everything_is_an_object.html ++.. _import search path: http://diveintopython.net/getting_to_know_python/everything_is_an_object.html + + .. django-admin-option:: --settings + +Index: docs/ref/signals.txt +=================================================================== +--- docs/ref/signals.txt (revision 16771) ++++ docs/ref/signals.txt (revision 17460) +@@ -352,12 +352,16 @@ + .. data:: django.db.models.signals.post_syncdb + :module: + +-Sent by :djadmin:`syncdb` after it installs an application. ++Sent by :djadmin:`syncdb` command after it installs an application, and ++:djadmin:`flush` command. + + Any handlers that listen to this signal need to be written in a particular + place: a ``management`` module in one of your :setting:`INSTALLED_APPS`. If + handlers are registered anywhere else they may not be loaded by +-:djadmin:`syncdb`. ++:djadmin:`syncdb`. It is important that handlers of this signal perform ++idempotent changes (e.g. no database alterations) as this may cause the ++:djadmin:`flush` management command to fail if it also ran during the ++:djadmin:`syncdb` command. + + Arguments sent with this signal: + +Index: README +=================================================================== +--- README (revision 16771) ++++ README (revision 17460) +@@ -28,7 +28,7 @@ + To get more help: + + * Join the #django channel on irc.freenode.net. Lots of helpful people +- hang out there. Read the archives at http://botland.oebfare.com/logger/django/. ++ hang out there. Read the archives at http://django-irc-logs.com/. + + * Join the django-users mailing list, or read the archives, at + http://groups.google.com/group/django-users. diff --git a/libre/parabolaweb-git/Makefile b/libre/parabolaweb-git/Makefile deleted file mode 100755 index 55115aba3..000000000 --- a/libre/parabolaweb-git/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -all: - makepkg - -python_packages=south -python2_packages=markdown|psycopg2|pyinotify|pytz -requirements= https://projects.parabolagnulinux.org/parabolaweb.git/plain/requirements_prod.txt - -requirements_prod.txt: WEB - rm -f $@ - wget --no-check-certificate $(requirements) - -deps-ver.txt: requirements_prod.txt - sed -r -e 's/.*/\L&/' -e 's/==/=/' \ - -e 's/^(${python_packages})/python-&/' \ - -e 's/^(${python2_packages})/python2-&/' $< >$@ - -deps-nover.txt: deps-ver.txt - sed 's/[<>=].*//' $< >$@ - -clean: - rm requirements_prod.txt deps-ver.txt deps-nover.txt - -WEB: FORCE -FORCE: PHONY -PHONY: -.PHONY: PHONY diff --git a/libre/parabolaweb-git/PKGBUILD b/libre/parabolaweb-git/PKGBUILD deleted file mode 100755 index 4641ea8d3..000000000 --- a/libre/parabolaweb-git/PKGBUILD +++ /dev/null @@ -1,43 +0,0 @@ -# Maintainer: Luke Shumaker <lukeshu@sbcglobal.net> - -pkgname=parabolaweb-git -pkgver=20120506 -pkgrel=3 -pkgdesc="The Parabola website, fork of archweb" -arch=('any') -url="https://projects.parabolagnulinux.org/parabolaweb.git/" -license=('GPL2') - -_deps_file=deps-ver.txt -#_deps_file=deps-nover.txt -make "$_deps_file" 1>&2 -depends=('python2' 'git' 'libretools' `cat $_deps_file`) - -source=('parabolaweb.init.sh' 'parabolaweb.update.sh.in') - -# These will make it install into /http/srv/web -_install_dir=/srv/http -_gitname=web - -_gitroot=https://projects.parabolagnulinux.org/parabolaweb.git -_gitbranch="master" - -build() { - cd "${srcdir}" - sed \ - -e "s|^_install_dir=.*|_install_dir='$_install_dir'|" \ - -e "s|^_gitname=.*|_gitname='$_gitname'|" \ - -e "s|^_gitroot=.*|_gitroot='$_gitroot'|" \ - -e "s|^_gitbranch=.*|_gitbranch='$_gitbranch'|" \ - < parabolaweb.update.sh.in > parabolaweb.update.sh -} - -package() { - cd "${srcdir}" - install -d "${pkgdir}/${_install_dir}" - install -Dm755 parabolaweb.init.sh "${pkgdir}/etc/rc.d/parabolaweb" - install -Dm755 parabolaweb.update.sh "${pkgdir}/usr/sbin/parabolaweb.update" -} - -md5sums=('72bc7092e4e50a2aaca8b871644520d9' - 'f495b2e4623691925308cb4a1ec7e5a9') diff --git a/libre/parabolaweb-git/deps-ver.txt b/libre/parabolaweb-git/deps-ver.txt deleted file mode 100755 index 67fe6848b..000000000 --- a/libre/parabolaweb-git/deps-ver.txt +++ /dev/null @@ -1,7 +0,0 @@ -django=1.3.1 -python2-markdown>=2.0.3 -python2-psycopg2 -python-south>=0.7.3 -python2-pyinotify>=0.9.2 -python-memcached>=1.47 -python2-pytz>=2011n diff --git a/libre/parabolaweb-git/parabolaweb.init.sh b/libre/parabolaweb-git/parabolaweb.init.sh deleted file mode 100755 index cb9f2441e..000000000 --- a/libre/parabolaweb-git/parabolaweb.init.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -. /etc/rc.conf -. /etc/rc.d/functions - -HOST=127.0.0.1 -PORT=8090 # 80 is nginx -PIDFILE=/var/run/web/fcgi.pid - -case $1 in -start) - stat_busy "Starting ParabolaWeb" - if [[ -e /srv/http/web/manage.py ]]; then - sudo -u nobody \ - python2 /srv/http/web/manage.py runfcgi \ - host=${HOST} \ - port=${PORT} \ - pidfile=${PIDFILE} \ - --settings=settings - - add_daemon parabolaweb - stat_done - exit 0 - else - stat_fail - exit 1 - fi - ;; - -stop) - stat_busy "Stopping ParabolaWeb" - if [[ -f ${PIDFILE} ]]; then - pid=$(cat ${PIDFILE}) - kill ${pid} - rm_daemon parabolaweb - stat_done - else - stat_fail - exit 1 - fi - ;; - -restart) - $0 stop - $0 start - ;; - -*) - echo "Usage: $0 {start|stop|restart}" >&2 - exit 1 - -esac diff --git a/libre/parabolaweb-git/parabolaweb.update.sh.in b/libre/parabolaweb-git/parabolaweb.update.sh.in deleted file mode 100755 index 8c3aef0f0..000000000 --- a/libre/parabolaweb-git/parabolaweb.update.sh.in +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/sh -set -e - -_install_dir=@INSTALL_DIR@ -_gitname=@GIT_NAME@ - -_gitroot=@GITROOT@ -_gitbranch=@GITBRANCH@ - -. /usr/bin/libremessages - -if [ ! -d "$_install_dir" ]; then - mkdir "$_install_dir" -fi -cd "$_install_dir" - -msg "Connecting to GIT server...." -if [ -d ${_gitname} ] ; then - msg2 "Updating existing tree" - cd ${_gitname} && git pull ${_gitroot} -else - msg2 "Cloning tree" - git clone ${_gitroot} ${_gitname} - cd ${_gitname} -fi -git checkout ${_gitbranch} -msg "GIT checkout done or server timeout" - -msg "Purging old .pyc files...." -find . -name '*.pyc' -delete - -msg "Checking configuration...." -if [ ! -f local_settings.py ]; then - cp local_settings.py.example local_settings.tmp.$$.py - if ${EDITOR:-xdg-open} local_settings.tmp.$$.py; then - mv local_settings.tmp.$$.py local_settings.py - else - rm local_settings.tmp.$$.py - msg "Failed to configure, exiting" - exit 1 - fi - msg "Creating database...." - ./manage.py syncdb -fi - -msg "Purging old .pyc files...." -find . -name '*.pyc' -delete - -msg "Updating database...." -msg2 "Running migrations...." -./manage.py migrate -msg2 "Loading fixtures...." -./manage.py loaddata */fixtures/*.json - -msg "Checking media/admin_media symlink...." -if [ ! -e media/admin-media ]; then - rm media/admin_media - ln -s /usr/lib/python2.7/site-packages/django/contrib/admin/media media/admin_media -fi diff --git a/libre/parabolaweb-git/requirements_prod.txt b/libre/parabolaweb-git/requirements_prod.txt deleted file mode 100755 index 78eb51250..000000000 --- a/libre/parabolaweb-git/requirements_prod.txt +++ /dev/null @@ -1,7 +0,0 @@ -Django==1.3.1 -Markdown>=2.0.3 -psycopg2 -South>=0.7.3 -pyinotify>=0.9.2 -python-memcached>=1.47 -pytz>=2011n diff --git a/libre/parabolaweb-utils/PKGBUILD b/libre/parabolaweb-utils/PKGBUILD new file mode 100644 index 000000000..3b57c5d13 --- /dev/null +++ b/libre/parabolaweb-utils/PKGBUILD @@ -0,0 +1,37 @@ +# Maintainer: Luke Shumaker <lukeshu@sbcglobal.net> + +. helper.sh +# provides: +# _get_pkgver +# _get_depends +# _get_depends_nover (no version requirements) + +pkgname=parabolaweb-utils +pkgver=`_get_pkgver` +pkgrel=1 +pkgdesc="Utils for the Parabola website" +arch=('any') +url="https://projects.parabolagnulinux.org/parabolaweb.git/" +license=('GPL2') +depends=('python2' 'git' 'libretools' `_get_depends`) + +export pkgver + +source=(git://parabolagnulinux.org/parabolaweb.git + parabolaweb.init.sh + update-parabolaweb) + +build() { + : +} + +package() { + cd "${srcdir}" + install -d "${pkgdir}/${_install_dir}" + install -Dm755 parabolaweb.init.sh "${pkgdir}/etc/rc.d/parabolaweb" + install -Dm755 update-parabolaweb "${pkgdir}/usrls/sbin/update-parabolaweb" +} + +md5sums=('SKIP' + 'f52aebbedaa61f688fb2bc626a783003' + 'dd05d6a4ea7cff7fdd789f59aeb9059a') diff --git a/libre/parabolaweb-utils/helper.sh b/libre/parabolaweb-utils/helper.sh new file mode 100644 index 000000000..d00f83f7f --- /dev/null +++ b/libre/parabolaweb-utils/helper.sh @@ -0,0 +1,37 @@ +_mksource() { + if [[ -z _DO_NOT_RUN_MKSOURCE ]]; then + _DO_NOT_RUN_MKSOURCE=true makepkg -o + fi +} + +_get_pkgver() { + if [[ -n $pkgver ]] && [[ $pkgver != 0.bogus ]]; then + echo $pkgver + else + _mksource 1>&2 + if [[ -f "${srcdir:-src}/parabolaweb/requirements_prod.txt" ]]; then + pushd "${srcdir:-src}/parabolaweb" >/dev/null + # get the date requirements_prod.txt was last modified + gitdate="$(git log -n1 --date=iso --format=format:'%cd' ./requirements_prod.txt)" + date -u +%Y%m%d.%H%M -d "$gitdate" + popd >/dev/null + else + echo 0.bogus + fi + fi +} + +_get_depends() { + _mksource 1>&2 + pushd "${srcdir:-src}" >/dev/null + python2_packages='markdown|psycopg2|pyinotify|pytz|south' + < parabolaweb/requirements_prod.txt sed -r \ + -e 's/.*/\L&/' -e 's/==/=/' \ + -e 's/^python-memcached/python2-memcached/' \ + -e "s/^(${python2_packages})/python2-&/" + popd >/dev/null +} + +_get_depends_nover() { + _get_depends | sed 's/[<>=].*//' +} diff --git a/libre/parabolaweb-utils/parabolaweb.init.sh b/libre/parabolaweb-utils/parabolaweb.init.sh new file mode 100644 index 000000000..0ff8ecd7c --- /dev/null +++ b/libre/parabolaweb-utils/parabolaweb.init.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +. /etc/rc.conf +. /etc/rc.d/functions + +HOST=127.0.0.1 +PORT=8090 # 80 is nginx +PIDFILE=/var/run/web/fcgi.pid + +case $1 in +start) + stat_busy "Starting ParabolaWeb" + if [[ -e /srv/http/web/manage.py ]]; then + sudo -u nobody \ + python2 /srv/http/web/manage.py runfcgi \ + host=${HOST} \ + port=${PORT} \ + pidfile=${PIDFILE} \ + --settings=settings + add_daemon parabolaweb + stat_done + exit 0 + else + stat_fail + exit 1 + fi + ;; + +stop) + stat_busy "Stopping ParabolaWeb" + if [[ -f ${PIDFILE} ]]; then + pid=$(cat ${PIDFILE}) + kill ${pid} + rm_daemon parabolaweb + stat_done + else + stat_fail + exit 1 + fi + ;; + +restart) + $0 stop + $0 start + ;; + +*) + echo "Usage: $0 {start|stop|restart}" >&2 + exit 1 + +esac diff --git a/libre/parabolaweb-utils/update-parabolaweb b/libre/parabolaweb-utils/update-parabolaweb new file mode 100644 index 000000000..e4d65c2d9 --- /dev/null +++ b/libre/parabolaweb-utils/update-parabolaweb @@ -0,0 +1,81 @@ +#!/bin/bash +set -e + +_install_dir=/srv/http +_gitname=web +_gitroot=git://parabolagnulinux.org/parabolaweb.git +_gitbranch=master + +. /usr/bin/libremessages + +download() { + msg "Connecting to GIT server...." + cd "$_install_dir" + if [[ -d ${_gitname} ]]; then + msg2 "Updating existing tree" + cd ${_gitname} && git pull ${_gitroot} + else + msg2 "Cloning tree" + git clone ${_gitroot} ${_gitname} + cd ${_gitname} + fi + git checkout ${_gitbranch} + msg "GIT checkout done or server timeout" +} + +clean() { + msg "Purging old .pyc files...." + cd "$_install_dir/$_gitname" + find . -name '*.pyc' -delete +} + +configure() { + msg "Checking configuration...." + cd "$_install_dir/$_gitname" + if [[ ! -f local_settings.py ]]; then + msg2 "Configuration file missing, opening editor..." + cp local_settings.py.example local_settings.tmp.$$.py + if "$EDITOR" local_settings.tmp.$$.py; then + mv local_settings.tmp.$$.py local_settings.py + else + rm local_settings.tmp.$$.py + msg "Failed to configure, exiting" + exit 1 + fi + msg2 "Creating database...." + ./manage.py syncdb + else + msg2 "Current configuration checks out" + fi +} + +migrate() { + msg "Updating database...." + msg2 "Running migrations...." + ./manage.py migrate + msg2 "Loading fixtures...." + ./manage.py loaddata */fixtures/*.json +} + +main() { + if [[ -z "$EDITOR" ]]; then + error 'Please set the $EDITOR variable' + exit 1 + fi + + [[ ! -d "$_install_dir" ]] && mkdir "$_install_dir" + + download + clean + configure + clean + migrate + + msg "Checking media/admin_media symlink...." + if [ ! -e media/admin-media ]; then + rm media/admin_media + ln -s /usr/lib/python2.7/site-packages/django/contrib/admin/media media/admin_media + fi +} + +main "$@" |