1
0
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:
Paul McMillan 2010-08-04 18:47:42 +00:00
parent 9315b44ad1
commit 5875c4e01c
32 changed files with 437 additions and 240 deletions

View File

@ -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)

View File

@ -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]

View File

@ -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)

View File

@ -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():

View File

@ -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()

View File

@ -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'))

View File

@ -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')),

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -12,20 +12,26 @@ 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 " pickle to make pickle files" @echo " singlehtml to make a single large HTML file"
@echo " json to make JSON files" @echo " pickle to make pickle files"
@echo " htmlhelp to make HTML files and a HTML help project" @echo " json to make JSON files"
@echo " qthelp to make HTML files and a qthelp project" @echo " htmlhelp to make HTML files and a HTML help project"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " qthelp to make HTML files and a qthelp project"
@echo " changes to make an overview of all changed/added/deprecated items" @echo " devhelp to make HTML files and a Devhelp project"
@echo " linkcheck to check all external links for integrity" @echo " epub to make an epub"
@echo " doctest to run all doctests embedded in the documentation (if enabled)" @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 " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean: clean:
-rm -rf $(BUILDDIR)/* -rm -rf $(BUILDDIR)/*
@ -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

View File

@ -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... def visit_section(self, node):
old_ids = node.get('ids', [])
if hasattr(sphinx_htmlwriter.SmartyPantsHTMLTranslator, 'start_tag_with_title') and sphinx.__version__ == '0.4.2': node['ids'] = ['s-' + i for i in old_ids]
def start_tag_with_title(self, node, tagname, **atts): node['ids'].extend(old_ids)
node = { SmartyPantsHTMLTranslator.visit_section(self, node)
'classes': node.get('classes', []), node['ids'] = old_ids
'ids': ['s-%s' % i for i in node.get('ids', [])]
}
return self.starttag(node, tagname, **atts)
else:
def visit_section(self, node):
old_ids = node.get('ids', [])
node['ids'] = ['s-' + i for i in old_ids]
if sphinx.__version__ != '0.4.2':
node['ids'].extend(old_ids)
sphinx_htmlwriter.SmartyPantsHTMLTranslator.visit_section(self, node)
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..."))
xrefs = self.env.reftargets.keys() try:
templatebuiltins = dict([('ttags', [n for (t,n) in xrefs if t == 'ttag']), xrefs = self.env.reftargets.keys()
('tfilters', [n for (t,n) in xrefs if t == 'tfilter'])]) templatebuiltins = dict([('ttags', [n for (t,n) in xrefs if t == 'ttag']),
('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 = ')

View File

@ -1,4 +1,4 @@
{% extends "!genindex.html" %} {% extends "basic/genindex.html" %}
{% block bodyclass %}{% endblock %} {% block bodyclass %}{% endblock %}
{% block sidebarwrapper %}{% endblock %} {% block sidebarwrapper %}{% endblock %}

View File

@ -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>

View File

@ -1,3 +1,3 @@
{% extends "!modindex.html" %} {% extends "basic/modindex.html" %}
{% block bodyclass %}{% endblock %} {% block bodyclass %}{% endblock %}
{% block sidebarwrapper %}{% endblock %} {% block sidebarwrapper %}{% endblock %}

View File

@ -1,3 +1,3 @@
{% extends "!search.html" %} {% extends "basic/search.html" %}
{% block bodyclass %}{% endblock %} {% block bodyclass %}{% endblock %}
{% block sidebarwrapper %}{% endblock %} {% block sidebarwrapper %}{% endblock %}

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1013 B

After

Width:  |  Height:  |  Size: 1013 B

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

4
docs/_theme/djangodocs/theme.conf vendored Normal file
View File

@ -0,0 +1,4 @@
[theme]
inherit = basic
stylesheet = default.css
pygments_style = trac

View File

@ -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

View File

@ -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

View File

@ -1027,90 +1027,88 @@ 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
to the initial forms. See the
:ref:`formsets documentation <topics-forms-formsets>` for more information.
.. versionadded:: 1.2 This controls the number of extra forms the formset will display in addition
to the initial forms. See the
:ref:`formsets documentation <topics-forms-formsets>` for more information.
For users with JavaScript-enabled browsers, an "Add another" link is .. versionadded:: 1.2
provided to enable any number of additional inlines to be added in
addition to those provided as a result of the ``extra`` argument.
The dynamic link will not appear if the number of currently displayed For users with JavaScript-enabled browsers, an "Add another" link is
forms exceeds ``max_num``, or if the user does not have JavaScript provided to enable any number of additional inlines to be added in addition
enabled. to those provided as a result of the ``extra`` argument.
The dynamic link will not appear if the number of currently displayed forms
exceeds ``max_num``, or if the user does not have JavaScript 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``
~~~~~~~~~~~~
The template used to render the inline on the page. .. attribute:: InlineModelAdmin.template
``verbose_name`` The template used to render the inline on the page.
~~~~~~~~~~~~~~~~
An override to the ``verbose_name`` found in the model's inner ``Meta`` class. .. attribute:: InlineModelAdmin.verbose_name
``verbose_name_plural`` An override to the ``verbose_name`` found in the model's inner ``Meta``
~~~~~~~~~~~~~~~~~~~~~~~ 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``.
An override to the ``verbose_name_plural`` found in the model's inner ``Meta``
class.
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
--------------------------------------------------------------------------- ---------------------------------------------------------------------------

View File

@ -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:

View File

@ -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': """

View File

@ -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'

View File

@ -328,6 +328,11 @@ def get_filter_tests():
'join03': (r'{{ a|join:" &amp; " }}', {'a': ['alpha', 'beta & me']}, 'alpha &amp; beta &amp; me'), 'join03': (r'{{ a|join:" &amp; " }}', {'a': ['alpha', 'beta & me']}, 'alpha &amp; beta &amp; me'),
'join04': (r'{% autoescape off %}{{ a|join:" &amp; " }}{% endautoescape %}', {'a': ['alpha', 'beta & me']}, 'alpha &amp; beta & me'), 'join04': (r'{% autoescape off %}{{ a|join:" &amp; " }}{% endautoescape %}', {'a': ['alpha', 'beta & me']}, 'alpha &amp; 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 &amp; beta &amp; me'),
'join06': (r'{{ a|join:var }}', {'a': ['alpha', 'beta & me'], 'var': mark_safe(' & ')}, 'alpha & beta &amp; me'),
'join07': (r'{{ a|join:var|lower }}', {'a': ['Alpha', 'Beta & me'], 'var': ' & ' }, 'alpha &amp; beta &amp; me'),
'join08': (r'{{ a|join:var|lower }}', {'a': ['Alpha', 'Beta & me'], 'var': mark_safe(' & ')}, 'alpha & beta &amp; 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'),

View File

@ -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,&amp;,R," ),
# Escape requirement survives lookup.
'autoescape-lookup01': ('{{ var.key }}', { "var": {"key": "this & that" }}, "this &amp; that" ),
} }