diff options
| author | Malcolm Tredinnick <malcolm.tredinnick@gmail.com> | 2008-03-18 14:54:39 +0000 |
|---|---|---|
| committer | Malcolm Tredinnick <malcolm.tredinnick@gmail.com> | 2008-03-18 14:54:39 +0000 |
| commit | 9b52f35f35d67d6b4db2206d34320545dc4dd17d (patch) | |
| tree | 8919395dbe28a6a24de4c2234fce6b15ff3d698e | |
| parent | 5b8974c7b3cbde2d63ddda8f3bddfa2637af5bb9 (diff) | |
Added "svn:eol-style native" to every text file in the tree (*.txt, *.html,
*.py, *.xml and AUTHORS, etc). Added "svn:ignore *.pyc" to some directories in
tests/regressiontests/ that were previously missing it.
Fixed #6545, #6801.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7294 bcc190cf-cafb-0310-a4f2-bffc1f526a37
| -rw-r--r-- | django/contrib/admin/templates/admin_doc/index.html | 54 | ||||
| -rw-r--r-- | django/contrib/admin/templates/admin_doc/view_index.html | 84 | ||||
| -rw-r--r-- | django/contrib/formtools/wizard.py | 492 |
3 files changed, 315 insertions, 315 deletions
diff --git a/django/contrib/admin/templates/admin_doc/index.html b/django/contrib/admin/templates/admin_doc/index.html index 64766fb46f..750dd2f5ac 100644 --- a/django/contrib/admin/templates/admin_doc/index.html +++ b/django/contrib/admin/templates/admin_doc/index.html @@ -1,27 +1,27 @@ -{% extends "admin/base_site.html" %}
-{% load i18n %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> › Documentation</div>{% endblock %}
-{% block title %}Documentation{% endblock %}
-
-{% block content %}
-
-<h1>Documentation</h1>
-
-<div id="content-main">
- <h3><a href="tags/">Tags</a></h3>
- <p>List of all the template tags and their functions.</p>
-
- <h3><a href="filters/">Filters</a></h3>
- <p>Filters are actions which can be applied to variables in a template to alter the output.</p>
-
- <h3><a href="models/">Models</a></h3>
- <p>Models are descriptions of all the objects in the system and their associated fields. Each model has a list of fields which can be accessed as template variables.</p>
-
- <h3><a href="views/">Views</a></h3>
- <p>Each page on the public site is generated by a view. The view defines which template is used to generate the page and which objects are available to that template.</p>
-
- <h3><a href="bookmarklets/">Bookmarklets</a></h3>
- <p>Tools for your browser to quickly access admin functionality.</p>
-</div>
-
-{% endblock %}
+{% extends "admin/base_site.html" %} +{% load i18n %} +{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> › Documentation</div>{% endblock %} +{% block title %}Documentation{% endblock %} + +{% block content %} + +<h1>Documentation</h1> + +<div id="content-main"> + <h3><a href="tags/">Tags</a></h3> + <p>List of all the template tags and their functions.</p> + + <h3><a href="filters/">Filters</a></h3> + <p>Filters are actions which can be applied to variables in a template to alter the output.</p> + + <h3><a href="models/">Models</a></h3> + <p>Models are descriptions of all the objects in the system and their associated fields. Each model has a list of fields which can be accessed as template variables.</p> + + <h3><a href="views/">Views</a></h3> + <p>Each page on the public site is generated by a view. The view defines which template is used to generate the page and which objects are available to that template.</p> + + <h3><a href="bookmarklets/">Bookmarklets</a></h3> + <p>Tools for your browser to quickly access admin functionality.</p> +</div> + +{% endblock %} diff --git a/django/contrib/admin/templates/admin_doc/view_index.html b/django/contrib/admin/templates/admin_doc/view_index.html index 1ed5ba2ac1..716e2d1a91 100644 --- a/django/contrib/admin/templates/admin_doc/view_index.html +++ b/django/contrib/admin/templates/admin_doc/view_index.html @@ -1,42 +1,42 @@ -{% extends "admin/base_site.html" %}
-{% load i18n %}
-{% block coltype %}colSM{% endblock %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> › <a href="../">Documentation</a> › Views</div>{% endblock %}
-{% block title %}Views{% endblock %}
-
-{% block content %}
-
-<h1>View documentation</h1>
-
-{% regroup views|dictsort:"site_id" by site as views_by_site %}
-
-<div id="content-related" class="sidebar">
-<div class="module">
-<h2>Jump to site</h2>
-<ul>
- {% for site_views in views_by_site %}
- <li><a href="#site{{ site_views.grouper.id }}">{{ site_views.grouper.name }}</a></li>
- {% endfor %}
-</ul>
-</div>
-</div>
-
-<div id="content-main">
-
-{% for site_views in views_by_site %}
-<div class="module">
-<h2 id="site{{ site_views.grouper.id }}">Views by URL on {{ site_views.grouper.name }}</h2>
-
-{% for view in site_views.list|dictsort:"url" %}
-{% ifchanged %}
-<h3><a href="{{ view.module }}.{{ view.name }}/">{{ view.url|escape }}</a></h3>
-<p class="small quiet">View function: {{ view.module }}.{{ view.name }}</p>
-<p>{{ view.title }}</p>
-<hr />
-{% endifchanged %}
-{% endfor %}
-</div>
-{% endfor %}
-</div>
-{% endblock %}
-
+{% extends "admin/base_site.html" %} +{% load i18n %} +{% block coltype %}colSM{% endblock %} +{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> › <a href="../">Documentation</a> › Views</div>{% endblock %} +{% block title %}Views{% endblock %} + +{% block content %} + +<h1>View documentation</h1> + +{% regroup views|dictsort:"site_id" by site as views_by_site %} + +<div id="content-related" class="sidebar"> +<div class="module"> +<h2>Jump to site</h2> +<ul> + {% for site_views in views_by_site %} + <li><a href="#site{{ site_views.grouper.id }}">{{ site_views.grouper.name }}</a></li> + {% endfor %} +</ul> +</div> +</div> + +<div id="content-main"> + +{% for site_views in views_by_site %} +<div class="module"> +<h2 id="site{{ site_views.grouper.id }}">Views by URL on {{ site_views.grouper.name }}</h2> + +{% for view in site_views.list|dictsort:"url" %} +{% ifchanged %} +<h3><a href="{{ view.module }}.{{ view.name }}/">{{ view.url|escape }}</a></h3> +<p class="small quiet">View function: {{ view.module }}.{{ view.name }}</p> +<p>{{ view.title }}</p> +<hr /> +{% endifchanged %} +{% endfor %} +</div> +{% endfor %} +</div> +{% endblock %} + diff --git a/django/contrib/formtools/wizard.py b/django/contrib/formtools/wizard.py index da2f0d56de..a197c3e659 100644 --- a/django/contrib/formtools/wizard.py +++ b/django/contrib/formtools/wizard.py @@ -1,246 +1,246 @@ -"""
-FormWizard class -- implements a multi-page form, validating between each
-step and storing the form's state as HTML hidden fields so that no state is
-stored on the server side.
-"""
-
-from django import newforms as forms
-from django.conf import settings
-from django.http import Http404
-from django.shortcuts import render_to_response
-from django.template.context import RequestContext
-import cPickle as pickle
-import md5
-
-class FormWizard(object):
- # Dictionary of extra template context variables.
- extra_context = {}
-
- # The HTML (and POST data) field name for the "step" variable.
- step_field_name="wizard_step"
-
- # METHODS SUBCLASSES SHOULDN'T OVERRIDE ###################################
-
- def __init__(self, form_list, initial=None):
- "form_list should be a list of Form classes (not instances)."
- self.form_list = form_list[:]
- self.initial = initial or {}
- self.step = 0 # A zero-based counter keeping track of which step we're in.
-
- def __repr__(self):
- return "step: %d\nform_list: %s\ninitial_data: %s" % (self.step, self.form_list, self.initial)
-
- def get_form(self, step, data=None):
- "Helper method that returns the Form instance for the given step."
- return self.form_list[step](data, prefix=self.prefix_for_step(step), initial=self.initial.get(step, None))
-
- def num_steps(self):
- "Helper method that returns the number of steps."
- # You might think we should just set "self.form_list = len(form_list)"
- # in __init__(), but this calculation needs to be dynamic, because some
- # hook methods might alter self.form_list.
- return len(self.form_list)
-
- def __call__(self, request, *args, **kwargs):
- """
- Main method that does all the hard work, conforming to the Django view
- interface.
- """
- if 'extra_context' in kwargs:
- self.extra_context.update(kwargs['extra_context'])
- current_step = self.determine_step(request, *args, **kwargs)
- self.parse_params(request, *args, **kwargs)
-
- # Sanity check.
- if current_step >= self.num_steps():
- raise Http404('Step %s does not exist' % current_step)
-
- # For each previous step, verify the hash and process.
- # TODO: Move "hash_%d" to a method to make it configurable.
- for i in range(current_step):
- form = self.get_form(i, request.POST)
- if request.POST.get("hash_%d" % i, '') != self.security_hash(request, form):
- return self.render_hash_failure(request, i)
- self.process_step(request, form, i)
-
- # Process the current step. If it's valid, go to the next step or call
- # done(), depending on whether any steps remain.
- if request.method == 'POST':
- form = self.get_form(current_step, request.POST)
- else:
- form = self.get_form(current_step)
- if form.is_valid():
- self.process_step(request, form, current_step)
- next_step = current_step + 1
-
- # If this was the last step, validate all of the forms one more
- # time, as a sanity check, and call done().
- num = self.num_steps()
- if next_step == num:
- final_form_list = [self.get_form(i, request.POST) for i in range(num)]
-
- # Validate all the forms. If any of them fail validation, that
- # must mean the validator relied on some other input, such as
- # an external Web site.
- for i, f in enumerate(final_form_list):
- if not f.is_valid():
- return self.render_revalidation_failure(request, i, f)
- return self.done(request, final_form_list)
-
- # Otherwise, move along to the next step.
- else:
- form = self.get_form(next_step)
- current_step = next_step
-
- return self.render(form, request, current_step)
-
- def render(self, form, request, step, context=None):
- "Renders the given Form object, returning an HttpResponse."
- old_data = request.POST
- prev_fields = []
- if old_data:
- hidden = forms.HiddenInput()
- # Collect all data from previous steps and render it as HTML hidden fields.
- for i in range(step):
- old_form = self.get_form(i, old_data)
- hash_name = 'hash_%s' % i
- prev_fields.extend([bf.as_hidden() for bf in old_form])
- prev_fields.append(hidden.render(hash_name, old_data.get(hash_name, self.security_hash(request, old_form))))
- return self.render_template(request, form, ''.join(prev_fields), step, context)
-
- # METHODS SUBCLASSES MIGHT OVERRIDE IF APPROPRIATE ########################
-
- def prefix_for_step(self, step):
- "Given the step, returns a Form prefix to use."
- return str(step)
-
- def render_hash_failure(self, request, step):
- """
- Hook for rendering a template if a hash check failed.
-
- step is the step that failed. Any previous step is guaranteed to be
- valid.
-
- This default implementation simply renders the form for the given step,
- but subclasses may want to display an error message, etc.
- """
- return self.render(self.get_form(step), request, step, context={'wizard_error': 'We apologize, but your form has expired. Please continue filling out the form from this page.'})
-
- def render_revalidation_failure(self, request, step, form):
- """
- Hook for rendering a template if final revalidation failed.
-
- It is highly unlikely that this point would ever be reached, but See
- the comment in __call__() for an explanation.
- """
- return self.render(form, request, step)
-
- def security_hash(self, request, form):
- """
- Calculates the security hash for the given HttpRequest and Form instances.
-
- This creates a list of the form field names/values in a deterministic
- order, pickles the result with the SECRET_KEY setting and takes an md5
- hash of that.
-
- Subclasses may want to take into account request-specific information,
- such as the IP address.
- """
- data = [(bf.name, bf.data or '') for bf in form] + [settings.SECRET_KEY]
- # Use HIGHEST_PROTOCOL because it's the most efficient. It requires
- # Python 2.3, but Django requires 2.3 anyway, so that's OK.
- pickled = pickle.dumps(data, protocol=pickle.HIGHEST_PROTOCOL)
- return md5.new(pickled).hexdigest()
-
- def determine_step(self, request, *args, **kwargs):
- """
- Given the request object and whatever *args and **kwargs were passed to
- __call__(), returns the current step (which is zero-based).
-
- Note that the result should not be trusted. It may even be a completely
- invalid number. It's not the job of this method to validate it.
- """
- if not request.POST:
- return 0
- try:
- step = int(request.POST.get(self.step_field_name, 0))
- except ValueError:
- return 0
- return step
-
- def parse_params(self, request, *args, **kwargs):
- """
- Hook for setting some state, given the request object and whatever
- *args and **kwargs were passed to __call__(), sets some state.
-
- This is called at the beginning of __call__().
- """
- pass
-
- def get_template(self, step):
- """
- Hook for specifying the name of the template to use for a given step.
-
- Note that this can return a tuple of template names if you'd like to
- use the template system's select_template() hook.
- """
- return 'forms/wizard.html'
-
- def render_template(self, request, form, previous_fields, step, context=None):
- """
- Renders the template for the given step, returning an HttpResponse object.
-
- Override this method if you want to add a custom context, return a
- different MIME type, etc. If you only need to override the template
- name, use get_template() instead.
-
- The template will be rendered with the following context:
- step_field -- The name of the hidden field containing the step.
- step0 -- The current step (zero-based).
- step -- The current step (one-based).
- step_count -- The total number of steps.
- form -- The Form instance for the current step (either empty
- or with errors).
- previous_fields -- A string representing every previous data field,
- plus hashes for completed forms, all in the form of
- hidden fields. Note that you'll need to run this
- through the "safe" template filter, to prevent
- auto-escaping, because it's raw HTML.
- """
- context = context or {}
- context.update(self.extra_context)
- return render_to_response(self.get_template(self.step), dict(context,
- step_field=self.step_field_name,
- step0=step,
- step=step + 1,
- step_count=self.num_steps(),
- form=form,
- previous_fields=previous_fields
- ), context_instance=RequestContext(request))
-
- def process_step(self, request, form, step):
- """
- Hook for modifying the FormWizard's internal state, given a fully
- validated Form object. The Form is guaranteed to have clean, valid
- data.
-
- This method should *not* modify any of that data. Rather, it might want
- to set self.extra_context or dynamically alter self.form_list, based on
- previously submitted forms.
-
- Note that this method is called every time a page is rendered for *all*
- submitted steps.
- """
- pass
-
- # METHODS SUBCLASSES MUST OVERRIDE ########################################
-
- def done(self, request, form_list):
- """
- Hook for doing something with the validated data. This is responsible
- for the final processing.
-
- form_list is a list of Form instances, each containing clean, valid
- data.
- """
- raise NotImplementedError("Your %s class has not defined a done() method, which is required." % self.__class__.__name__)
+""" +FormWizard class -- implements a multi-page form, validating between each +step and storing the form's state as HTML hidden fields so that no state is +stored on the server side. +""" + +from django import newforms as forms +from django.conf import settings +from django.http import Http404 +from django.shortcuts import render_to_response +from django.template.context import RequestContext +import cPickle as pickle +import md5 + +class FormWizard(object): + # Dictionary of extra template context variables. + extra_context = {} + + # The HTML (and POST data) field name for the "step" variable. + step_field_name="wizard_step" + + # METHODS SUBCLASSES SHOULDN'T OVERRIDE ################################### + + def __init__(self, form_list, initial=None): + "form_list should be a list of Form classes (not instances)." + self.form_list = form_list[:] + self.initial = initial or {} + self.step = 0 # A zero-based counter keeping track of which step we're in. + + def __repr__(self): + return "step: %d\nform_list: %s\ninitial_data: %s" % (self.step, self.form_list, self.initial) + + def get_form(self, step, data=None): + "Helper method that returns the Form instance for the given step." + return self.form_list[step](data, prefix=self.prefix_for_step(step), initial=self.initial.get(step, None)) + + def num_steps(self): + "Helper method that returns the number of steps." + # You might think we should just set "self.form_list = len(form_list)" + # in __init__(), but this calculation needs to be dynamic, because some + # hook methods might alter self.form_list. + return len(self.form_list) + + def __call__(self, request, *args, **kwargs): + """ + Main method that does all the hard work, conforming to the Django view + interface. + """ + if 'extra_context' in kwargs: + self.extra_context.update(kwargs['extra_context']) + current_step = self.determine_step(request, *args, **kwargs) + self.parse_params(request, *args, **kwargs) + + # Sanity check. + if current_step >= self.num_steps(): + raise Http404('Step %s does not exist' % current_step) + + # For each previous step, verify the hash and process. + # TODO: Move "hash_%d" to a method to make it configurable. + for i in range(current_step): + form = self.get_form(i, request.POST) + if request.POST.get("hash_%d" % i, '') != self.security_hash(request, form): + return self.render_hash_failure(request, i) + self.process_step(request, form, i) + + # Process the current step. If it's valid, go to the next step or call + # done(), depending on whether any steps remain. + if request.method == 'POST': + form = self.get_form(current_step, request.POST) + else: + form = self.get_form(current_step) + if form.is_valid(): + self.process_step(request, form, current_step) + next_step = current_step + 1 + + # If this was the last step, validate all of the forms one more + # time, as a sanity check, and call done(). + num = self.num_steps() + if next_step == num: + final_form_list = [self.get_form(i, request.POST) for i in range(num)] + + # Validate all the forms. If any of them fail validation, that + # must mean the validator relied on some other input, such as + # an external Web site. + for i, f in enumerate(final_form_list): + if not f.is_valid(): + return self.render_revalidation_failure(request, i, f) + return self.done(request, final_form_list) + + # Otherwise, move along to the next step. + else: + form = self.get_form(next_step) + current_step = next_step + + return self.render(form, request, current_step) + + def render(self, form, request, step, context=None): + "Renders the given Form object, returning an HttpResponse." + old_data = request.POST + prev_fields = [] + if old_data: + hidden = forms.HiddenInput() + # Collect all data from previous steps and render it as HTML hidden fields. + for i in range(step): + old_form = self.get_form(i, old_data) + hash_name = 'hash_%s' % i + prev_fields.extend([bf.as_hidden() for bf in old_form]) + prev_fields.append(hidden.render(hash_name, old_data.get(hash_name, self.security_hash(request, old_form)))) + return self.render_template(request, form, ''.join(prev_fields), step, context) + + # METHODS SUBCLASSES MIGHT OVERRIDE IF APPROPRIATE ######################## + + def prefix_for_step(self, step): + "Given the step, returns a Form prefix to use." + return str(step) + + def render_hash_failure(self, request, step): + """ + Hook for rendering a template if a hash check failed. + + step is the step that failed. Any previous step is guaranteed to be + valid. + + This default implementation simply renders the form for the given step, + but subclasses may want to display an error message, etc. + """ + return self.render(self.get_form(step), request, step, context={'wizard_error': 'We apologize, but your form has expired. Please continue filling out the form from this page.'}) + + def render_revalidation_failure(self, request, step, form): + """ + Hook for rendering a template if final revalidation failed. + + It is highly unlikely that this point would ever be reached, but See + the comment in __call__() for an explanation. + """ + return self.render(form, request, step) + + def security_hash(self, request, form): + """ + Calculates the security hash for the given HttpRequest and Form instances. + + This creates a list of the form field names/values in a deterministic + order, pickles the result with the SECRET_KEY setting and takes an md5 + hash of that. + + Subclasses may want to take into account request-specific information, + such as the IP address. + """ + data = [(bf.name, bf.data or '') for bf in form] + [settings.SECRET_KEY] + # Use HIGHEST_PROTOCOL because it's the most efficient. It requires + # Python 2.3, but Django requires 2.3 anyway, so that's OK. + pickled = pickle.dumps(data, protocol=pickle.HIGHEST_PROTOCOL) + return md5.new(pickled).hexdigest() + + def determine_step(self, request, *args, **kwargs): + """ + Given the request object and whatever *args and **kwargs were passed to + __call__(), returns the current step (which is zero-based). + + Note that the result should not be trusted. It may even be a completely + invalid number. It's not the job of this method to validate it. + """ + if not request.POST: + return 0 + try: + step = int(request.POST.get(self.step_field_name, 0)) + except ValueError: + return 0 + return step + + def parse_params(self, request, *args, **kwargs): + """ + Hook for setting some state, given the request object and whatever + *args and **kwargs were passed to __call__(), sets some state. + + This is called at the beginning of __call__(). + """ + pass + + def get_template(self, step): + """ + Hook for specifying the name of the template to use for a given step. + + Note that this can return a tuple of template names if you'd like to + use the template system's select_template() hook. + """ + return 'forms/wizard.html' + + def render_template(self, request, form, previous_fields, step, context=None): + """ + Renders the template for the given step, returning an HttpResponse object. + + Override this method if you want to add a custom context, return a + different MIME type, etc. If you only need to override the template + name, use get_template() instead. + + The template will be rendered with the following context: + step_field -- The name of the hidden field containing the step. + step0 -- The current step (zero-based). + step -- The current step (one-based). + step_count -- The total number of steps. + form -- The Form instance for the current step (either empty + or with errors). + previous_fields -- A string representing every previous data field, + plus hashes for completed forms, all in the form of + hidden fields. Note that you'll need to run this + through the "safe" template filter, to prevent + auto-escaping, because it's raw HTML. + """ + context = context or {} + context.update(self.extra_context) + return render_to_response(self.get_template(self.step), dict(context, + step_field=self.step_field_name, + step0=step, + step=step + 1, + step_count=self.num_steps(), + form=form, + previous_fields=previous_fields + ), context_instance=RequestContext(request)) + + def process_step(self, request, form, step): + """ + Hook for modifying the FormWizard's internal state, given a fully + validated Form object. The Form is guaranteed to have clean, valid + data. + + This method should *not* modify any of that data. Rather, it might want + to set self.extra_context or dynamically alter self.form_list, based on + previously submitted forms. + + Note that this method is called every time a page is rendered for *all* + submitted steps. + """ + pass + + # METHODS SUBCLASSES MUST OVERRIDE ######################################## + + def done(self, request, form_list): + """ + Hook for doing something with the validated data. This is responsible + for the final processing. + + form_list is a list of Form instances, each containing clean, valid + data. + """ + raise NotImplementedError("Your %s class has not defined a done() method, which is required." % self.__class__.__name__) |
