mirror of
https://github.com/django/django.git
synced 2025-10-24 06:06:09 +00:00
i18n: merged up to r868
git-svn-id: http://code.djangoproject.com/svn/django/branches/i18n@869 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
244
docs/design_philosophies.txt
Normal file
244
docs/design_philosophies.txt
Normal file
@@ -0,0 +1,244 @@
|
||||
===================
|
||||
Design philosophies
|
||||
===================
|
||||
|
||||
This document explains some of the fundamental philosophies Django's developers
|
||||
have used in creating the framework. Its goal is to explain the past and guide
|
||||
the future.
|
||||
|
||||
Overall
|
||||
=======
|
||||
|
||||
Loose coupling
|
||||
--------------
|
||||
|
||||
A fundamental goal of Django's stack is `loose coupling and tight cohesion`_.
|
||||
The various layers of the framework shouldn't "know" about each other unless
|
||||
absolutely necessary.
|
||||
|
||||
For example, the template system knows nothing about Web requests, the database
|
||||
layer knows nothing about data display and the view system doesn't care which
|
||||
template system a programmer uses.
|
||||
|
||||
.. _`loose coupling and tight cohesion`: http://c2.com/cgi/wiki?CouplingAndCohesion
|
||||
|
||||
Less code
|
||||
---------
|
||||
|
||||
Django apps should use as little code as possible; they should lack boilerplate.
|
||||
Django should take full advantage of Python's dynamic capabilities, such as
|
||||
introspection.
|
||||
|
||||
Quick development
|
||||
-----------------
|
||||
|
||||
The point of a Web framework in the 21st century is to make the tedious aspects
|
||||
of Web development fast. Django should allow for incredibly quick Web
|
||||
development.
|
||||
|
||||
Don't repeat yourself (DRY)
|
||||
---------------------------
|
||||
|
||||
Every distinct concept and/or piece of data should live in one, and only one,
|
||||
place. Redundancy is bad. Normalization is good.
|
||||
|
||||
The framework, within reason, should deduce as much as possible from as little
|
||||
as possible.
|
||||
|
||||
Explicit is better than implicit
|
||||
--------------------------------
|
||||
|
||||
This, a `core Python principle`_, means Django shouldn't do too much "magic."
|
||||
Magic shouldn't happen unless there's a really good reason for it.
|
||||
|
||||
.. _`core Python principle`: http://www.python.org/doc/Humor.html#zen
|
||||
|
||||
Consistency
|
||||
-----------
|
||||
|
||||
The framework should be consistent at all levels. Consistency applies to
|
||||
everything from low-level (the Python coding style used) to high-level (the
|
||||
"experience" of using Django).
|
||||
|
||||
Models
|
||||
======
|
||||
|
||||
Explicit is better than implicit
|
||||
--------------------------------
|
||||
|
||||
Fields shouldn't assume certain behaviors based solely on the name of the
|
||||
field. This requires too much knowledge of the system and is prone to errors.
|
||||
Instead, behaviors should be based on keyword arguments and, in some cases, on
|
||||
the type of the field.
|
||||
|
||||
Include all relevant domain logic
|
||||
---------------------------------
|
||||
|
||||
Models should encapsulate every aspect of an "object," following Martin
|
||||
Fowler's `Active Record`_ design pattern.
|
||||
|
||||
This is why model-specific admin options are included in the model itself; data
|
||||
related to a model should be stored *in* the model.
|
||||
|
||||
.. _`Active Record`: http://www.martinfowler.com/eaaCatalog/activeRecord.html
|
||||
|
||||
Database API
|
||||
============
|
||||
|
||||
The core goals of the database API are:
|
||||
|
||||
SQL efficiency
|
||||
--------------
|
||||
|
||||
It should execute SQL statements as few times as possible, and it should
|
||||
optimize statements internally.
|
||||
|
||||
This is why developers need to call ``save()`` explicitly, rather than the
|
||||
framework saving things behind the scenes silently.
|
||||
|
||||
This is also why the ``select_related`` argument exists. It's an optional
|
||||
performance booster for the common case of selecting "every related object."
|
||||
|
||||
Terse, powerful syntax
|
||||
----------------------
|
||||
|
||||
The database API should allow rich, expressive statements in as little syntax
|
||||
as possible. It should not rely on importing other modules or helper objects.
|
||||
|
||||
Joins should be performed automatically, behind the scenes, when necessary.
|
||||
|
||||
Every object should be able to access every related object, systemwide. This
|
||||
access should work both ways.
|
||||
|
||||
Option to drop into raw SQL easily, when needed
|
||||
-----------------------------------------------
|
||||
|
||||
The database API should realize it's a shortcut but not necessarily an
|
||||
end-all-be-all. The framework should make it easy to write custom SQL -- entire
|
||||
statements, or just custom ``WHERE`` clauses as custom parameters to API calls.
|
||||
|
||||
URL design
|
||||
==========
|
||||
|
||||
Loose coupling
|
||||
--------------
|
||||
|
||||
URLs in a Django app should not be coupled to the underlying Python code. Tying
|
||||
URLs to Python function names is a Bad And Ugly Thing.
|
||||
|
||||
Along these lines, the Django URL system should allow URLs for the same app to
|
||||
be different in different contexts. For example, one site may put stories at
|
||||
``/stories/``, while another may use ``/news/``.
|
||||
|
||||
Infinite flexibility
|
||||
--------------------
|
||||
|
||||
URLs should be as flexible as possible. Any conceivable URL design should be
|
||||
allowed.
|
||||
|
||||
Encourage best practices
|
||||
------------------------
|
||||
|
||||
The framework should make it just as easy (or even easier) for a developer to
|
||||
design pretty URLs than ugly ones.
|
||||
|
||||
File extensions in Web-page URLs should be avoided.
|
||||
|
||||
Definitive URLs
|
||||
---------------
|
||||
|
||||
Technically, ``foo.com/bar`` and ``foo.com/bar/`` are two different URLs, and
|
||||
search-engine robots (and some Web traffic-analyzing tools) would treat them as
|
||||
separate pages. Django should make an effort to "normalize" URLs so that
|
||||
search-engine robots don't get confused.
|
||||
|
||||
This is the reasoning behind the ``APPEND_SLASH`` setting.
|
||||
|
||||
Template system
|
||||
===============
|
||||
|
||||
Separate logic from presentation
|
||||
--------------------------------
|
||||
|
||||
We see a template system as a tool that controls presentation and
|
||||
presentation-related logic -- and that's it. The template system shouldn't
|
||||
support functionality that goes beyond this basic goal.
|
||||
|
||||
If we wanted to put everything in templates, we'd be using PHP. Been there,
|
||||
done that, wised up.
|
||||
|
||||
Discourage redundancy
|
||||
---------------------
|
||||
|
||||
The majority of dynamic Web sites use some sort of common sitewide design --
|
||||
a common header, footer, navigation bar, etc. The Django template system should
|
||||
make it easy to store those elements in a single place, eliminating duplicate
|
||||
code.
|
||||
|
||||
This is the philosophy behind template inheritance.
|
||||
|
||||
Be decoupled from HTML
|
||||
----------------------
|
||||
|
||||
The template system shouldn't be designed so that it only outputs HTML. It
|
||||
should be equally good at generating other text-based formats, or just plain
|
||||
text.
|
||||
|
||||
Assume designer competence
|
||||
--------------------------
|
||||
|
||||
The template system shouldn't be designed so that templates necessarily are
|
||||
displayed nicely in WYSIWYG editors such as Dreamweaver. That is too severe of
|
||||
a limitation and wouldn't allow the syntax to be as nice as it is. Django
|
||||
expects template authors are comfortable editing HTML directly.
|
||||
|
||||
Treat whitespace obviously
|
||||
--------------------------
|
||||
|
||||
The template system shouldn't do magic things with whitespace. If a template
|
||||
includes whitespace, the system should treat the whitespace as it treats text
|
||||
-- just display it.
|
||||
|
||||
Don't invent a programming language
|
||||
-----------------------------------
|
||||
|
||||
The template system intentionally doesn't allow the following:
|
||||
|
||||
* Assignment to variables
|
||||
* Advanced logic
|
||||
|
||||
The goal is not to invent a programming language. The goal is to offer just
|
||||
enough programming-esque functionality, such as branching and looping, that is
|
||||
essential for making presentation-related decisions.
|
||||
|
||||
Extensibility
|
||||
-------------
|
||||
|
||||
The template system should recognize that advanced template authors may want
|
||||
to extend its technology.
|
||||
|
||||
This is the philosophy behind custom template tags and filters.
|
||||
|
||||
Views
|
||||
=====
|
||||
|
||||
Simplicity
|
||||
----------
|
||||
|
||||
Writing a view should be as simple as writing a Python function. Developers
|
||||
shouldn't have to instantiate a class when a function will do.
|
||||
|
||||
Use request objects
|
||||
-------------------
|
||||
|
||||
Views should have access to a request object -- an object that stores metadata
|
||||
about the current request. The object should be passed directly to a view
|
||||
function, rather than the view function having to access the request data from
|
||||
a global variable. This makes it light, clean and easy to test views by passing
|
||||
in "fake" request objects.
|
||||
|
||||
Loose coupling
|
||||
--------------
|
||||
|
||||
A view shouldn't care about which template system the developer uses -- or even
|
||||
whether a template system is used at all.
|
||||
@@ -65,9 +65,8 @@ Using the ``AddManipulator``
|
||||
We'll start with the ``AddManipulator``. Here's a very simple view that takes
|
||||
POSTed data from the browser and creates a new ``Place`` object::
|
||||
|
||||
from django.core import template_loader
|
||||
from django.core.exceptions import Http404
|
||||
from django.core.extensions import DjangoContext as Context
|
||||
from django.core.extensions import render_to_response
|
||||
from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect
|
||||
from django.models.places import places
|
||||
from django.core import formfields
|
||||
@@ -112,13 +111,7 @@ view with a form that submits to this flawed creation view::
|
||||
# Create a FormWrapper object that the template can use. Ignore
|
||||
# the last two arguments to FormWrapper for now.
|
||||
form = formfields.FormWrapper(places.AddManipulator(), {}, {})
|
||||
|
||||
# Create a template, context and response.
|
||||
t = template_loader.get_template('places/naive_create_form')
|
||||
c = Context(request, {
|
||||
'form': form
|
||||
})
|
||||
return HttpResponse(t.render(c))
|
||||
return render_to_response('places/naive_create_form', {'form': form})
|
||||
|
||||
(This view, as well as all the following ones, has the same imports as in the
|
||||
first example above.)
|
||||
@@ -169,11 +162,7 @@ creation view that takes validation into account::
|
||||
# Check for validation errors
|
||||
errors = manipulator.get_validation_errors(new_data)
|
||||
if errors:
|
||||
t = template_loader.get_template('places/errors')
|
||||
c = Context(request, {
|
||||
'errors': errors
|
||||
}
|
||||
return HttpResponse(t.render(c))
|
||||
return render_to_response('places/errors', {'errors': errors})
|
||||
else:
|
||||
manipulator.do_html2python(request.POST)
|
||||
new_place = manipulator.save(request.POST)
|
||||
@@ -245,11 +234,7 @@ Below is the finished view::
|
||||
|
||||
# Create the FormWrapper, template, context, response.
|
||||
form = formfields.FormWrapper(manipulator, new_data, errors)
|
||||
t = template_loader.get_template("places/create_form")
|
||||
c = Context(request, {
|
||||
'form': form,
|
||||
})
|
||||
return HttpResponse(t.render(c))
|
||||
return render_to_response('places/create_form', {'form': form})
|
||||
|
||||
and here's the ``create_form`` template::
|
||||
|
||||
@@ -338,12 +323,7 @@ about editing an existing one? It's shockingly similar to creating a new one::
|
||||
new_data = place.__dict__
|
||||
|
||||
form = formfields.FormWrapper(manipulator, new_data, errors)
|
||||
t = template_loader.get_template("places/edit_form")
|
||||
c = Context(request, {
|
||||
'form': form,
|
||||
'place': place,
|
||||
})
|
||||
return HttpResponse(t.render(c))
|
||||
return render_to_response('places/edit_form', {'form': form, 'place': place})
|
||||
|
||||
The only real differences are:
|
||||
|
||||
@@ -422,11 +402,7 @@ Here's a simple function that might drive the above form::
|
||||
else:
|
||||
errors = new_data = {}
|
||||
form = formfields.FormWrapper(manipulator, new_data, errors)
|
||||
t = template_loader.get_template("contact_form")
|
||||
c = Context(request, {
|
||||
'form': form,
|
||||
})
|
||||
return HttpResponse(t.render(c))
|
||||
return render_to_response('contact_form', {'form': form})
|
||||
|
||||
Validators
|
||||
==========
|
||||
|
||||
@@ -136,9 +136,7 @@ Here's a typical usage example::
|
||||
else:
|
||||
return HttpResponse("Please enable cookies and try again.")
|
||||
request.session.set_test_cookie()
|
||||
t = template_loader.get_template("foo/login_form")
|
||||
c = Context(request)
|
||||
return HttpResponse(t.render(c))
|
||||
return render_to_response('foo/login_form')
|
||||
|
||||
Using sessions out of views
|
||||
===========================
|
||||
|
||||
@@ -376,9 +376,9 @@ Built-in tag reference
|
||||
========================== ================================================
|
||||
``forloop.counter`` The current iteration of the loop (1-indexed)
|
||||
``forloop.counter0`` The current iteration of the loop (0-indexed)
|
||||
``forloop.revcounter`` The number of iterations from the end of the
|
||||
``forloop.revcounter`` The number of iterations from the end of the
|
||||
loop (1-indexed)
|
||||
``forloop.revcounter0`` The number of iterations from the end of the
|
||||
``forloop.revcounter0`` The number of iterations from the end of the
|
||||
loop (0-indexed)
|
||||
``forloop.first`` True if this is the first time through the loop
|
||||
``forloop.last`` True if this is the last time through the loop
|
||||
@@ -569,25 +569,28 @@ Built-in filter reference
|
||||
-------------------------
|
||||
|
||||
``add``
|
||||
Adds the arg to the value
|
||||
Adds the arg to the value.
|
||||
|
||||
``addslashes``
|
||||
Adds slashes - useful for passing strings to JavaScript, for example.
|
||||
Adds slashes. Useful for passing strings to JavaScript, for example.
|
||||
|
||||
``capfirst``
|
||||
Capitalizes the first character of the value
|
||||
Capitalizes the first character of the value.
|
||||
|
||||
``center``
|
||||
Centers the value in a field of a given width
|
||||
Centers the value in a field of a given width.
|
||||
|
||||
``cut``
|
||||
Removes all values of arg from the given string
|
||||
Removes all values of arg from the given string.
|
||||
|
||||
``date``
|
||||
Formats a date according to the given format (same as the ``now`` tag)
|
||||
Formats a date according to the given format (same as the ``now`` tag).
|
||||
|
||||
``default``
|
||||
If value is unavailable, use given default
|
||||
If value is unavailable, use given default.
|
||||
|
||||
``default_if_none``
|
||||
If value is ``None``, use given default.
|
||||
|
||||
``dictsort``
|
||||
Takes a list of dicts, returns that list sorted by the property given in the
|
||||
@@ -598,24 +601,24 @@ Built-in filter reference
|
||||
given in the argument.
|
||||
|
||||
``divisibleby``
|
||||
Returns true if the value is divisible by the argument
|
||||
Returns true if the value is divisible by the argument.
|
||||
|
||||
``escape``
|
||||
Escapes a string's HTML
|
||||
Escapes a string's HTML.
|
||||
|
||||
``filesizeformat``
|
||||
Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102
|
||||
bytes, etc).
|
||||
|
||||
``first``
|
||||
Returns the first item in a list
|
||||
Returns the first item in a list.
|
||||
|
||||
``fix_ampersands``
|
||||
Replaces ampersands with ``&`` entities
|
||||
Replaces ampersands with ``&`` entities.
|
||||
|
||||
``floatformat``
|
||||
Displays a floating point number as 34.2 (with one decimal places) - but
|
||||
only if there's a point to be displayed
|
||||
only if there's a point to be displayed.
|
||||
|
||||
``get_digit``
|
||||
Given a whole number, returns the requested digit of it, where 1 is the
|
||||
@@ -624,52 +627,52 @@ Built-in filter reference
|
||||
or if argument is less than 1). Otherwise, output is always an integer.
|
||||
|
||||
``join``
|
||||
Joins a list with a string, like Python's ``str.join(list)``
|
||||
Joins a list with a string, like Python's ``str.join(list)``.
|
||||
|
||||
``length``
|
||||
Returns the length of the value - useful for lists
|
||||
Returns the length of the value. Useful for lists.
|
||||
|
||||
``length_is``
|
||||
Returns a boolean of whether the value's length is the argument
|
||||
Returns a boolean of whether the value's length is the argument.
|
||||
|
||||
``linebreaks``
|
||||
Converts newlines into <p> and <br />s
|
||||
Converts newlines into <p> and <br />s.
|
||||
|
||||
``linebreaksbr``
|
||||
Converts newlines into <br />s
|
||||
Converts newlines into <br />s.
|
||||
|
||||
``linenumbers``
|
||||
Displays text with line numbers
|
||||
Displays text with line numbers.
|
||||
|
||||
``ljust``
|
||||
Left-aligns the value in a field of a given width
|
||||
Left-aligns the value in a field of a given width.
|
||||
|
||||
**Argument:** field size
|
||||
|
||||
``lower``
|
||||
Converts a string into all lowercase
|
||||
Converts a string into all lowercase.
|
||||
|
||||
``make_list``
|
||||
Returns the value turned into a list. For an integer, it's a list of
|
||||
digits. For a string, it's a list of characters.
|
||||
|
||||
``phone2numeric``
|
||||
Takes a phone number and converts it in to its numerical equivalent
|
||||
Takes a phone number and converts it in to its numerical equivalent.
|
||||
|
||||
``pluralize``
|
||||
Returns 's' if the value is not 1, for '1 vote' vs. '2 votes'
|
||||
Returns 's' if the value is not 1, for '1 vote' vs. '2 votes'.
|
||||
|
||||
``pprint``
|
||||
A wrapper around pprint.pprint -- for debugging, really
|
||||
A wrapper around pprint.pprint -- for debugging, really.
|
||||
|
||||
``random``
|
||||
Returns a random item from the list
|
||||
Returns a random item from the list.
|
||||
|
||||
``removetags``
|
||||
Removes a space separated list of [X]HTML tags from the output
|
||||
Removes a space separated list of [X]HTML tags from the output.
|
||||
|
||||
``rjust``
|
||||
Right-aligns the value in a field of a given width
|
||||
Right-aligns the value in a field of a given width.
|
||||
|
||||
**Argument:** field size
|
||||
|
||||
@@ -696,19 +699,19 @@ Built-in filter reference
|
||||
of Python string formatting
|
||||
|
||||
``striptags``
|
||||
Strips all [X]HTML tags
|
||||
Strips all [X]HTML tags.
|
||||
|
||||
``time``
|
||||
Formats a time according to the given format (same as the ``now`` tag).
|
||||
|
||||
``timesince``
|
||||
Formats a date as the time since that date (i.e. "4 days, 6 hours")
|
||||
Formats a date as the time since that date (i.e. "4 days, 6 hours").
|
||||
|
||||
``title``
|
||||
Converts a string into titlecase
|
||||
Converts a string into titlecase.
|
||||
|
||||
``truncatewords``
|
||||
Truncates a string after a certain number of words
|
||||
Truncates a string after a certain number of words.
|
||||
|
||||
**Argument:** Number of words to truncate after
|
||||
|
||||
@@ -733,26 +736,27 @@ Built-in filter reference
|
||||
</li>
|
||||
|
||||
``upper``
|
||||
Converts a string into all uppercase
|
||||
Converts a string into all uppercase.
|
||||
|
||||
``urlencode``
|
||||
Escapes a value for use in a URL
|
||||
Escapes a value for use in a URL.
|
||||
|
||||
``urlize``
|
||||
Converts URLs in plain text into clickable links
|
||||
Converts URLs in plain text into clickable links.
|
||||
|
||||
``urlizetrunc``
|
||||
Converts URLs into clickable links, truncating URLs to the given character limit
|
||||
Converts URLs into clickable links, truncating URLs to the given character
|
||||
limit.
|
||||
|
||||
**Argument:** Length to truncate URLs to.
|
||||
**Argument:** Length to truncate URLs to
|
||||
|
||||
``wordcount``
|
||||
Returns the number of words
|
||||
Returns the number of words.
|
||||
|
||||
``wordwrap``
|
||||
Wraps words at specified line length
|
||||
Wraps words at specified line length.
|
||||
|
||||
**Argument:** number of words to wrap the text at.
|
||||
**Argument:** number of words at which to wrap the text
|
||||
|
||||
``yesno``
|
||||
Given a string mapping values for true, false and (optionally) None,
|
||||
|
||||
@@ -307,12 +307,12 @@ The Python API
|
||||
|
||||
Django has two ways to load templates from files:
|
||||
|
||||
``django.core.template_loader.get_template(template_name)``
|
||||
``django.core.template.loader.get_template(template_name)``
|
||||
``get_template`` returns the compiled template (a ``Template`` object) for
|
||||
the template with the given name. If the template doesn't exist, it raises
|
||||
``django.core.template.TemplateDoesNotExist``.
|
||||
|
||||
``django.core.template_loader.select_template(template_name_list)``
|
||||
``django.core.template.loader.select_template(template_name_list)``
|
||||
``select_template`` is just like ``get_template``, except it takes a list
|
||||
of template names. Of the list, it returns the first template that exists.
|
||||
|
||||
@@ -398,8 +398,8 @@ Python code, depending on whether you're writing filters or tags.
|
||||
.. admonition:: Behind the scenes
|
||||
|
||||
For a ton of examples, read the source code for Django's default filters
|
||||
and tags. They're in ``django/core/defaultfilters.py`` and
|
||||
``django/core/defaulttags.py``, respectively.
|
||||
and tags. They're in ``django/core/template/defaultfilters.py`` and
|
||||
``django/core/template/defaulttags.py``, respectively.
|
||||
|
||||
Writing custom template filters
|
||||
-------------------------------
|
||||
@@ -710,4 +710,4 @@ The only new concept here is the ``self.nodelist.render(context)`` in
|
||||
|
||||
For more examples of complex rendering, see the source code for ``{% if %}``,
|
||||
``{% for %}``, ``{% ifequal %}`` and ``{% ifchanged %}``. They live in
|
||||
``django/core/defaulttags.py``.
|
||||
``django/core/template/defaulttags.py``.
|
||||
|
||||
@@ -191,14 +191,13 @@ There's a problem here, though: The page's design is hard-coded in the view. If
|
||||
you want to change the way the page looks, you'll have to edit this Python code.
|
||||
So let's use Django's template system to separate the design from Python::
|
||||
|
||||
from django.core import template_loader
|
||||
from django.core.template import Context
|
||||
from django.core.template import Context, loader
|
||||
from django.models.polls import polls
|
||||
from django.utils.httpwrappers import HttpResponse
|
||||
|
||||
def index(request):
|
||||
latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
|
||||
t = template_loader.get_template('polls/index')
|
||||
t = loader.get_template('polls/index')
|
||||
c = Context({
|
||||
'latest_poll_list': latest_poll_list,
|
||||
})
|
||||
@@ -224,7 +223,7 @@ and feel" section of Tutorial 2.
|
||||
When you've done that, create a directory ``polls`` in your template directory.
|
||||
Within that, create a file called ``index.html``. Django requires that
|
||||
templates have ".html" extension. Note that our
|
||||
``template_loader.get_template('polls/index')`` code from above maps to
|
||||
``loader.get_template('polls/index')`` code from above maps to
|
||||
"[template_directory]/polls/index.html" on the filesystem.
|
||||
|
||||
Put the following code in that template::
|
||||
@@ -256,7 +255,7 @@ provides a shortcut. Here's the full ``index()`` view, rewritten::
|
||||
latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
|
||||
return render_to_response('polls/index', {'latest_poll_list': latest_poll_list})
|
||||
|
||||
Note that we no longer need to import ``template_loader``, ``Context`` or
|
||||
Note that we no longer need to import ``loader``, ``Context`` or
|
||||
``HttpResponse``.
|
||||
|
||||
The ``render_to_response()`` function takes a template name as its first
|
||||
|
||||
@@ -197,8 +197,8 @@ objects" and "display a detail page for a particular type of object."
|
||||
By default, the ``object_detail`` generic view uses a template called
|
||||
``<app_label>/<module_name>_detail``. In our case, it'll use the template
|
||||
``"polls/polls_detail"``. Thus, rename your ``polls/detail.html`` template to
|
||||
``polls/polls_detail.html``, and change the ``template_loader.get_template()``
|
||||
line in ``vote()``.
|
||||
``polls/polls_detail.html``, and change the ``render_to_response()`` line in
|
||||
``vote()``.
|
||||
|
||||
Similarly, the ``object_list`` generic view uses a template called
|
||||
``<app_label>/<module_name>_list``. Thus, rename ``polls/index.html`` to
|
||||
|
||||
Reference in New Issue
Block a user