mirror of
https://github.com/django/django.git
synced 2025-07-05 10:19:20 +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
|
||||
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
|
||||
db_table = model._meta.db_table
|
||||
idx_name = '%s_%s_id' % (db_table, f.column)
|
||||
|
@ -95,7 +95,7 @@ class GeoSQLCompiler(compiler.SQLCompiler):
|
||||
return result
|
||||
|
||||
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
|
||||
model. Will sometimes be called to pull in related models (e.g. via
|
||||
@ -121,6 +121,8 @@ class GeoSQLCompiler(compiler.SQLCompiler):
|
||||
if start_alias:
|
||||
seen = {None: start_alias}
|
||||
for field, model in opts.get_fields_with_model():
|
||||
if local_only and model is not None:
|
||||
continue
|
||||
if start_alias:
|
||||
try:
|
||||
alias = seen[model]
|
||||
|
@ -38,6 +38,11 @@ class Author(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
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):
|
||||
title = models.CharField(max_length=100)
|
||||
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.tests.utils import mysql, oracle, postgis, spatialite, no_mysql, no_oracle, no_spatialite
|
||||
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),
|
||||
('Roswell', 'NM', -104.528056, 33.387222),
|
||||
@ -291,6 +291,14 @@ class RelatedGeoModelTest(unittest.TestCase):
|
||||
self.assertEqual(4, len(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.
|
||||
|
||||
def suite():
|
||||
|
@ -1,7 +1,7 @@
|
||||
from optparse import make_option
|
||||
|
||||
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.base import NoArgsCommand, CommandError
|
||||
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
|
||||
# applications to respond as if the database had been
|
||||
# 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.
|
||||
kwargs = options.copy()
|
||||
|
@ -64,7 +64,7 @@ class DatabaseCreation(BaseDatabaseCreation):
|
||||
# a second index that specifies their operator class, which is
|
||||
# needed when performing correct LIKE queries outside the
|
||||
# C locale. See #12234.
|
||||
db_type = f.db_type()
|
||||
db_type = f.db_type(connection=self.connection)
|
||||
if db_type.startswith('varchar'):
|
||||
output.append(get_index_sql('%s_%s_like' % (db_table, f.column),
|
||||
' varchar_pattern_ops'))
|
||||
|
@ -56,7 +56,8 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||
def last_insert_id(self, cursor, table_name, pk_name):
|
||||
# Use pg_get_serial_sequence to get the underlying sequence name
|
||||
# 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]
|
||||
|
||||
def no_limit_value(self):
|
||||
@ -98,7 +99,7 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||
column_name = 'id'
|
||||
sql.append("%s setval(pg_get_serial_sequence('%s','%s'), 1, false);" % \
|
||||
(style.SQL_KEYWORD('SELECT'),
|
||||
style.SQL_TABLE(table_name),
|
||||
style.SQL_TABLE(self.quote_name(table_name)),
|
||||
style.SQL_FIELD(column_name))
|
||||
)
|
||||
return sql
|
||||
@ -120,7 +121,7 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||
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;" % \
|
||||
(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(qn(f.column)),
|
||||
style.SQL_FIELD(qn(f.column)),
|
||||
@ -132,7 +133,7 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||
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;" % \
|
||||
(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(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)
|
||||
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,
|
||||
related_name=kwargs.pop('related_name', 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))
|
||||
Field.__init__(self, **kwargs)
|
||||
|
||||
self.db_index = True
|
||||
|
||||
def validate(self, value, model_instance):
|
||||
if self.rel.parent_link:
|
||||
return
|
||||
|
@ -1090,10 +1090,7 @@ class Query(object):
|
||||
# exclude the "foo__in=[]" case from this handling, because
|
||||
# it's short-circuited in the Where class.
|
||||
# We also need to handle the case where a subquery is provided
|
||||
entry = self.where_class()
|
||||
entry.add((Constraint(alias, col, None), 'isnull', True), AND)
|
||||
entry.negate()
|
||||
self.where.add(entry, AND)
|
||||
self.where.add((Constraint(alias, col, None), 'isnull', False), AND)
|
||||
|
||||
if can_reuse is not None:
|
||||
can_reuse.update(join_list)
|
||||
|
@ -11,9 +11,10 @@ except ImportError:
|
||||
from django.template import Variable, Library
|
||||
from django.conf import settings
|
||||
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.html import conditional_escape
|
||||
from django.utils.safestring import mark_safe, SafeData
|
||||
from django.utils.translation import ugettext, ungettext
|
||||
|
||||
register = Library()
|
||||
|
||||
@ -496,10 +497,9 @@ def join(value, arg, autoescape=None):
|
||||
"""
|
||||
value = map(force_unicode, value)
|
||||
if autoescape:
|
||||
from django.utils.html import conditional_escape
|
||||
value = [conditional_escape(v) for v in value]
|
||||
try:
|
||||
data = arg.join(value)
|
||||
data = conditional_escape(arg).join(value)
|
||||
except AttributeError: # fail silently but nicely
|
||||
return value
|
||||
return mark_safe(data)
|
||||
|
@ -12,20 +12,26 @@ PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
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:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@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)"
|
||||
@echo " html to make standalone HTML files"
|
||||
@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 " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help 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 " 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:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
@ -40,6 +46,11 @@ dirhtml:
|
||||
@echo
|
||||
@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:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@ -65,12 +76,42 @@ qthelp:
|
||||
@echo "To view the help file:"
|
||||
@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:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
|
||||
"run these through (pdf)latex."
|
||||
@echo "Run \`make' in that directory to 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:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
|
@ -1,9 +1,9 @@
|
||||
"""
|
||||
Sphinx plugins for Django documentation.
|
||||
"""
|
||||
import os
|
||||
|
||||
import docutils.nodes
|
||||
import docutils.transforms
|
||||
from docutils import nodes, transforms
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
@ -14,26 +14,12 @@ except ImportError:
|
||||
from django.utils import simplejson as json
|
||||
except ImportError:
|
||||
json = None
|
||||
import os
|
||||
import sphinx
|
||||
import sphinx.addnodes
|
||||
try:
|
||||
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 import addnodes, roles
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||
from sphinx.writers.html import SmartyPantsHTMLTranslator
|
||||
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):
|
||||
app.add_crossref_type(
|
||||
@ -74,21 +60,20 @@ def setup(app):
|
||||
app.add_transform(SuppressBlockquotes)
|
||||
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,
|
||||
content_offset, block_text, state, state_machine):
|
||||
env = state.document.settings.env
|
||||
is_nextversion = env.config.django_next_version == arguments[0]
|
||||
ret = []
|
||||
node = sphinx.addnodes.versionmodified()
|
||||
node = addnodes.versionmodified()
|
||||
ret.append(node)
|
||||
if not is_nextversion:
|
||||
if len(arguments) == 1:
|
||||
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['version'] = arguments[0]
|
||||
else:
|
||||
@ -103,29 +88,29 @@ def parse_version_directive(name, arguments, options, content, lineno,
|
||||
env.note_versionchange(node['type'], node['version'], node, lineno)
|
||||
return ret
|
||||
|
||||
|
||||
class SuppressBlockquotes(docutils.transforms.Transform):
|
||||
|
||||
class SuppressBlockquotes(transforms.Transform):
|
||||
"""
|
||||
Remove the default blockquotes that encase indented list, tables, etc.
|
||||
"""
|
||||
default_priority = 300
|
||||
|
||||
|
||||
suppress_blockquote_child_nodes = (
|
||||
docutils.nodes.bullet_list,
|
||||
docutils.nodes.enumerated_list,
|
||||
docutils.nodes.definition_list,
|
||||
docutils.nodes.literal_block,
|
||||
docutils.nodes.doctest_block,
|
||||
docutils.nodes.line_block,
|
||||
docutils.nodes.table
|
||||
nodes.bullet_list,
|
||||
nodes.enumerated_list,
|
||||
nodes.definition_list,
|
||||
nodes.literal_block,
|
||||
nodes.doctest_block,
|
||||
nodes.line_block,
|
||||
nodes.table
|
||||
)
|
||||
|
||||
|
||||
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):
|
||||
node.replace_self(node.children[0])
|
||||
|
||||
class DjangoHTMLTranslator(sphinx_htmlwriter.SmartyPantsHTMLTranslator):
|
||||
class DjangoHTMLTranslator(SmartyPantsHTMLTranslator):
|
||||
"""
|
||||
Django-specific reST to HTML tweaks.
|
||||
"""
|
||||
@ -133,42 +118,41 @@ class DjangoHTMLTranslator(sphinx_htmlwriter.SmartyPantsHTMLTranslator):
|
||||
# Don't use border=1, which docutils does by default.
|
||||
def visit_table(self, node):
|
||||
self.body.append(self.starttag(node, 'table', CLASS='docutils'))
|
||||
|
||||
|
||||
# <big>? Really?
|
||||
def visit_desc_parameterlist(self, node):
|
||||
self.body.append('(')
|
||||
self.first_param = 1
|
||||
|
||||
|
||||
def depart_desc_parameterlist(self, node):
|
||||
self.body.append(')')
|
||||
pass
|
||||
|
||||
|
||||
#
|
||||
# Don't apply smartypants to literal blocks
|
||||
#
|
||||
def visit_literal_block(self, node):
|
||||
self.no_smarty += 1
|
||||
sphinx_htmlwriter.SmartyPantsHTMLTranslator.visit_literal_block(self, node)
|
||||
SmartyPantsHTMLTranslator.visit_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
|
||||
|
||||
|
||||
#
|
||||
# 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,
|
||||
# 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 work and I think it'll require Sphinx 0.5 anyway.
|
||||
# that work.
|
||||
#
|
||||
version_text = {
|
||||
'deprecated': 'Deprecated in Django %s',
|
||||
'versionchanged': 'Changed in Django %s',
|
||||
'versionadded': 'New in Django %s',
|
||||
}
|
||||
|
||||
|
||||
def visit_versionmodified(self, node):
|
||||
self.body.append(
|
||||
self.starttag(node, 'div', CLASS=node['type'])
|
||||
@ -178,41 +162,31 @@ class DjangoHTMLTranslator(sphinx_htmlwriter.SmartyPantsHTMLTranslator):
|
||||
len(node) and ":" or "."
|
||||
)
|
||||
self.body.append('<span class="title">%s</span> ' % title)
|
||||
|
||||
|
||||
def depart_versionmodified(self, node):
|
||||
self.body.append("</div>\n")
|
||||
|
||||
|
||||
# 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):
|
||||
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 visit_section(self, node):
|
||||
old_ids = node.get('ids', [])
|
||||
node['ids'] = ['s-' + i for i in old_ids]
|
||||
node['ids'].extend(old_ids)
|
||||
SmartyPantsHTMLTranslator.visit_section(self, node)
|
||||
node['ids'] = old_ids
|
||||
|
||||
def parse_django_admin_node(env, sig, signode):
|
||||
command = sig.split(' ')[0]
|
||||
env._django_curr_admin_command = command
|
||||
title = "django-admin.py %s" % sig
|
||||
signode += sphinx.addnodes.desc_name(title, title)
|
||||
signode += addnodes.desc_name(title, title)
|
||||
return sig
|
||||
|
||||
def parse_django_adminopt_node(env, sig, signode):
|
||||
"""A copy of sphinx.directives.CmdoptionDesc.parse_signature()"""
|
||||
from sphinx import addnodes
|
||||
from sphinx.directives.desc import option_desc_re
|
||||
try:
|
||||
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
|
||||
firstname = ''
|
||||
for m in option_desc_re.finditer(sig):
|
||||
@ -228,44 +202,8 @@ def parse_django_adminopt_node(env, sig, signode):
|
||||
raise ValueError
|
||||
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):
|
||||
# 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):
|
||||
class DjangoStandaloneHTMLBuilder(StandaloneHTMLBuilder):
|
||||
"""
|
||||
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")
|
||||
return
|
||||
self.info(bold("writing templatebuiltins.js..."))
|
||||
xrefs = self.env.reftargets.keys()
|
||||
templatebuiltins = dict([('ttags', [n for (t,n) in xrefs if t == 'ttag']),
|
||||
('tfilters', [n for (t,n) in xrefs if t == 'tfilter'])])
|
||||
try:
|
||||
xrefs = self.env.reftargets.keys()
|
||||
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")
|
||||
f = open(outfilename, 'wb')
|
||||
f.write('var django_template_builtins = ')
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% extends "!genindex.html" %}
|
||||
{% extends "basic/genindex.html" %}
|
||||
|
||||
{% block bodyclass %}{% endblock %}
|
||||
{% block sidebarwrapper %}{% endblock %}
|
@ -1,4 +1,4 @@
|
||||
{% extends "!layout.html" %}
|
||||
{% extends "basic/layout.html" %}
|
||||
|
||||
{%- macro secondnav() %}
|
||||
{%- if prev %}
|
||||
@ -61,7 +61,7 @@
|
||||
<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="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 class="nav">{{ secondnav() }}</div>
|
||||
</div>
|
@ -1,3 +1,3 @@
|
||||
{% extends "!modindex.html" %}
|
||||
{% extends "basic/modindex.html" %}
|
||||
{% block bodyclass %}{% endblock %}
|
||||
{% block sidebarwrapper %}{% endblock %}
|
@ -1,3 +1,3 @@
|
||||
{% extends "!search.html" %}
|
||||
{% extends "basic/search.html" %}
|
||||
{% block bodyclass %}{% 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
|
||||
# that aren't pickleable (module imports are okay, they're removed automatically).
|
||||
#
|
||||
# All configuration values have a default value; values that are commented out
|
||||
# serve to show the default value.
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# If your extensions are in another directory, add it here.
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), "_ext"))
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# 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
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ["djangodocs"]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ["_templates"]
|
||||
# templates_path = []
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.txt'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'contents'
|
||||
|
||||
@ -37,8 +44,10 @@ master_doc = 'contents'
|
||||
project = 'Django'
|
||||
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.
|
||||
version = '1.2'
|
||||
@ -47,14 +56,22 @@ release = version
|
||||
# The next version to be released
|
||||
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
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of documents that shouldn't be included in the build.
|
||||
#unused_docs = []
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# 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.
|
||||
add_function_parentheses = True
|
||||
@ -75,13 +92,35 @@ pygments_style = 'trac'
|
||||
# Note: exclude_dirnames is new in Sphinx 0.5
|
||||
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
|
||||
# must exist either in Sphinx' static/ path, or in one of the custom paths
|
||||
# given in html_static_path.
|
||||
html_style = 'default.css'
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = "djangodocs"
|
||||
|
||||
# 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,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
@ -110,17 +149,38 @@ html_translator_class = "djangodocs.DjangoHTMLTranslator"
|
||||
html_additional_pages = {}
|
||||
|
||||
# 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>.
|
||||
html_copy_source = True
|
||||
# If false, no index is generated.
|
||||
#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.
|
||||
htmlhelp_basename = 'Djangodoc'
|
||||
|
||||
modindex_common_prefix = ["django."]
|
||||
|
||||
# Options for LaTeX output
|
||||
# ------------------------
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
# The paper size ('letter' or 'a4').
|
||||
#latex_paper_size = 'letter'
|
||||
@ -132,9 +192,24 @@ htmlhelp_basename = 'Djangodoc'
|
||||
# (source start file, target name, title, author, document class [howto/manual]).
|
||||
#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.
|
||||
#latex_preamble = ''
|
||||
|
||||
@ -142,10 +217,53 @@ latex_documents = [
|
||||
#latex_appendices = []
|
||||
|
||||
# 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
|
||||
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.
|
||||
|
||||
To get started contributing, you'll want to read the `ReStructuredText
|
||||
|
@ -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
|
||||
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
|
||||
with automatically, but ``fk_name`` must be specified explicitly if there are
|
||||
more than one foreign key to the same parent model.
|
||||
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 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
|
||||
many possibilities of customization. Inlines are built around
|
||||
:ref:`model formsets <model-formsets>`.
|
||||
This defaults to ``BaseInlineFormSet``. Using your own formset can give you
|
||||
many possibilities of customization. Inlines are built around
|
||||
:ref:`model formsets <model-formsets>`.
|
||||
|
||||
``form``
|
||||
~~~~~~~~
|
||||
.. attribute:: InlineModelAdmin.form
|
||||
|
||||
The value for ``form`` defaults to ``ModelForm``. This is what is
|
||||
passed through to ``inlineformset_factory`` when creating the formset for this
|
||||
inline.
|
||||
The value for ``form`` defaults to ``ModelForm``. This is what is passed
|
||||
through to ``inlineformset_factory`` when creating the formset for this
|
||||
inline.
|
||||
|
||||
.. _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
|
||||
provided to enable any number of additional inlines to be added in
|
||||
addition to those provided as a result of the ``extra`` argument.
|
||||
.. versionadded:: 1.2
|
||||
|
||||
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.
|
||||
For users with JavaScript-enabled browsers, an "Add another" link is
|
||||
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 forms
|
||||
exceeds ``max_num``, or if the user does not have JavaScript enabled.
|
||||
|
||||
.. _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
|
||||
directly correlate to the number of objects, but can if the value is small
|
||||
enough. See :ref:`model-formsets-max-num` for more information.
|
||||
This controls the maximum number of forms to show in the inline. This
|
||||
doesn't directly correlate to the number of objects, but can if the value
|
||||
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
|
||||
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
|
||||
drop-down.
|
||||
By default, Django's admin uses a select-box interface (<select>) for
|
||||
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
|
||||
drop-down.
|
||||
|
||||
``raw_id_fields`` is a list of fields you would like to change
|
||||
into a ``Input`` widget for either a ``ForeignKey`` or ``ManyToManyField``::
|
||||
``raw_id_fields`` is a list of fields you would like to change into a
|
||||
``Input`` widget for either a ``ForeignKey`` or ``ManyToManyField``::
|
||||
|
||||
class BookInline(admin.TabularInline):
|
||||
model = Book
|
||||
raw_id_fields = ("pages",)
|
||||
class BookInline(admin.TabularInline):
|
||||
model = Book
|
||||
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
|
||||
---------------------------------------------------------------------------
|
||||
|
@ -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``::
|
||||
|
||||
|
||||
from django.core.validators import ValidationError, NON_FIELD_ERRORS
|
||||
from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
|
||||
try:
|
||||
article.full_clean()
|
||||
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.db import models
|
||||
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)
|
||||
|
||||
|
||||
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
|
||||
|
||||
__test__ = {'API_TESTS': """
|
||||
|
@ -6,7 +6,7 @@ import unittest
|
||||
from django.conf import settings
|
||||
from django.core import management
|
||||
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.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):
|
||||
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):
|
||||
print 'connection_created signal'
|
||||
|
@ -328,7 +328,12 @@ def get_filter_tests():
|
||||
'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'),
|
||||
|
||||
|
||||
# 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'),
|
||||
'date02': (r'{{ d|date }}', {'d': datetime(2008, 1, 1)}, 'Jan. 1, 2008'),
|
||||
#Ticket 9520: Make sure |date doesn't blow up on non-dates
|
||||
|
@ -506,6 +506,17 @@ class Templates(unittest.TestCase):
|
||||
'basic-syntax28': ("{{ a.b }}", {'a': SilentGetItemClass()}, ('', '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-index01': ("{{ var.1 }}", {"var": ["first item", "second item"]}, "second item"),
|
||||
|
||||
@ -592,7 +603,7 @@ class Templates(unittest.TestCase):
|
||||
|
||||
#filters should accept empty string constants
|
||||
'filter-syntax20': ('{{ ""|default_if_none:"was none" }}', {}, ""),
|
||||
|
||||
|
||||
### COMMENT SYNTAX ########################################################
|
||||
'comment-syntax01': ("{# this is hidden #}hello", {}, "hello"),
|
||||
'comment-syntax02': ("{# this is hidden #}hello{# foo #}", {}, "hello"),
|
||||
@ -1285,7 +1296,8 @@ class Templates(unittest.TestCase):
|
||||
|
||||
# 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'),
|
||||
|
||||
|
||||
|
||||
### AUTOESCAPE TAG ##############################################
|
||||
'autoescape-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"),
|
||||
'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
|
||||
# tags can be used in those cases)
|
||||
'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