mirror of
https://github.com/django/django.git
synced 2025-07-05 18:29:11 +00:00
[soc2010/test-refactor] Merged up to trunk.
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2010/test-refactor@13468 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
9315b44ad1
commit
5875c4e01c
@ -6,7 +6,7 @@ class MySQLCreation(DatabaseCreation):
|
|||||||
from django.contrib.gis.db.models.fields import GeometryField
|
from django.contrib.gis.db.models.fields import GeometryField
|
||||||
output = super(MySQLCreation, self).sql_indexes_for_field(model, f, style)
|
output = super(MySQLCreation, self).sql_indexes_for_field(model, f, style)
|
||||||
|
|
||||||
if isinstance(f, GeometryField):
|
if isinstance(f, GeometryField) and f.spatial_index:
|
||||||
qn = self.connection.ops.quote_name
|
qn = self.connection.ops.quote_name
|
||||||
db_table = model._meta.db_table
|
db_table = model._meta.db_table
|
||||||
idx_name = '%s_%s_id' % (db_table, f.column)
|
idx_name = '%s_%s_id' % (db_table, f.column)
|
||||||
|
@ -95,7 +95,7 @@ class GeoSQLCompiler(compiler.SQLCompiler):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def get_default_columns(self, with_aliases=False, col_aliases=None,
|
def get_default_columns(self, with_aliases=False, col_aliases=None,
|
||||||
start_alias=None, opts=None, as_pairs=False):
|
start_alias=None, opts=None, as_pairs=False, local_only=False):
|
||||||
"""
|
"""
|
||||||
Computes the default columns for selecting every field in the base
|
Computes the default columns for selecting every field in the base
|
||||||
model. Will sometimes be called to pull in related models (e.g. via
|
model. Will sometimes be called to pull in related models (e.g. via
|
||||||
@ -121,6 +121,8 @@ class GeoSQLCompiler(compiler.SQLCompiler):
|
|||||||
if start_alias:
|
if start_alias:
|
||||||
seen = {None: start_alias}
|
seen = {None: start_alias}
|
||||||
for field, model in opts.get_fields_with_model():
|
for field, model in opts.get_fields_with_model():
|
||||||
|
if local_only and model is not None:
|
||||||
|
continue
|
||||||
if start_alias:
|
if start_alias:
|
||||||
try:
|
try:
|
||||||
alias = seen[model]
|
alias = seen[model]
|
||||||
|
@ -38,6 +38,11 @@ class Author(models.Model):
|
|||||||
name = models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
|
|
||||||
|
class Article(models.Model):
|
||||||
|
title = models.CharField(max_length=100)
|
||||||
|
author = models.ForeignKey(Author, unique=True)
|
||||||
|
objects = models.GeoManager()
|
||||||
|
|
||||||
class Book(models.Model):
|
class Book(models.Model):
|
||||||
title = models.CharField(max_length=100)
|
title = models.CharField(max_length=100)
|
||||||
author = models.ForeignKey(Author, related_name='books', null=True)
|
author = models.ForeignKey(Author, related_name='books', null=True)
|
||||||
|
@ -4,7 +4,7 @@ from django.contrib.gis.db.models import Collect, Count, Extent, F, Union
|
|||||||
from django.contrib.gis.geometry.backend import Geometry
|
from django.contrib.gis.geometry.backend import Geometry
|
||||||
from django.contrib.gis.tests.utils import mysql, oracle, postgis, spatialite, no_mysql, no_oracle, no_spatialite
|
from django.contrib.gis.tests.utils import mysql, oracle, postgis, spatialite, no_mysql, no_oracle, no_spatialite
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from models import City, Location, DirectoryEntry, Parcel, Book, Author
|
from models import City, Location, DirectoryEntry, Parcel, Book, Author, Article
|
||||||
|
|
||||||
cities = (('Aurora', 'TX', -97.516111, 33.058333),
|
cities = (('Aurora', 'TX', -97.516111, 33.058333),
|
||||||
('Roswell', 'NM', -104.528056, 33.387222),
|
('Roswell', 'NM', -104.528056, 33.387222),
|
||||||
@ -291,6 +291,14 @@ class RelatedGeoModelTest(unittest.TestCase):
|
|||||||
self.assertEqual(4, len(coll))
|
self.assertEqual(4, len(coll))
|
||||||
self.assertEqual(ref_geom, coll)
|
self.assertEqual(ref_geom, coll)
|
||||||
|
|
||||||
|
def test15_invalid_select_related(self):
|
||||||
|
"Testing doing select_related on the related name manager of a unique FK. See #13934."
|
||||||
|
qs = Article.objects.select_related('author__article')
|
||||||
|
# This triggers TypeError when `get_default_columns` has no `local_only`
|
||||||
|
# keyword. The TypeError is swallowed if QuerySet is actually
|
||||||
|
# evaluated as list generation swallows TypeError in CPython.
|
||||||
|
sql = str(qs.query)
|
||||||
|
|
||||||
# TODO: Related tests for KML, GML, and distance lookups.
|
# TODO: Related tests for KML, GML, and distance lookups.
|
||||||
|
|
||||||
def suite():
|
def suite():
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from optparse import make_option
|
from optparse import make_option
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import connections, transaction, models, DEFAULT_DB_ALIAS
|
from django.db import connections, router, transaction, models, DEFAULT_DB_ALIAS
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.core.management.base import NoArgsCommand, CommandError
|
from django.core.management.base import NoArgsCommand, CommandError
|
||||||
from django.core.management.color import no_style
|
from django.core.management.color import no_style
|
||||||
@ -66,7 +66,13 @@ The full error: %s""" % (connection.settings_dict['NAME'], e))
|
|||||||
# Emit the post sync signal. This allows individual
|
# Emit the post sync signal. This allows individual
|
||||||
# applications to respond as if the database had been
|
# applications to respond as if the database had been
|
||||||
# sync'd from scratch.
|
# sync'd from scratch.
|
||||||
emit_post_sync_signal(models.get_models(), verbosity, interactive, db)
|
all_models = [
|
||||||
|
(app.__name__.split('.')[-2],
|
||||||
|
[m for m in models.get_models(app, include_auto_created=True)
|
||||||
|
if router.allow_syncdb(db, m)])
|
||||||
|
for app in models.get_apps()
|
||||||
|
]
|
||||||
|
emit_post_sync_signal(all_models, verbosity, interactive, db)
|
||||||
|
|
||||||
# Reinstall the initial_data fixture.
|
# Reinstall the initial_data fixture.
|
||||||
kwargs = options.copy()
|
kwargs = options.copy()
|
||||||
|
@ -64,7 +64,7 @@ class DatabaseCreation(BaseDatabaseCreation):
|
|||||||
# a second index that specifies their operator class, which is
|
# a second index that specifies their operator class, which is
|
||||||
# needed when performing correct LIKE queries outside the
|
# needed when performing correct LIKE queries outside the
|
||||||
# C locale. See #12234.
|
# C locale. See #12234.
|
||||||
db_type = f.db_type()
|
db_type = f.db_type(connection=self.connection)
|
||||||
if db_type.startswith('varchar'):
|
if db_type.startswith('varchar'):
|
||||||
output.append(get_index_sql('%s_%s_like' % (db_table, f.column),
|
output.append(get_index_sql('%s_%s_like' % (db_table, f.column),
|
||||||
' varchar_pattern_ops'))
|
' varchar_pattern_ops'))
|
||||||
|
@ -56,7 +56,8 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|||||||
def last_insert_id(self, cursor, table_name, pk_name):
|
def last_insert_id(self, cursor, table_name, pk_name):
|
||||||
# Use pg_get_serial_sequence to get the underlying sequence name
|
# Use pg_get_serial_sequence to get the underlying sequence name
|
||||||
# from the table name and column name (available since PostgreSQL 8)
|
# from the table name and column name (available since PostgreSQL 8)
|
||||||
cursor.execute("SELECT CURRVAL(pg_get_serial_sequence('%s','%s'))" % (table_name, pk_name))
|
cursor.execute("SELECT CURRVAL(pg_get_serial_sequence('%s','%s'))" % (
|
||||||
|
self.quote_name(table_name), pk_name))
|
||||||
return cursor.fetchone()[0]
|
return cursor.fetchone()[0]
|
||||||
|
|
||||||
def no_limit_value(self):
|
def no_limit_value(self):
|
||||||
@ -98,7 +99,7 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|||||||
column_name = 'id'
|
column_name = 'id'
|
||||||
sql.append("%s setval(pg_get_serial_sequence('%s','%s'), 1, false);" % \
|
sql.append("%s setval(pg_get_serial_sequence('%s','%s'), 1, false);" % \
|
||||||
(style.SQL_KEYWORD('SELECT'),
|
(style.SQL_KEYWORD('SELECT'),
|
||||||
style.SQL_TABLE(table_name),
|
style.SQL_TABLE(self.quote_name(table_name)),
|
||||||
style.SQL_FIELD(column_name))
|
style.SQL_FIELD(column_name))
|
||||||
)
|
)
|
||||||
return sql
|
return sql
|
||||||
@ -120,7 +121,7 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|||||||
if isinstance(f, models.AutoField):
|
if isinstance(f, models.AutoField):
|
||||||
output.append("%s setval(pg_get_serial_sequence('%s','%s'), coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
|
output.append("%s setval(pg_get_serial_sequence('%s','%s'), coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
|
||||||
(style.SQL_KEYWORD('SELECT'),
|
(style.SQL_KEYWORD('SELECT'),
|
||||||
style.SQL_TABLE(model._meta.db_table),
|
style.SQL_TABLE(qn(model._meta.db_table)),
|
||||||
style.SQL_FIELD(f.column),
|
style.SQL_FIELD(f.column),
|
||||||
style.SQL_FIELD(qn(f.column)),
|
style.SQL_FIELD(qn(f.column)),
|
||||||
style.SQL_FIELD(qn(f.column)),
|
style.SQL_FIELD(qn(f.column)),
|
||||||
@ -132,7 +133,7 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|||||||
if not f.rel.through:
|
if not f.rel.through:
|
||||||
output.append("%s setval(pg_get_serial_sequence('%s','%s'), coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
|
output.append("%s setval(pg_get_serial_sequence('%s','%s'), coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
|
||||||
(style.SQL_KEYWORD('SELECT'),
|
(style.SQL_KEYWORD('SELECT'),
|
||||||
style.SQL_TABLE(model._meta.db_table),
|
style.SQL_TABLE(qn(f.m2m_db_table())),
|
||||||
style.SQL_FIELD('id'),
|
style.SQL_FIELD('id'),
|
||||||
style.SQL_FIELD(qn('id')),
|
style.SQL_FIELD(qn('id')),
|
||||||
style.SQL_FIELD(qn('id')),
|
style.SQL_FIELD(qn('id')),
|
||||||
|
@ -812,6 +812,9 @@ class ForeignKey(RelatedField, Field):
|
|||||||
to_field = to_field or (to._meta.pk and to._meta.pk.name)
|
to_field = to_field or (to._meta.pk and to._meta.pk.name)
|
||||||
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
|
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
|
||||||
|
|
||||||
|
if 'db_index' not in kwargs:
|
||||||
|
kwargs['db_index'] = True
|
||||||
|
|
||||||
kwargs['rel'] = rel_class(to, to_field,
|
kwargs['rel'] = rel_class(to, to_field,
|
||||||
related_name=kwargs.pop('related_name', None),
|
related_name=kwargs.pop('related_name', None),
|
||||||
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
||||||
@ -819,8 +822,6 @@ class ForeignKey(RelatedField, Field):
|
|||||||
parent_link=kwargs.pop('parent_link', False))
|
parent_link=kwargs.pop('parent_link', False))
|
||||||
Field.__init__(self, **kwargs)
|
Field.__init__(self, **kwargs)
|
||||||
|
|
||||||
self.db_index = True
|
|
||||||
|
|
||||||
def validate(self, value, model_instance):
|
def validate(self, value, model_instance):
|
||||||
if self.rel.parent_link:
|
if self.rel.parent_link:
|
||||||
return
|
return
|
||||||
|
@ -1090,10 +1090,7 @@ class Query(object):
|
|||||||
# exclude the "foo__in=[]" case from this handling, because
|
# exclude the "foo__in=[]" case from this handling, because
|
||||||
# it's short-circuited in the Where class.
|
# it's short-circuited in the Where class.
|
||||||
# We also need to handle the case where a subquery is provided
|
# We also need to handle the case where a subquery is provided
|
||||||
entry = self.where_class()
|
self.where.add((Constraint(alias, col, None), 'isnull', False), AND)
|
||||||
entry.add((Constraint(alias, col, None), 'isnull', True), AND)
|
|
||||||
entry.negate()
|
|
||||||
self.where.add(entry, AND)
|
|
||||||
|
|
||||||
if can_reuse is not None:
|
if can_reuse is not None:
|
||||||
can_reuse.update(join_list)
|
can_reuse.update(join_list)
|
||||||
|
@ -11,9 +11,10 @@ except ImportError:
|
|||||||
from django.template import Variable, Library
|
from django.template import Variable, Library
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils import formats
|
from django.utils import formats
|
||||||
from django.utils.translation import ugettext, ungettext
|
|
||||||
from django.utils.encoding import force_unicode, iri_to_uri
|
from django.utils.encoding import force_unicode, iri_to_uri
|
||||||
|
from django.utils.html import conditional_escape
|
||||||
from django.utils.safestring import mark_safe, SafeData
|
from django.utils.safestring import mark_safe, SafeData
|
||||||
|
from django.utils.translation import ugettext, ungettext
|
||||||
|
|
||||||
register = Library()
|
register = Library()
|
||||||
|
|
||||||
@ -496,10 +497,9 @@ def join(value, arg, autoescape=None):
|
|||||||
"""
|
"""
|
||||||
value = map(force_unicode, value)
|
value = map(force_unicode, value)
|
||||||
if autoescape:
|
if autoescape:
|
||||||
from django.utils.html import conditional_escape
|
|
||||||
value = [conditional_escape(v) for v in value]
|
value = [conditional_escape(v) for v in value]
|
||||||
try:
|
try:
|
||||||
data = arg.join(value)
|
data = conditional_escape(arg).join(value)
|
||||||
except AttributeError: # fail silently but nicely
|
except AttributeError: # fail silently but nicely
|
||||||
return value
|
return value
|
||||||
return mark_safe(data)
|
return mark_safe(data)
|
||||||
|
@ -12,17 +12,23 @@ PAPEROPT_a4 = -D latex_paper_size=a4
|
|||||||
PAPEROPT_letter = -D latex_paper_size=letter
|
PAPEROPT_letter = -D latex_paper_size=letter
|
||||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||||
|
|
||||||
.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
|
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "Please use \`make <target>' where <target> is one of"
|
@echo "Please use \`make <target>' where <target> is one of"
|
||||||
@echo " html to make standalone HTML files"
|
@echo " html to make standalone HTML files"
|
||||||
@echo " dirhtml to make HTML files named index.html in directories"
|
@echo " dirhtml to make HTML files named index.html in directories"
|
||||||
|
@echo " singlehtml to make a single large HTML file"
|
||||||
@echo " pickle to make pickle files"
|
@echo " pickle to make pickle files"
|
||||||
@echo " json to make JSON files"
|
@echo " json to make JSON files"
|
||||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||||
@echo " qthelp to make HTML files and a qthelp project"
|
@echo " qthelp to make HTML files and a qthelp project"
|
||||||
|
@echo " devhelp to make HTML files and a Devhelp project"
|
||||||
|
@echo " epub to make an epub"
|
||||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||||
|
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||||
|
@echo " text to make text files"
|
||||||
|
@echo " man to make manual pages"
|
||||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||||
@echo " linkcheck to check all external links for integrity"
|
@echo " linkcheck to check all external links for integrity"
|
||||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||||
@ -40,6 +46,11 @@ dirhtml:
|
|||||||
@echo
|
@echo
|
||||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||||
|
|
||||||
|
singlehtml:
|
||||||
|
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||||
|
|
||||||
pickle:
|
pickle:
|
||||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||||
@echo
|
@echo
|
||||||
@ -65,12 +76,42 @@ qthelp:
|
|||||||
@echo "To view the help file:"
|
@echo "To view the help file:"
|
||||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django.qhc"
|
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django.qhc"
|
||||||
|
|
||||||
|
devhelp:
|
||||||
|
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished."
|
||||||
|
@echo "To view the help file:"
|
||||||
|
@echo "# mkdir -p $$HOME/.local/share/devhelp/django"
|
||||||
|
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/django"
|
||||||
|
@echo "# devhelp"
|
||||||
|
|
||||||
|
epub:
|
||||||
|
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||||
|
|
||||||
latex:
|
latex:
|
||||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||||
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
|
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||||
"run these through (pdf)latex."
|
"(use \`make latexpdf' here to do that automatically)."
|
||||||
|
|
||||||
|
latexpdf:
|
||||||
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||||
|
@echo "Running LaTeX files through pdflatex..."
|
||||||
|
make -C $(BUILDDIR)/latex all-pdf
|
||||||
|
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||||
|
|
||||||
|
text:
|
||||||
|
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||||
|
|
||||||
|
man:
|
||||||
|
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||||
|
|
||||||
changes:
|
changes:
|
||||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"""
|
"""
|
||||||
Sphinx plugins for Django documentation.
|
Sphinx plugins for Django documentation.
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
|
|
||||||
import docutils.nodes
|
from docutils import nodes, transforms
|
||||||
import docutils.transforms
|
|
||||||
try:
|
try:
|
||||||
import json
|
import json
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -14,26 +14,12 @@ except ImportError:
|
|||||||
from django.utils import simplejson as json
|
from django.utils import simplejson as json
|
||||||
except ImportError:
|
except ImportError:
|
||||||
json = None
|
json = None
|
||||||
import os
|
|
||||||
import sphinx
|
from sphinx import addnodes, roles
|
||||||
import sphinx.addnodes
|
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||||
try:
|
from sphinx.writers.html import SmartyPantsHTMLTranslator
|
||||||
from sphinx import builders
|
|
||||||
except ImportError:
|
|
||||||
import sphinx.builder as builders
|
|
||||||
try:
|
|
||||||
import sphinx.builders.html as builders_html
|
|
||||||
except ImportError:
|
|
||||||
builders_html = builders
|
|
||||||
from sphinx.util.console import bold
|
from sphinx.util.console import bold
|
||||||
import sphinx.directives
|
|
||||||
import sphinx.environment
|
|
||||||
try:
|
|
||||||
import sphinx.writers.html as sphinx_htmlwriter
|
|
||||||
except ImportError:
|
|
||||||
import sphinx.htmlwriter as sphinx_htmlwriter
|
|
||||||
import sphinx.roles
|
|
||||||
from docutils import nodes
|
|
||||||
|
|
||||||
def setup(app):
|
def setup(app):
|
||||||
app.add_crossref_type(
|
app.add_crossref_type(
|
||||||
@ -74,21 +60,20 @@ def setup(app):
|
|||||||
app.add_transform(SuppressBlockquotes)
|
app.add_transform(SuppressBlockquotes)
|
||||||
app.add_builder(DjangoStandaloneHTMLBuilder)
|
app.add_builder(DjangoStandaloneHTMLBuilder)
|
||||||
|
|
||||||
# Monkeypatch PickleHTMLBuilder so that it doesn't die in Sphinx 0.4.2
|
|
||||||
if sphinx.__version__ == '0.4.2':
|
|
||||||
monkeypatch_pickle_builder()
|
|
||||||
|
|
||||||
def parse_version_directive(name, arguments, options, content, lineno,
|
def parse_version_directive(name, arguments, options, content, lineno,
|
||||||
content_offset, block_text, state, state_machine):
|
content_offset, block_text, state, state_machine):
|
||||||
env = state.document.settings.env
|
env = state.document.settings.env
|
||||||
is_nextversion = env.config.django_next_version == arguments[0]
|
is_nextversion = env.config.django_next_version == arguments[0]
|
||||||
ret = []
|
ret = []
|
||||||
node = sphinx.addnodes.versionmodified()
|
node = addnodes.versionmodified()
|
||||||
ret.append(node)
|
ret.append(node)
|
||||||
if not is_nextversion:
|
if not is_nextversion:
|
||||||
if len(arguments) == 1:
|
if len(arguments) == 1:
|
||||||
linktext = 'Please, see the release notes <releases-%s>' % (arguments[0])
|
linktext = 'Please, see the release notes <releases-%s>' % (arguments[0])
|
||||||
xrefs = sphinx.roles.xfileref_role('ref', linktext, linktext, lineno, state)
|
try:
|
||||||
|
xrefs = roles.XRefRole()('ref', linktext, linktext, lineno, state) # Sphinx >= 1.0
|
||||||
|
except:
|
||||||
|
xrefs = roles.xfileref_role('ref', linktext, linktext, lineno, state) # Sphinx < 1.0
|
||||||
node.extend(xrefs[0])
|
node.extend(xrefs[0])
|
||||||
node['version'] = arguments[0]
|
node['version'] = arguments[0]
|
||||||
else:
|
else:
|
||||||
@ -104,28 +89,28 @@ def parse_version_directive(name, arguments, options, content, lineno,
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class SuppressBlockquotes(docutils.transforms.Transform):
|
class SuppressBlockquotes(transforms.Transform):
|
||||||
"""
|
"""
|
||||||
Remove the default blockquotes that encase indented list, tables, etc.
|
Remove the default blockquotes that encase indented list, tables, etc.
|
||||||
"""
|
"""
|
||||||
default_priority = 300
|
default_priority = 300
|
||||||
|
|
||||||
suppress_blockquote_child_nodes = (
|
suppress_blockquote_child_nodes = (
|
||||||
docutils.nodes.bullet_list,
|
nodes.bullet_list,
|
||||||
docutils.nodes.enumerated_list,
|
nodes.enumerated_list,
|
||||||
docutils.nodes.definition_list,
|
nodes.definition_list,
|
||||||
docutils.nodes.literal_block,
|
nodes.literal_block,
|
||||||
docutils.nodes.doctest_block,
|
nodes.doctest_block,
|
||||||
docutils.nodes.line_block,
|
nodes.line_block,
|
||||||
docutils.nodes.table
|
nodes.table
|
||||||
)
|
)
|
||||||
|
|
||||||
def apply(self):
|
def apply(self):
|
||||||
for node in self.document.traverse(docutils.nodes.block_quote):
|
for node in self.document.traverse(nodes.block_quote):
|
||||||
if len(node.children) == 1 and isinstance(node.children[0], self.suppress_blockquote_child_nodes):
|
if len(node.children) == 1 and isinstance(node.children[0], self.suppress_blockquote_child_nodes):
|
||||||
node.replace_self(node.children[0])
|
node.replace_self(node.children[0])
|
||||||
|
|
||||||
class DjangoHTMLTranslator(sphinx_htmlwriter.SmartyPantsHTMLTranslator):
|
class DjangoHTMLTranslator(SmartyPantsHTMLTranslator):
|
||||||
"""
|
"""
|
||||||
Django-specific reST to HTML tweaks.
|
Django-specific reST to HTML tweaks.
|
||||||
"""
|
"""
|
||||||
@ -141,27 +126,26 @@ class DjangoHTMLTranslator(sphinx_htmlwriter.SmartyPantsHTMLTranslator):
|
|||||||
|
|
||||||
def depart_desc_parameterlist(self, node):
|
def depart_desc_parameterlist(self, node):
|
||||||
self.body.append(')')
|
self.body.append(')')
|
||||||
pass
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Don't apply smartypants to literal blocks
|
# Don't apply smartypants to literal blocks
|
||||||
#
|
#
|
||||||
def visit_literal_block(self, node):
|
def visit_literal_block(self, node):
|
||||||
self.no_smarty += 1
|
self.no_smarty += 1
|
||||||
sphinx_htmlwriter.SmartyPantsHTMLTranslator.visit_literal_block(self, node)
|
SmartyPantsHTMLTranslator.visit_literal_block(self, node)
|
||||||
|
|
||||||
def depart_literal_block(self, node):
|
def depart_literal_block(self, node):
|
||||||
sphinx_htmlwriter.SmartyPantsHTMLTranslator.depart_literal_block(self, node)
|
SmartyPantsHTMLTranslator.depart_literal_block(self, node)
|
||||||
self.no_smarty -= 1
|
self.no_smarty -= 1
|
||||||
|
|
||||||
#
|
#
|
||||||
# Turn the "new in version" stuff (versoinadded/versionchanged) into a
|
# Turn the "new in version" stuff (versionadded/versionchanged) into a
|
||||||
# better callout -- the Sphinx default is just a little span,
|
# better callout -- the Sphinx default is just a little span,
|
||||||
# which is a bit less obvious that I'd like.
|
# which is a bit less obvious that I'd like.
|
||||||
#
|
#
|
||||||
# FIXME: these messages are all hardcoded in English. We need to chanage
|
# FIXME: these messages are all hardcoded in English. We need to change
|
||||||
# that to accomodate other language docs, but I can't work out how to make
|
# that to accomodate other language docs, but I can't work out how to make
|
||||||
# that work and I think it'll require Sphinx 0.5 anyway.
|
# that work.
|
||||||
#
|
#
|
||||||
version_text = {
|
version_text = {
|
||||||
'deprecated': 'Deprecated in Django %s',
|
'deprecated': 'Deprecated in Django %s',
|
||||||
@ -183,36 +167,26 @@ class DjangoHTMLTranslator(sphinx_htmlwriter.SmartyPantsHTMLTranslator):
|
|||||||
self.body.append("</div>\n")
|
self.body.append("</div>\n")
|
||||||
|
|
||||||
# Give each section a unique ID -- nice for custom CSS hooks
|
# Give each section a unique ID -- nice for custom CSS hooks
|
||||||
# This is different on docutils 0.5 vs. 0.4...
|
|
||||||
|
|
||||||
if hasattr(sphinx_htmlwriter.SmartyPantsHTMLTranslator, 'start_tag_with_title') and sphinx.__version__ == '0.4.2':
|
|
||||||
def start_tag_with_title(self, node, tagname, **atts):
|
|
||||||
node = {
|
|
||||||
'classes': node.get('classes', []),
|
|
||||||
'ids': ['s-%s' % i for i in node.get('ids', [])]
|
|
||||||
}
|
|
||||||
return self.starttag(node, tagname, **atts)
|
|
||||||
|
|
||||||
else:
|
|
||||||
def visit_section(self, node):
|
def visit_section(self, node):
|
||||||
old_ids = node.get('ids', [])
|
old_ids = node.get('ids', [])
|
||||||
node['ids'] = ['s-' + i for i in old_ids]
|
node['ids'] = ['s-' + i for i in old_ids]
|
||||||
if sphinx.__version__ != '0.4.2':
|
|
||||||
node['ids'].extend(old_ids)
|
node['ids'].extend(old_ids)
|
||||||
sphinx_htmlwriter.SmartyPantsHTMLTranslator.visit_section(self, node)
|
SmartyPantsHTMLTranslator.visit_section(self, node)
|
||||||
node['ids'] = old_ids
|
node['ids'] = old_ids
|
||||||
|
|
||||||
def parse_django_admin_node(env, sig, signode):
|
def parse_django_admin_node(env, sig, signode):
|
||||||
command = sig.split(' ')[0]
|
command = sig.split(' ')[0]
|
||||||
env._django_curr_admin_command = command
|
env._django_curr_admin_command = command
|
||||||
title = "django-admin.py %s" % sig
|
title = "django-admin.py %s" % sig
|
||||||
signode += sphinx.addnodes.desc_name(title, title)
|
signode += addnodes.desc_name(title, title)
|
||||||
return sig
|
return sig
|
||||||
|
|
||||||
def parse_django_adminopt_node(env, sig, signode):
|
def parse_django_adminopt_node(env, sig, signode):
|
||||||
"""A copy of sphinx.directives.CmdoptionDesc.parse_signature()"""
|
"""A copy of sphinx.directives.CmdoptionDesc.parse_signature()"""
|
||||||
from sphinx import addnodes
|
try:
|
||||||
from sphinx.directives.desc import option_desc_re
|
from sphinx.domains.std import option_desc_re # Sphinx >= 1.0
|
||||||
|
except:
|
||||||
|
from sphinx.directives.desc import option_desc_re # Sphinx < 1.0
|
||||||
count = 0
|
count = 0
|
||||||
firstname = ''
|
firstname = ''
|
||||||
for m in option_desc_re.finditer(sig):
|
for m in option_desc_re.finditer(sig):
|
||||||
@ -228,44 +202,8 @@ def parse_django_adminopt_node(env, sig, signode):
|
|||||||
raise ValueError
|
raise ValueError
|
||||||
return firstname
|
return firstname
|
||||||
|
|
||||||
def monkeypatch_pickle_builder():
|
|
||||||
import shutil
|
|
||||||
from os import path
|
|
||||||
try:
|
|
||||||
import cPickle as pickle
|
|
||||||
except ImportError:
|
|
||||||
import pickle
|
|
||||||
|
|
||||||
def handle_finish(self):
|
class DjangoStandaloneHTMLBuilder(StandaloneHTMLBuilder):
|
||||||
# dump the global context
|
|
||||||
outfilename = path.join(self.outdir, 'globalcontext.pickle')
|
|
||||||
f = open(outfilename, 'wb')
|
|
||||||
try:
|
|
||||||
pickle.dump(self.globalcontext, f, 2)
|
|
||||||
finally:
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
self.info(bold('dumping search index...'))
|
|
||||||
self.indexer.prune(self.env.all_docs)
|
|
||||||
f = open(path.join(self.outdir, 'searchindex.pickle'), 'wb')
|
|
||||||
try:
|
|
||||||
self.indexer.dump(f, 'pickle')
|
|
||||||
finally:
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
# copy the environment file from the doctree dir to the output dir
|
|
||||||
# as needed by the web app
|
|
||||||
shutil.copyfile(path.join(self.doctreedir, builders.ENV_PICKLE_FILENAME),
|
|
||||||
path.join(self.outdir, builders.ENV_PICKLE_FILENAME))
|
|
||||||
|
|
||||||
# touch 'last build' file, used by the web application to determine
|
|
||||||
# when to reload its environment and clear the cache
|
|
||||||
open(path.join(self.outdir, builders.LAST_BUILD_FILENAME), 'w').close()
|
|
||||||
|
|
||||||
builders.PickleHTMLBuilder.handle_finish = handle_finish
|
|
||||||
|
|
||||||
|
|
||||||
class DjangoStandaloneHTMLBuilder(builders_html.StandaloneHTMLBuilder):
|
|
||||||
"""
|
"""
|
||||||
Subclass to add some extra things we need.
|
Subclass to add some extra things we need.
|
||||||
"""
|
"""
|
||||||
@ -278,9 +216,14 @@ class DjangoStandaloneHTMLBuilder(builders_html.StandaloneHTMLBuilder):
|
|||||||
self.warn("cannot create templatebuiltins.js due to missing simplejson dependency")
|
self.warn("cannot create templatebuiltins.js due to missing simplejson dependency")
|
||||||
return
|
return
|
||||||
self.info(bold("writing templatebuiltins.js..."))
|
self.info(bold("writing templatebuiltins.js..."))
|
||||||
|
try:
|
||||||
xrefs = self.env.reftargets.keys()
|
xrefs = self.env.reftargets.keys()
|
||||||
templatebuiltins = dict([('ttags', [n for (t,n) in xrefs if t == 'ttag']),
|
templatebuiltins = dict([('ttags', [n for (t,n) in xrefs if t == 'ttag']),
|
||||||
('tfilters', [n for (t,n) in xrefs if t == 'tfilter'])])
|
('tfilters', [n for (t,n) in xrefs if t == 'tfilter'])])
|
||||||
|
except AttributeError:
|
||||||
|
xrefs = self.env.domaindata["std"]["objects"]
|
||||||
|
templatebuiltins = dict([('ttags', [n for (t,n) in xrefs if t == 'templatetag']),
|
||||||
|
('tfilters', [n for (t,n) in xrefs if t == 'templatefilter'])])
|
||||||
outfilename = os.path.join(self.outdir, "templatebuiltins.js")
|
outfilename = os.path.join(self.outdir, "templatebuiltins.js")
|
||||||
f = open(outfilename, 'wb')
|
f = open(outfilename, 'wb')
|
||||||
f.write('var django_template_builtins = ')
|
f.write('var django_template_builtins = ')
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{% extends "!genindex.html" %}
|
{% extends "basic/genindex.html" %}
|
||||||
|
|
||||||
{% block bodyclass %}{% endblock %}
|
{% block bodyclass %}{% endblock %}
|
||||||
{% block sidebarwrapper %}{% endblock %}
|
{% block sidebarwrapper %}{% endblock %}
|
@ -1,4 +1,4 @@
|
|||||||
{% extends "!layout.html" %}
|
{% extends "basic/layout.html" %}
|
||||||
|
|
||||||
{%- macro secondnav() %}
|
{%- macro secondnav() %}
|
||||||
{%- if prev %}
|
{%- if prev %}
|
||||||
@ -61,7 +61,7 @@
|
|||||||
<a title="Home page" href="{{ pathto('index') }}">Home</a> {{ reldelim2 }}
|
<a title="Home page" href="{{ pathto('index') }}">Home</a> {{ reldelim2 }}
|
||||||
<a title="Table of contents" href="{{ pathto('contents') }}">Table of contents</a> {{ reldelim2 }}
|
<a title="Table of contents" href="{{ pathto('contents') }}">Table of contents</a> {{ reldelim2 }}
|
||||||
<a title="Global index" href="{{ pathto('genindex') }}">Index</a> {{ reldelim2 }}
|
<a title="Global index" href="{{ pathto('genindex') }}">Index</a> {{ reldelim2 }}
|
||||||
<a title="Module index" href="{{ pathto('modindex') }}">Modules</a>
|
<a title="Module index" href="{{ pathto('py-modindex') }}">Modules</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav">{{ secondnav() }}</div>
|
<div class="nav">{{ secondnav() }}</div>
|
||||||
</div>
|
</div>
|
@ -1,3 +1,3 @@
|
|||||||
{% extends "!modindex.html" %}
|
{% extends "basic/modindex.html" %}
|
||||||
{% block bodyclass %}{% endblock %}
|
{% block bodyclass %}{% endblock %}
|
||||||
{% block sidebarwrapper %}{% endblock %}
|
{% block sidebarwrapper %}{% endblock %}
|
@ -1,3 +1,3 @@
|
|||||||
{% extends "!search.html" %}
|
{% extends "basic/search.html" %}
|
||||||
{% block bodyclass %}{% endblock %}
|
{% block bodyclass %}{% endblock %}
|
||||||
{% block sidebarwrapper %}{% endblock %}
|
{% block sidebarwrapper %}{% endblock %}
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1013 B After Width: | Height: | Size: 1013 B |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
4
docs/_theme/djangodocs/theme.conf
vendored
Normal file
4
docs/_theme/djangodocs/theme.conf
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[theme]
|
||||||
|
inherit = basic
|
||||||
|
stylesheet = default.css
|
||||||
|
pygments_style = trac
|
174
docs/conf.py
174
docs/conf.py
@ -8,28 +8,35 @@
|
|||||||
# The contents of this file are pickled, so don't put values in the namespace
|
# The contents of this file are pickled, so don't put values in the namespace
|
||||||
# that aren't pickleable (module imports are okay, they're removed automatically).
|
# that aren't pickleable (module imports are okay, they're removed automatically).
|
||||||
#
|
#
|
||||||
# All configuration values have a default value; values that are commented out
|
# All configuration values have a default; values that are commented out
|
||||||
# serve to show the default value.
|
# serve to show the default.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
# If your extensions are in another directory, add it here.
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
sys.path.append(os.path.join(os.path.dirname(__file__), "_ext"))
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "_ext")))
|
||||||
|
|
||||||
# General configuration
|
# -- General configuration -----------------------------------------------------
|
||||||
# ---------------------
|
|
||||||
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
|
#needs_sphinx = '1.0'
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
extensions = ["djangodocs"]
|
extensions = ["djangodocs"]
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ["_templates"]
|
# templates_path = []
|
||||||
|
|
||||||
# The suffix of source filenames.
|
# The suffix of source filenames.
|
||||||
source_suffix = '.txt'
|
source_suffix = '.txt'
|
||||||
|
|
||||||
|
# The encoding of source files.
|
||||||
|
#source_encoding = 'utf-8-sig'
|
||||||
|
|
||||||
# The master toctree document.
|
# The master toctree document.
|
||||||
master_doc = 'contents'
|
master_doc = 'contents'
|
||||||
|
|
||||||
@ -37,8 +44,10 @@ master_doc = 'contents'
|
|||||||
project = 'Django'
|
project = 'Django'
|
||||||
copyright = 'Django Software Foundation and contributors'
|
copyright = 'Django Software Foundation and contributors'
|
||||||
|
|
||||||
# The default replacements for |version| and |release|, also used in various
|
|
||||||
# other places throughout the built documents.
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
|
# |version| and |release|, also used in various other places throughout the
|
||||||
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '1.2'
|
version = '1.2'
|
||||||
@ -47,14 +56,22 @@ release = version
|
|||||||
# The next version to be released
|
# The next version to be released
|
||||||
django_next_version = '1.3'
|
django_next_version = '1.3'
|
||||||
|
|
||||||
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
|
# for a list of supported languages.
|
||||||
|
#language = None
|
||||||
|
|
||||||
# There are two options for replacing |today|: either, you set today to some
|
# There are two options for replacing |today|: either, you set today to some
|
||||||
# non-false value, then it is used:
|
# non-false value, then it is used:
|
||||||
#today = ''
|
#today = ''
|
||||||
# Else, today_fmt is used as the format for a strftime call.
|
# Else, today_fmt is used as the format for a strftime call.
|
||||||
today_fmt = '%B %d, %Y'
|
today_fmt = '%B %d, %Y'
|
||||||
|
|
||||||
# List of documents that shouldn't be included in the build.
|
# List of patterns, relative to source directory, that match files and
|
||||||
#unused_docs = []
|
# directories to ignore when looking for source files.
|
||||||
|
exclude_patterns = ['_build']
|
||||||
|
|
||||||
|
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||||
|
#default_role = None
|
||||||
|
|
||||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||||
add_function_parentheses = True
|
add_function_parentheses = True
|
||||||
@ -75,13 +92,35 @@ pygments_style = 'trac'
|
|||||||
# Note: exclude_dirnames is new in Sphinx 0.5
|
# Note: exclude_dirnames is new in Sphinx 0.5
|
||||||
exclude_dirnames = ['.svn']
|
exclude_dirnames = ['.svn']
|
||||||
|
|
||||||
# Options for HTML output
|
# -- Options for HTML output ---------------------------------------------------
|
||||||
# -----------------------
|
|
||||||
|
|
||||||
# The style sheet to use for HTML and HTML Help pages. A file of that name
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# must exist either in Sphinx' static/ path, or in one of the custom paths
|
# a list of builtin themes.
|
||||||
# given in html_static_path.
|
html_theme = "djangodocs"
|
||||||
html_style = 'default.css'
|
|
||||||
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
|
# further. For a list of options available for each theme, see the
|
||||||
|
# documentation.
|
||||||
|
#html_theme_options = {}
|
||||||
|
|
||||||
|
# Add any paths that contain custom themes here, relative to this directory.
|
||||||
|
html_theme_path = ["_theme"]
|
||||||
|
|
||||||
|
# The name for this set of Sphinx documents. If None, it defaults to
|
||||||
|
# "<project> v<release> documentation".
|
||||||
|
#html_title = None
|
||||||
|
|
||||||
|
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||||
|
#html_short_title = None
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to place at the top
|
||||||
|
# of the sidebar.
|
||||||
|
#html_logo = None
|
||||||
|
|
||||||
|
# The name of an image file (within the static path) to use as favicon of the
|
||||||
|
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||||
|
# pixels large.
|
||||||
|
#html_favicon = None
|
||||||
|
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
@ -110,17 +149,38 @@ html_translator_class = "djangodocs.DjangoHTMLTranslator"
|
|||||||
html_additional_pages = {}
|
html_additional_pages = {}
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
#html_use_modindex = True
|
#html_domain_indices = True
|
||||||
|
|
||||||
# If true, the reST sources are included in the HTML build as _sources/<name>.
|
# If false, no index is generated.
|
||||||
html_copy_source = True
|
#html_use_index = True
|
||||||
|
|
||||||
|
# If true, the index is split into individual pages for each letter.
|
||||||
|
#html_split_index = False
|
||||||
|
|
||||||
|
# If true, links to the reST sources are added to the pages.
|
||||||
|
#html_show_sourcelink = True
|
||||||
|
|
||||||
|
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||||
|
#html_show_sphinx = True
|
||||||
|
|
||||||
|
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||||
|
#html_show_copyright = True
|
||||||
|
|
||||||
|
# If true, an OpenSearch description file will be output, and all pages will
|
||||||
|
# contain a <link> tag referring to it. The value of this option must be the
|
||||||
|
# base URL from which the finished HTML is served.
|
||||||
|
#html_use_opensearch = ''
|
||||||
|
|
||||||
|
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||||
|
#html_file_suffix = None
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
# Output file base name for HTML help builder.
|
||||||
htmlhelp_basename = 'Djangodoc'
|
htmlhelp_basename = 'Djangodoc'
|
||||||
|
|
||||||
|
modindex_common_prefix = ["django."]
|
||||||
|
|
||||||
# Options for LaTeX output
|
|
||||||
# ------------------------
|
# -- Options for LaTeX output --------------------------------------------------
|
||||||
|
|
||||||
# The paper size ('letter' or 'a4').
|
# The paper size ('letter' or 'a4').
|
||||||
#latex_paper_size = 'letter'
|
#latex_paper_size = 'letter'
|
||||||
@ -132,9 +192,24 @@ htmlhelp_basename = 'Djangodoc'
|
|||||||
# (source start file, target name, title, author, document class [howto/manual]).
|
# (source start file, target name, title, author, document class [howto/manual]).
|
||||||
#latex_documents = []
|
#latex_documents = []
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
('contents', 'django.tex', 'Django Documentation', 'Django Software Foundation', 'manual'),
|
('contents', 'django.tex', u'Django Documentation',
|
||||||
|
u'Django Software Foundation', 'manual'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
|
# the title page.
|
||||||
|
#latex_logo = None
|
||||||
|
|
||||||
|
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||||
|
# not chapters.
|
||||||
|
#latex_use_parts = False
|
||||||
|
|
||||||
|
# If true, show page references after internal links.
|
||||||
|
#latex_show_pagerefs = False
|
||||||
|
|
||||||
|
# If true, show URL addresses after external links.
|
||||||
|
#latex_show_urls = False
|
||||||
|
|
||||||
# Additional stuff for the LaTeX preamble.
|
# Additional stuff for the LaTeX preamble.
|
||||||
#latex_preamble = ''
|
#latex_preamble = ''
|
||||||
|
|
||||||
@ -142,10 +217,53 @@ latex_documents = [
|
|||||||
#latex_appendices = []
|
#latex_appendices = []
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
#latex_use_modindex = True
|
#latex_domain_indices = True
|
||||||
|
|
||||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
|
||||||
# not chapters.
|
|
||||||
# If this isn't set to True, the LaTex writer can only handle six levels of headers.
|
|
||||||
latex_use_parts = True
|
|
||||||
|
|
||||||
|
# -- Options for manual page output --------------------------------------------
|
||||||
|
|
||||||
|
# One entry per manual page. List of tuples
|
||||||
|
# (source start file, name, description, authors, manual section).
|
||||||
|
man_pages = [
|
||||||
|
('contents', 'django', 'Django Documentation', ['Django Software Foundation'], 1)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for Epub output ---------------------------------------------------
|
||||||
|
|
||||||
|
# Bibliographic Dublin Core info.
|
||||||
|
epub_title = u'Django'
|
||||||
|
epub_author = u'Django Software Foundation'
|
||||||
|
epub_publisher = u'Django Software Foundation'
|
||||||
|
epub_copyright = u'2010, Django Software Foundation'
|
||||||
|
|
||||||
|
# The language of the text. It defaults to the language option
|
||||||
|
# or en if the language is not set.
|
||||||
|
#epub_language = ''
|
||||||
|
|
||||||
|
# The scheme of the identifier. Typical schemes are ISBN or URL.
|
||||||
|
#epub_scheme = ''
|
||||||
|
|
||||||
|
# The unique identifier of the text. This can be a ISBN number
|
||||||
|
# or the project homepage.
|
||||||
|
#epub_identifier = ''
|
||||||
|
|
||||||
|
# A unique identification for the text.
|
||||||
|
#epub_uid = ''
|
||||||
|
|
||||||
|
# HTML files that should be inserted before the pages created by sphinx.
|
||||||
|
# The format is a list of tuples containing the path and title.
|
||||||
|
#epub_pre_files = []
|
||||||
|
|
||||||
|
# HTML files shat should be inserted after the pages created by sphinx.
|
||||||
|
# The format is a list of tuples containing the path and title.
|
||||||
|
#epub_post_files = []
|
||||||
|
|
||||||
|
# A list of files that should not be packed into the epub file.
|
||||||
|
#epub_exclude_files = []
|
||||||
|
|
||||||
|
# The depth of the table of contents in toc.ncx.
|
||||||
|
#epub_tocdepth = 3
|
||||||
|
|
||||||
|
# Allow duplicate toc entries.
|
||||||
|
#epub_tocdup = True
|
||||||
|
@ -15,6 +15,11 @@ __ http://docutils.sourceforge.net/
|
|||||||
To actually build the documentation locally, you'll currently need to install
|
To actually build the documentation locally, you'll currently need to install
|
||||||
Sphinx -- ``easy_install Sphinx`` should do the trick.
|
Sphinx -- ``easy_install Sphinx`` should do the trick.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Generation of the Django documentation will work with Sphinx version 0.6
|
||||||
|
or newer, but we recommend going straigh to Sphinx 1.0 or newer.
|
||||||
|
|
||||||
Then, building the html is easy; just ``make html`` from the ``docs`` directory.
|
Then, building the html is easy; just ``make html`` from the ``docs`` directory.
|
||||||
|
|
||||||
To get started contributing, you'll want to read the `ReStructuredText
|
To get started contributing, you'll want to read the `ReStructuredText
|
||||||
|
@ -1027,36 +1027,32 @@ The difference between these two is merely the template used to render them.
|
|||||||
The ``InlineModelAdmin`` class is a subclass of ``ModelAdmin`` so it inherits
|
The ``InlineModelAdmin`` class is a subclass of ``ModelAdmin`` so it inherits
|
||||||
all the same functionality as well as some of its own:
|
all the same functionality as well as some of its own:
|
||||||
|
|
||||||
``model``
|
.. attribute:: InlineModelAdmin.model
|
||||||
~~~~~~~~~
|
|
||||||
|
|
||||||
The model in which the inline is using. This is required.
|
The model in which the inline is using. This is required.
|
||||||
|
|
||||||
``fk_name``
|
.. attribute:: InlineModelAdmin.fk_name
|
||||||
~~~~~~~~~~~
|
|
||||||
|
|
||||||
The name of the foreign key on the model. In most cases this will be dealt
|
The name of the foreign key on the model. In most cases this will be dealt
|
||||||
with automatically, but ``fk_name`` must be specified explicitly if there are
|
with automatically, but ``fk_name`` must be specified explicitly if there
|
||||||
more than one foreign key to the same parent model.
|
are more than one foreign key to the same parent model.
|
||||||
|
|
||||||
``formset``
|
.. attribute:: InlineModelAdmin.formset
|
||||||
~~~~~~~~~~~
|
|
||||||
|
|
||||||
This defaults to ``BaseInlineFormSet``. Using your own formset can give you
|
This defaults to ``BaseInlineFormSet``. Using your own formset can give you
|
||||||
many possibilities of customization. Inlines are built around
|
many possibilities of customization. Inlines are built around
|
||||||
:ref:`model formsets <model-formsets>`.
|
:ref:`model formsets <model-formsets>`.
|
||||||
|
|
||||||
``form``
|
.. attribute:: InlineModelAdmin.form
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
The value for ``form`` defaults to ``ModelForm``. This is what is
|
The value for ``form`` defaults to ``ModelForm``. This is what is passed
|
||||||
passed through to ``inlineformset_factory`` when creating the formset for this
|
through to ``inlineformset_factory`` when creating the formset for this
|
||||||
inline.
|
inline.
|
||||||
|
|
||||||
.. _ref-contrib-admin-inline-extra:
|
.. _ref-contrib-admin-inline-extra:
|
||||||
|
|
||||||
``extra``
|
.. attribute:: InlineModelAdmin.extra
|
||||||
~~~~~~~~~
|
|
||||||
|
|
||||||
This controls the number of extra forms the formset will display in addition
|
This controls the number of extra forms the formset will display in addition
|
||||||
to the initial forms. See the
|
to the initial forms. See the
|
||||||
@ -1065,53 +1061,55 @@ to the initial forms. See the
|
|||||||
.. versionadded:: 1.2
|
.. versionadded:: 1.2
|
||||||
|
|
||||||
For users with JavaScript-enabled browsers, an "Add another" link is
|
For users with JavaScript-enabled browsers, an "Add another" link is
|
||||||
provided to enable any number of additional inlines to be added in
|
provided to enable any number of additional inlines to be added in addition
|
||||||
addition to those provided as a result of the ``extra`` argument.
|
to those provided as a result of the ``extra`` argument.
|
||||||
|
|
||||||
The dynamic link will not appear if the number of currently displayed
|
The dynamic link will not appear if the number of currently displayed forms
|
||||||
forms exceeds ``max_num``, or if the user does not have JavaScript
|
exceeds ``max_num``, or if the user does not have JavaScript enabled.
|
||||||
enabled.
|
|
||||||
|
|
||||||
.. _ref-contrib-admin-inline-max-num:
|
.. _ref-contrib-admin-inline-max-num:
|
||||||
|
|
||||||
``max_num``
|
.. attribute:: InlineModelAdmin.max_num
|
||||||
~~~~~~~~~~~
|
|
||||||
|
|
||||||
This controls the maximum number of forms to show in the inline. This doesn't
|
This controls the maximum number of forms to show in the inline. This
|
||||||
directly correlate to the number of objects, but can if the value is small
|
doesn't directly correlate to the number of objects, but can if the value
|
||||||
enough. See :ref:`model-formsets-max-num` for more information.
|
is small enough. See :ref:`model-formsets-max-num` for more information.
|
||||||
|
|
||||||
``raw_id_fields``
|
.. attribute:: InlineModelAdmin.raw_id_fields
|
||||||
~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
By default, Django's admin uses a select-box interface (<select>) for
|
By default, Django's admin uses a select-box interface (<select>) for
|
||||||
fields that are ``ForeignKey``. Sometimes you don't want to incur the
|
fields that are ``ForeignKey``. Sometimes you don't want to incur the
|
||||||
overhead of having to select all the related instances to display in the
|
overhead of having to select all the related instances to display in the
|
||||||
drop-down.
|
drop-down.
|
||||||
|
|
||||||
``raw_id_fields`` is a list of fields you would like to change
|
``raw_id_fields`` is a list of fields you would like to change into a
|
||||||
into a ``Input`` widget for either a ``ForeignKey`` or ``ManyToManyField``::
|
``Input`` widget for either a ``ForeignKey`` or ``ManyToManyField``::
|
||||||
|
|
||||||
class BookInline(admin.TabularInline):
|
class BookInline(admin.TabularInline):
|
||||||
model = Book
|
model = Book
|
||||||
raw_id_fields = ("pages",)
|
raw_id_fields = ("pages",)
|
||||||
|
|
||||||
``template``
|
|
||||||
~~~~~~~~~~~~
|
.. attribute:: InlineModelAdmin.template
|
||||||
|
|
||||||
The template used to render the inline on the page.
|
The template used to render the inline on the page.
|
||||||
|
|
||||||
``verbose_name``
|
.. attribute:: InlineModelAdmin.verbose_name
|
||||||
~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
An override to the ``verbose_name`` found in the model's inner ``Meta`` class.
|
An override to the ``verbose_name`` found in the model's inner ``Meta``
|
||||||
|
|
||||||
``verbose_name_plural``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
An override to the ``verbose_name_plural`` found in the model's inner ``Meta``
|
|
||||||
class.
|
class.
|
||||||
|
|
||||||
|
.. attribute:: InlineModelAdmin.verbose_name_plural
|
||||||
|
|
||||||
|
An override to the ``verbose_name_plural`` found in the model's inner
|
||||||
|
``Meta`` class.
|
||||||
|
|
||||||
|
.. attribute:: InlineModelAdmin.can_delete
|
||||||
|
|
||||||
|
Specifies whether or not inline objects can be deleted in the inline.
|
||||||
|
Defaults to ``True``.
|
||||||
|
|
||||||
|
|
||||||
Working with a model with two or more foreign keys to the same parent model
|
Working with a model with two or more foreign keys to the same parent model
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ special key that is used for errors that are tied to the entire model instead
|
|||||||
of to a specific field. You can access these errors with ``NON_FIELD_ERRORS``::
|
of to a specific field. You can access these errors with ``NON_FIELD_ERRORS``::
|
||||||
|
|
||||||
|
|
||||||
from django.core.validators import ValidationError, NON_FIELD_ERRORS
|
from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
|
||||||
try:
|
try:
|
||||||
article.full_clean()
|
article.full_clean()
|
||||||
except ValidationError, e:
|
except ValidationError, e:
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from django.contrib.contenttypes import generic
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db import connection, DEFAULT_DB_ALIAS
|
from django.db import connection, DEFAULT_DB_ALIAS
|
||||||
@ -37,6 +39,21 @@ if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != 'django.db.backends.mysql':
|
|||||||
m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz = models.ManyToManyField(Person,blank=True)
|
m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz = models.ManyToManyField(Person,blank=True)
|
||||||
|
|
||||||
|
|
||||||
|
class Tag(models.Model):
|
||||||
|
name = models.CharField(max_length=30)
|
||||||
|
content_type = models.ForeignKey(ContentType, related_name='backend_tags')
|
||||||
|
object_id = models.PositiveIntegerField()
|
||||||
|
content_object = generic.GenericForeignKey('content_type', 'object_id')
|
||||||
|
|
||||||
|
|
||||||
|
class Post(models.Model):
|
||||||
|
name = models.CharField(max_length=30)
|
||||||
|
text = models.TextField()
|
||||||
|
tags = generic.GenericRelation('Tag')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'CaseSensitive_Post'
|
||||||
|
|
||||||
qn = connection.ops.quote_name
|
qn = connection.ops.quote_name
|
||||||
|
|
||||||
__test__ = {'API_TESTS': """
|
__test__ = {'API_TESTS': """
|
||||||
|
@ -6,7 +6,7 @@ import unittest
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core import management
|
from django.core import management
|
||||||
from django.core.management.color import no_style
|
from django.core.management.color import no_style
|
||||||
from django.db import backend, connection, DEFAULT_DB_ALIAS
|
from django.db import backend, connection, connections, DEFAULT_DB_ALIAS
|
||||||
from django.db.backends.signals import connection_created
|
from django.db.backends.signals import connection_created
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
@ -137,6 +137,23 @@ if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != 'django.db.backends.mysql':
|
|||||||
for statement in connection.ops.sql_flush(no_style(), tables, sequences):
|
for statement in connection.ops.sql_flush(no_style(), tables, sequences):
|
||||||
cursor.execute(statement)
|
cursor.execute(statement)
|
||||||
|
|
||||||
|
class SequenceResetTest(TestCase):
|
||||||
|
def test_generic_relation(self):
|
||||||
|
"Sequence names are correct when resetting generic relations (Ref #13941)"
|
||||||
|
# Create an object with a manually specified PK
|
||||||
|
models.Post.objects.create(id=10, name='1st post', text='hello world')
|
||||||
|
|
||||||
|
# Reset the sequences for the database
|
||||||
|
cursor = connection.cursor()
|
||||||
|
commands = connections[DEFAULT_DB_ALIAS].ops.sequence_reset_sql(no_style(), [models.Post])
|
||||||
|
for sql in commands:
|
||||||
|
cursor.execute(sql)
|
||||||
|
|
||||||
|
# If we create a new object now, it should have a PK greater
|
||||||
|
# than the PK we specified manually.
|
||||||
|
obj = models.Post.objects.create(name='New post', text='goodbye world')
|
||||||
|
self.assertTrue(obj.pk > 10)
|
||||||
|
|
||||||
|
|
||||||
def connection_created_test(sender, **kwargs):
|
def connection_created_test(sender, **kwargs):
|
||||||
print 'connection_created signal'
|
print 'connection_created signal'
|
||||||
|
@ -328,6 +328,11 @@ def get_filter_tests():
|
|||||||
'join03': (r'{{ a|join:" & " }}', {'a': ['alpha', 'beta & me']}, 'alpha & beta & me'),
|
'join03': (r'{{ a|join:" & " }}', {'a': ['alpha', 'beta & me']}, 'alpha & beta & me'),
|
||||||
'join04': (r'{% autoescape off %}{{ a|join:" & " }}{% endautoescape %}', {'a': ['alpha', 'beta & me']}, 'alpha & beta & me'),
|
'join04': (r'{% autoescape off %}{{ a|join:" & " }}{% endautoescape %}', {'a': ['alpha', 'beta & me']}, 'alpha & beta & me'),
|
||||||
|
|
||||||
|
# Test that joining with unsafe joiners don't result in unsafe strings (#11377)
|
||||||
|
'join05': (r'{{ a|join:var }}', {'a': ['alpha', 'beta & me'], 'var': ' & '}, 'alpha & beta & me'),
|
||||||
|
'join06': (r'{{ a|join:var }}', {'a': ['alpha', 'beta & me'], 'var': mark_safe(' & ')}, 'alpha & beta & me'),
|
||||||
|
'join07': (r'{{ a|join:var|lower }}', {'a': ['Alpha', 'Beta & me'], 'var': ' & ' }, 'alpha & beta & me'),
|
||||||
|
'join08': (r'{{ a|join:var|lower }}', {'a': ['Alpha', 'Beta & me'], 'var': mark_safe(' & ')}, 'alpha & beta & me'),
|
||||||
|
|
||||||
'date01': (r'{{ d|date:"m" }}', {'d': datetime(2008, 1, 1)}, '01'),
|
'date01': (r'{{ d|date:"m" }}', {'d': datetime(2008, 1, 1)}, '01'),
|
||||||
'date02': (r'{{ d|date }}', {'d': datetime(2008, 1, 1)}, 'Jan. 1, 2008'),
|
'date02': (r'{{ d|date }}', {'d': datetime(2008, 1, 1)}, 'Jan. 1, 2008'),
|
||||||
|
@ -506,6 +506,17 @@ class Templates(unittest.TestCase):
|
|||||||
'basic-syntax28': ("{{ a.b }}", {'a': SilentGetItemClass()}, ('', 'INVALID')),
|
'basic-syntax28': ("{{ a.b }}", {'a': SilentGetItemClass()}, ('', 'INVALID')),
|
||||||
'basic-syntax29': ("{{ a.b }}", {'a': SilentAttrClass()}, ('', 'INVALID')),
|
'basic-syntax29': ("{{ a.b }}", {'a': SilentAttrClass()}, ('', 'INVALID')),
|
||||||
|
|
||||||
|
# Something that starts like a number but has an extra lookup works as a lookup.
|
||||||
|
'basic-syntax30': ("{{ 1.2.3 }}", {"1": {"2": {"3": "d"}}}, "d"),
|
||||||
|
'basic-syntax31': ("{{ 1.2.3 }}", {"1": {"2": ("a", "b", "c", "d")}}, "d"),
|
||||||
|
'basic-syntax32': ("{{ 1.2.3 }}", {"1": (("x", "x", "x", "x"), ("y", "y", "y", "y"), ("a", "b", "c", "d"))}, "d"),
|
||||||
|
'basic-syntax33': ("{{ 1.2.3 }}", {"1": ("xxxx", "yyyy", "abcd")}, "d"),
|
||||||
|
'basic-syntax34': ("{{ 1.2.3 }}", {"1": ({"x": "x"}, {"y": "y"}, {"z": "z", "3": "d"})}, "d"),
|
||||||
|
|
||||||
|
# Numbers are numbers even if their digits are in the context.
|
||||||
|
'basic-syntax35': ("{{ 1 }}", {"1": "abc"}, "1"),
|
||||||
|
'basic-syntax36': ("{{ 1.2 }}", {"1": "abc"}, "1.2"),
|
||||||
|
|
||||||
# List-index syntax allows a template to access a certain item of a subscriptable object.
|
# List-index syntax allows a template to access a certain item of a subscriptable object.
|
||||||
'list-index01': ("{{ var.1 }}", {"var": ["first item", "second item"]}, "second item"),
|
'list-index01': ("{{ var.1 }}", {"var": ["first item", "second item"]}, "second item"),
|
||||||
|
|
||||||
@ -1286,6 +1297,7 @@ class Templates(unittest.TestCase):
|
|||||||
# Regression test for #11270.
|
# Regression test for #11270.
|
||||||
'cache17': ('{% load cache %}{% cache 10 long_cache_key poem %}Some Content{% endcache %}', {'poem': 'Oh freddled gruntbuggly/Thy micturations are to me/As plurdled gabbleblotchits/On a lurgid bee/That mordiously hath bitled out/Its earted jurtles/Into a rancid festering/Or else I shall rend thee in the gobberwarts with my blurglecruncheon/See if I dont.'}, 'Some Content'),
|
'cache17': ('{% load cache %}{% cache 10 long_cache_key poem %}Some Content{% endcache %}', {'poem': 'Oh freddled gruntbuggly/Thy micturations are to me/As plurdled gabbleblotchits/On a lurgid bee/That mordiously hath bitled out/Its earted jurtles/Into a rancid festering/Or else I shall rend thee in the gobberwarts with my blurglecruncheon/See if I dont.'}, 'Some Content'),
|
||||||
|
|
||||||
|
|
||||||
### AUTOESCAPE TAG ##############################################
|
### AUTOESCAPE TAG ##############################################
|
||||||
'autoescape-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"),
|
'autoescape-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"),
|
||||||
'autoescape-tag02': ("{% autoescape off %}{{ first }}{% endautoescape %}", {"first": "<b>hello</b>"}, "<b>hello</b>"),
|
'autoescape-tag02': ("{% autoescape off %}{{ first }}{% endautoescape %}", {"first": "<b>hello</b>"}, "<b>hello</b>"),
|
||||||
@ -1314,6 +1326,23 @@ class Templates(unittest.TestCase):
|
|||||||
# implementation details (fortunately, the (no)autoescape block
|
# implementation details (fortunately, the (no)autoescape block
|
||||||
# tags can be used in those cases)
|
# tags can be used in those cases)
|
||||||
'autoescape-filtertag01': ("{{ first }}{% filter safe %}{{ first }} x<y{% endfilter %}", {"first": "<a>"}, template.TemplateSyntaxError),
|
'autoescape-filtertag01': ("{{ first }}{% filter safe %}{{ first }} x<y{% endfilter %}", {"first": "<a>"}, template.TemplateSyntaxError),
|
||||||
|
|
||||||
|
# ifqeual compares unescaped vales.
|
||||||
|
'autoescape-ifequal01': ('{% ifequal var "this & that" %}yes{% endifequal %}', { "var": "this & that" }, "yes" ),
|
||||||
|
|
||||||
|
# Arguments to filters are 'safe' and manipulate their input unescaped.
|
||||||
|
'autoescape-filters01': ('{{ var|cut:"&" }}', { "var": "this & that" }, "this that" ),
|
||||||
|
'autoescape-filters02': ('{{ var|join:" & \" }}', { "var": ("Tom", "Dick", "Harry") }, "Tom & Dick & Harry" ),
|
||||||
|
|
||||||
|
# Literal strings are safe.
|
||||||
|
'autoescape-literals01': ('{{ "this & that" }}',{}, "this & that" ),
|
||||||
|
|
||||||
|
# Iterating over strings outputs safe characters.
|
||||||
|
'autoescape-stringiterations01': ('{% for l in var %}{{ l }},{% endfor %}', {'var': 'K&R'}, "K,&,R," ),
|
||||||
|
|
||||||
|
# Escape requirement survives lookup.
|
||||||
|
'autoescape-lookup01': ('{{ var.key }}', { "var": {"key": "this & that" }}, "this & that" ),
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user