mirror of
https://github.com/django/django.git
synced 2025-07-06 18:59:13 +00:00
queryset-refactor: Merged to [6250]
git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6339 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
5ce2e6c2c8
commit
7325fbf4ff
1
AUTHORS
1
AUTHORS
@ -252,6 +252,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Armin Ronacher
|
||||
Brian Rosner <brosner@gmail.com>
|
||||
Oliver Rutherfurd <http://rutherfurd.net/>
|
||||
ryankanno
|
||||
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
|
||||
Vinay Sajip <vinay_sajip@yahoo.co.uk>
|
||||
David Schein
|
||||
|
@ -1,6 +1,6 @@
|
||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||
from django.http import HttpResponseRedirect
|
||||
from urllib import quote
|
||||
from django.utils.http import urlquote
|
||||
|
||||
def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
|
||||
"""
|
||||
@ -15,7 +15,7 @@ def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIE
|
||||
def _checklogin(request, *args, **kwargs):
|
||||
if test_func(request.user):
|
||||
return view_func(request, *args, **kwargs)
|
||||
return HttpResponseRedirect('%s?%s=%s' % (login_url, redirect_field_name, quote(request.get_full_path())))
|
||||
return HttpResponseRedirect('%s?%s=%s' % (login_url, redirect_field_name, urlquote(request.get_full_path())))
|
||||
_checklogin.__doc__ = view_func.__doc__
|
||||
_checklogin.__dict__ = view_func.__dict__
|
||||
|
||||
|
@ -155,7 +155,7 @@ class PublicFreeCommentManipulator(oldforms.Manipulator):
|
||||
c.save()
|
||||
return c
|
||||
|
||||
def post_comment(request):
|
||||
def post_comment(request, extra_context=None, context_processors=None):
|
||||
"""
|
||||
Post a comment
|
||||
|
||||
@ -185,6 +185,7 @@ def post_comment(request):
|
||||
rating_choices
|
||||
choice of ratings
|
||||
"""
|
||||
if extra_context is None: extra_context = {}
|
||||
if not request.POST:
|
||||
raise Http404, _("Only POSTs are allowed")
|
||||
try:
|
||||
@ -244,7 +245,7 @@ def post_comment(request):
|
||||
'ratings_required': RATINGS_REQUIRED in option_list,
|
||||
'rating_range': rating_range,
|
||||
'rating_choices': rating_choices,
|
||||
}, context_instance=RequestContext(request))
|
||||
}, context_instance=RequestContext(request, extra_context, context_processors))
|
||||
elif 'post' in request.POST:
|
||||
# If the IP is banned, mail the admins, do NOT save the comment, and
|
||||
# serve up the "Thanks for posting" page as if the comment WAS posted.
|
||||
@ -257,7 +258,7 @@ def post_comment(request):
|
||||
else:
|
||||
raise Http404, _("The comment form didn't provide either 'preview' or 'post'")
|
||||
|
||||
def post_free_comment(request):
|
||||
def post_free_comment(request, extra_context=None, context_processors=None):
|
||||
"""
|
||||
Post a free comment (not requiring a log in)
|
||||
|
||||
@ -277,6 +278,7 @@ def post_free_comment(request):
|
||||
security hash (must be included in a posted form to succesfully
|
||||
post a comment).
|
||||
"""
|
||||
if extra_context is None: extra_context = {}
|
||||
if not request.POST:
|
||||
raise Http404, _("Only POSTs are allowed")
|
||||
try:
|
||||
@ -307,7 +309,7 @@ def post_free_comment(request):
|
||||
'options': options,
|
||||
'target': target,
|
||||
'hash': security_hash,
|
||||
}, context_instance=RequestContext(request))
|
||||
}, context_instance=RequestContext(request, extra_context, context_processors))
|
||||
elif 'post' in request.POST:
|
||||
# If the IP is banned, mail the admins, do NOT save the comment, and
|
||||
# serve up the "Thanks for posting" page as if the comment WAS posted.
|
||||
@ -321,7 +323,7 @@ def post_free_comment(request):
|
||||
else:
|
||||
raise Http404, _("The comment form didn't provide either 'preview' or 'post'")
|
||||
|
||||
def comment_was_posted(request):
|
||||
def comment_was_posted(request, extra_context=None, context_processors=None):
|
||||
"""
|
||||
Display "comment was posted" success page
|
||||
|
||||
@ -330,6 +332,7 @@ def comment_was_posted(request):
|
||||
object
|
||||
The object the comment was posted on
|
||||
"""
|
||||
if extra_context is None: extra_context = {}
|
||||
obj = None
|
||||
if 'c' in request.GET:
|
||||
content_type_id, object_id = request.GET['c'].split(':')
|
||||
@ -338,4 +341,5 @@ def comment_was_posted(request):
|
||||
obj = content_type.get_object_for_this_type(pk=object_id)
|
||||
except ObjectDoesNotExist:
|
||||
pass
|
||||
return render_to_response('comments/posted.html', {'object': obj}, context_instance=RequestContext(request))
|
||||
return render_to_response('comments/posted.html', {'object': obj},
|
||||
context_instance=RequestContext(request, extra_context, context_processors))
|
||||
|
@ -4,7 +4,7 @@ from django.template import RequestContext
|
||||
from django.contrib.comments.models import Comment, KarmaScore
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
def vote(request, comment_id, vote):
|
||||
def vote(request, comment_id, vote, extra_context=None, context_processors=None):
|
||||
"""
|
||||
Rate a comment (+1 or -1)
|
||||
|
||||
@ -13,6 +13,7 @@ def vote(request, comment_id, vote):
|
||||
comment
|
||||
`comments.comments` object being rated
|
||||
"""
|
||||
if extra_context is None: extra_context = {}
|
||||
rating = {'up': 1, 'down': -1}.get(vote, False)
|
||||
if not rating:
|
||||
raise Http404, "Invalid vote"
|
||||
@ -27,4 +28,5 @@ def vote(request, comment_id, vote):
|
||||
KarmaScore.objects.vote(request.user.id, comment_id, rating)
|
||||
# Reload comment to ensure we have up to date karma count
|
||||
comment = Comment.objects.get(pk=comment_id)
|
||||
return render_to_response('comments/karma_vote_accepted.html', {'comment': comment}, context_instance=RequestContext(request))
|
||||
return render_to_response('comments/karma_vote_accepted.html', {'comment': comment},
|
||||
context_instance=RequestContext(request, extra_context, context_processors))
|
||||
|
@ -6,7 +6,7 @@ from django.contrib.auth.decorators import login_required
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.conf import settings
|
||||
|
||||
def flag(request, comment_id):
|
||||
def flag(request, comment_id, extra_context=None, context_processors=None):
|
||||
"""
|
||||
Flags a comment. Confirmation on GET, action on POST.
|
||||
|
||||
@ -15,18 +15,22 @@ def flag(request, comment_id):
|
||||
comment
|
||||
the flagged `comments.comments` object
|
||||
"""
|
||||
if extra_context is None: extra_context = {}
|
||||
comment = get_object_or_404(Comment,pk=comment_id, site__id__exact=settings.SITE_ID)
|
||||
if request.POST:
|
||||
UserFlag.objects.flag(comment, request.user)
|
||||
return HttpResponseRedirect('%sdone/' % request.path)
|
||||
return render_to_response('comments/flag_verify.html', {'comment': comment}, context_instance=RequestContext(request))
|
||||
return render_to_response('comments/flag_verify.html', {'comment': comment},
|
||||
context_instance=RequestContext(request, extra_context, context_processors))
|
||||
flag = login_required(flag)
|
||||
|
||||
def flag_done(request, comment_id):
|
||||
def flag_done(request, comment_id, extra_context=None, context_processors=None):
|
||||
if extra_context is None: extra_context = {}
|
||||
comment = get_object_or_404(Comment,pk=comment_id, site__id__exact=settings.SITE_ID)
|
||||
return render_to_response('comments/flag_done.html', {'comment': comment}, context_instance=RequestContext(request))
|
||||
return render_to_response('comments/flag_done.html', {'comment': comment},
|
||||
context_instance=RequestContext(request, extra_context, context_processors))
|
||||
|
||||
def delete(request, comment_id):
|
||||
def delete(request, comment_id, extra_context=None, context_processors=None):
|
||||
"""
|
||||
Deletes a comment. Confirmation on GET, action on POST.
|
||||
|
||||
@ -35,6 +39,7 @@ def delete(request, comment_id):
|
||||
comment
|
||||
the flagged `comments.comments` object
|
||||
"""
|
||||
if extra_context is None: extra_context = {}
|
||||
comment = get_object_or_404(Comment,pk=comment_id, site__id__exact=settings.SITE_ID)
|
||||
if not Comment.objects.user_is_moderator(request.user):
|
||||
raise Http404
|
||||
@ -46,9 +51,12 @@ def delete(request, comment_id):
|
||||
m = ModeratorDeletion(None, request.user.id, comment.id, None)
|
||||
m.save()
|
||||
return HttpResponseRedirect('%sdone/' % request.path)
|
||||
return render_to_response('comments/delete_verify.html', {'comment': comment}, context_instance=RequestContext(request))
|
||||
return render_to_response('comments/delete_verify.html', {'comment': comment},
|
||||
context_instance=RequestContext(request, extra_context, context_processors))
|
||||
delete = login_required(delete)
|
||||
|
||||
def delete_done(request, comment_id):
|
||||
def delete_done(request, comment_id, extra_context=None, context_processors=None):
|
||||
if extra_context is None: extra_context = {}
|
||||
comment = get_object_or_404(Comment,pk=comment_id, site__id__exact=settings.SITE_ID)
|
||||
return render_to_response('comments/delete_done.html', {'comment': comment}, context_instance=RequestContext(request))
|
||||
return render_to_response('comments/delete_done.html', {'comment': comment},
|
||||
context_instance=RequestContext(request, extra_context, context_processors))
|
||||
|
@ -1,47 +1,5 @@
|
||||
"""
|
||||
Formtools Preview application.
|
||||
|
||||
This is an abstraction of the following workflow:
|
||||
|
||||
"Display an HTML form, force a preview, then do something with the submission."
|
||||
|
||||
Given a django.newforms.Form object that you define, this takes care of the
|
||||
following:
|
||||
|
||||
* Displays the form as HTML on a Web page.
|
||||
* Validates the form data once it's submitted via POST.
|
||||
* If it's valid, displays a preview page.
|
||||
* If it's not valid, redisplays the form with error messages.
|
||||
* At the preview page, if the preview confirmation button is pressed, calls
|
||||
a hook that you define -- a done() method.
|
||||
|
||||
The framework enforces the required preview by passing a shared-secret hash to
|
||||
the preview page. If somebody tweaks the form parameters on the preview page,
|
||||
the form submission will fail the hash comparison test.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Subclass FormPreview and define a done() method:
|
||||
|
||||
def done(self, request, cleaned_data):
|
||||
# ...
|
||||
|
||||
This method takes an HttpRequest object and a dictionary of the form data after
|
||||
it has been validated and cleaned. It should return an HttpResponseRedirect.
|
||||
|
||||
Then, just instantiate your FormPreview subclass by passing it a Form class,
|
||||
and pass that to your URLconf, like so:
|
||||
|
||||
(r'^post/$', MyFormPreview(MyForm)),
|
||||
|
||||
The FormPreview class has a few other hooks. See the docstrings in the source
|
||||
code below.
|
||||
|
||||
The framework also uses two templates: 'formtools/preview.html' and
|
||||
'formtools/form.html'. You can override these by setting 'preview_template' and
|
||||
'form_template' attributes on your FormPreview subclass. See
|
||||
django/contrib/formtools/templates for the default templates.
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
|
@ -62,6 +62,6 @@ def lorem(parser, token):
|
||||
count = '1'
|
||||
count = parser.compile_filter(count)
|
||||
if len(bits) != 1:
|
||||
raise TemplateSyntaxError("Incorrect format for %r tag" % tagname)
|
||||
raise template.TemplateSyntaxError("Incorrect format for %r tag" % tagname)
|
||||
return LoremNode(count, method, common)
|
||||
lorem = register.tag(lorem)
|
||||
|
@ -7,6 +7,10 @@ u'lorem ipsum dolor sit amet consectetur adipisicing'
|
||||
>>> paragraphs(1)
|
||||
['Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.']
|
||||
|
||||
>>> from django.template import loader, Context
|
||||
>>> t = loader.get_template_from_string("{% load webdesign %}{% lorem 3 w %}")
|
||||
>>> t.render(Context({}))
|
||||
u'lorem ipsum dolor'
|
||||
"""
|
||||
|
||||
from django.contrib.webdesign.lorem_ipsum import *
|
||||
|
@ -142,7 +142,7 @@ def fix_location_header(request, response):
|
||||
Code constructing response objects is free to insert relative paths and
|
||||
this function converts them to absolute paths.
|
||||
"""
|
||||
if 'location' in response.headers and http.get_host(request):
|
||||
if 'Location' in response and http.get_host(request):
|
||||
response['Location'] = request.build_absolute_uri(response['Location'])
|
||||
return response
|
||||
|
||||
|
@ -159,8 +159,8 @@ class ModPythonHandler(BaseHandler):
|
||||
|
||||
# Convert our custom HttpResponse object back into the mod_python req.
|
||||
req.content_type = response['Content-Type']
|
||||
for key, value in response.headers.items():
|
||||
if key != 'Content-Type':
|
||||
for key, value in response.items():
|
||||
if key != 'content-type':
|
||||
req.headers_out[str(key)] = str(value)
|
||||
for c in response.cookies.values():
|
||||
req.headers_out.add('Set-Cookie', c.output(header=''))
|
||||
|
@ -208,7 +208,7 @@ class WSGIHandler(BaseHandler):
|
||||
except KeyError:
|
||||
status_text = 'UNKNOWN STATUS CODE'
|
||||
status = '%s %s' % (response.status_code, status_text)
|
||||
response_headers = [(str(k), str(v)) for k, v in response.headers.items()]
|
||||
response_headers = [(str(k), str(v)) for k, v in response.items()]
|
||||
for c in response.cookies.values():
|
||||
response_headers.append(('Set-Cookie', str(c.output(header=''))))
|
||||
start_response(status, response_headers)
|
||||
|
@ -1,3 +1,4 @@
|
||||
import os
|
||||
from django.core.management.base import NoArgsCommand
|
||||
from optparse import make_option
|
||||
|
||||
@ -43,4 +44,16 @@ class Command(NoArgsCommand):
|
||||
import rlcompleter
|
||||
readline.set_completer(rlcompleter.Completer(imported_objects).complete)
|
||||
readline.parse_and_bind("tab:complete")
|
||||
|
||||
# We want to honor both $PYTHONSTARTUP and .pythonrc.py, so follow system
|
||||
# conventions and get $PYTHONSTARTUP first then import user.
|
||||
if not use_plain:
|
||||
pythonrc = os.environ.get("PYTHONSTARTUP")
|
||||
if pythonrc and os.path.isfile(pythonrc):
|
||||
try:
|
||||
execfile(pythonrc)
|
||||
except NameError:
|
||||
pass
|
||||
# This will import .pythonrc.py as a side-effect
|
||||
import user
|
||||
code.interact(local=imported_objects)
|
||||
|
@ -52,8 +52,7 @@ def get_validation_errors(outfile, app=None):
|
||||
if f.prepopulate_from is not None and type(f.prepopulate_from) not in (list, tuple):
|
||||
e.add(opts, '"%s": prepopulate_from should be a list or tuple.' % f.name)
|
||||
if f.choices:
|
||||
if isinstance(f.choices, basestring) or \
|
||||
not is_iterable(f.choices):
|
||||
if isinstance(f.choices, basestring) or not is_iterable(f.choices):
|
||||
e.add(opts, '"%s": "choices" should be iterable (e.g., a tuple or list).' % f.name)
|
||||
else:
|
||||
for c in f.choices:
|
||||
|
@ -24,6 +24,12 @@ from MySQLdb.constants import FIELD_TYPE
|
||||
import types
|
||||
import re
|
||||
|
||||
# Raise exceptions for database warnings if DEBUG is on
|
||||
from django.conf import settings
|
||||
if settings.DEBUG:
|
||||
from warnings import filterwarnings
|
||||
filterwarnings("error", category=Database.Warning)
|
||||
|
||||
DatabaseError = Database.DatabaseError
|
||||
IntegrityError = Database.IntegrityError
|
||||
|
||||
@ -153,7 +159,6 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||
return False
|
||||
|
||||
def _cursor(self, settings):
|
||||
from warnings import filterwarnings
|
||||
if not self._valid_connection():
|
||||
kwargs = {
|
||||
'conv': django_conversions,
|
||||
@ -175,8 +180,6 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||
kwargs.update(self.options)
|
||||
self.connection = Database.connect(**kwargs)
|
||||
cursor = self.connection.cursor()
|
||||
if settings.DEBUG:
|
||||
filterwarnings("error", category=Database.Warning)
|
||||
return cursor
|
||||
|
||||
def _rollback(self):
|
||||
|
@ -290,7 +290,7 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||
# string instead of null, but only if the field accepts the
|
||||
# empty string.
|
||||
if value is None and isinstance(field, Field) and field.empty_strings_allowed:
|
||||
value = ''
|
||||
value = u''
|
||||
# Convert 1 or 0 to True or False
|
||||
elif value in (1, 0) and isinstance(field, (BooleanField, NullBooleanField)):
|
||||
value = bool(value)
|
||||
@ -354,7 +354,10 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||
for sequence_info in sequences:
|
||||
table_name = sequence_info['table']
|
||||
seq_name = get_sequence_name(table_name)
|
||||
query = _get_sequence_reset_sql() % {'sequence': seq_name, 'table': self.quote_name(table_name)}
|
||||
column_name = self.quote_name(sequence_info['column'] or 'id')
|
||||
query = _get_sequence_reset_sql() % {'sequence': seq_name,
|
||||
'table': self.quote_name(table_name),
|
||||
'column': column_name}
|
||||
sql.append(query)
|
||||
return sql
|
||||
else:
|
||||
@ -368,13 +371,16 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||
for f in model._meta.fields:
|
||||
if isinstance(f, models.AutoField):
|
||||
sequence_name = get_sequence_name(model._meta.db_table)
|
||||
output.append(query % {'sequence':sequence_name,
|
||||
'table':model._meta.db_table})
|
||||
column_name = self.quote_name(f.db_column or f.name)
|
||||
output.append(query % {'sequence': sequence_name,
|
||||
'table': model._meta.db_table,
|
||||
'column': column_name})
|
||||
break # Only one AutoField is allowed per model, so don't bother continuing.
|
||||
for f in model._meta.many_to_many:
|
||||
sequence_name = get_sequence_name(f.m2m_db_table())
|
||||
output.append(query % {'sequence':sequence_name,
|
||||
'table':f.m2m_db_table()})
|
||||
output.append(query % {'sequence': sequence_name,
|
||||
'table': f.m2m_db_table(),
|
||||
'column': self.quote_name('id')})
|
||||
return output
|
||||
|
||||
def start_transaction_sql(self):
|
||||
@ -507,7 +513,7 @@ def _get_sequence_reset_sql():
|
||||
cval integer;
|
||||
BEGIN
|
||||
LOCK TABLE %(table)s IN SHARE MODE;
|
||||
SELECT NVL(MAX(id), 0) INTO startvalue FROM %(table)s;
|
||||
SELECT NVL(MAX(%(column)s), 0) INTO startvalue FROM %(table)s;
|
||||
SELECT %(sequence)s.nextval INTO cval FROM dual;
|
||||
cval := startvalue - cval;
|
||||
IF cval != 0 THEN
|
||||
|
@ -246,7 +246,7 @@ class HttpResponse(object):
|
||||
else:
|
||||
self._container = [content]
|
||||
self._is_string = True
|
||||
self.headers = {'content-type': content_type}
|
||||
self._headers = {'content-type': content_type}
|
||||
self.cookies = SimpleCookie()
|
||||
if status:
|
||||
self.status_code = status
|
||||
@ -254,24 +254,32 @@ class HttpResponse(object):
|
||||
def __str__(self):
|
||||
"Full HTTP message, including headers"
|
||||
return '\n'.join(['%s: %s' % (key, value)
|
||||
for key, value in self.headers.items()]) \
|
||||
for key, value in self._headers.items()]) \
|
||||
+ '\n\n' + self.content
|
||||
|
||||
def __setitem__(self, header, value):
|
||||
self.headers[header.lower()] = value
|
||||
self._headers[header.lower()] = value
|
||||
|
||||
def __delitem__(self, header):
|
||||
try:
|
||||
del self.headers[header.lower()]
|
||||
del self._headers[header.lower()]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def __getitem__(self, header):
|
||||
return self.headers[header.lower()]
|
||||
return self._headers[header.lower()]
|
||||
|
||||
def has_header(self, header):
|
||||
"Case-insensitive check for a header"
|
||||
return self.headers.has_key(header.lower())
|
||||
return self._headers.has_key(header.lower())
|
||||
|
||||
__contains__ = has_header
|
||||
|
||||
def items(self):
|
||||
return self._headers.items()
|
||||
|
||||
def get(self, header, alternate):
|
||||
return self._headers.get(header, alternate)
|
||||
|
||||
def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=None):
|
||||
self.cookies[key] = value
|
||||
|
@ -20,7 +20,7 @@ class GZipMiddleware(object):
|
||||
|
||||
# Avoid gzipping if we've already got a content-encoding or if the
|
||||
# content-type is Javascript (silly IE...)
|
||||
is_js = "javascript" in response.headers.get('Content-Type', '').lower()
|
||||
is_js = "javascript" in response.get('Content-Type', '').lower()
|
||||
if response.has_header('Content-Encoding') or is_js:
|
||||
return response
|
||||
|
||||
|
@ -14,7 +14,7 @@ def render_to_response(*args, **kwargs):
|
||||
Returns a HttpResponse whose content is filled with the result of calling
|
||||
django.template.loader.render_to_string() with the passed arguments.
|
||||
"""
|
||||
httpresponse_kwargs = {'mimetype': kwargs.pop('mimetype')}
|
||||
httpresponse_kwargs = {'mimetype': kwargs.pop('mimetype', None)}
|
||||
return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
|
||||
load_and_render = render_to_response # For backwards compatibility.
|
||||
|
||||
|
@ -254,13 +254,20 @@ def escape(value):
|
||||
escape = stringfilter(escape)
|
||||
|
||||
def linebreaks(value):
|
||||
"Converts newlines into <p> and <br />s"
|
||||
"""
|
||||
Replaces line breaks in plain text with appropriate HTML; a single
|
||||
newline becomes an HTML line break (``<br />``) and a new line
|
||||
followed by a blank line becomes a paragraph break (``</p>``).
|
||||
"""
|
||||
from django.utils.html import linebreaks
|
||||
return linebreaks(value)
|
||||
linebreaks = stringfilter(linebreaks)
|
||||
|
||||
def linebreaksbr(value):
|
||||
"Converts newlines into <br />s"
|
||||
"""
|
||||
Converts all newlines in a piece of plain text to HTML line breaks
|
||||
(``<br />``).
|
||||
"""
|
||||
return value.replace('\n', '<br />')
|
||||
linebreaksbr = stringfilter(linebreaksbr)
|
||||
|
||||
|
@ -42,9 +42,9 @@ def patch_cache_control(response, **kwargs):
|
||||
def dictitem(s):
|
||||
t = s.split('=',1)
|
||||
if len(t) > 1:
|
||||
return (t[0].lower().replace('-', '_'), t[1])
|
||||
return (t[0].lower(), t[1])
|
||||
else:
|
||||
return (t[0].lower().replace('-', '_'), True)
|
||||
return (t[0].lower(), True)
|
||||
|
||||
def dictvalue(t):
|
||||
if t[1] is True:
|
||||
|
@ -27,7 +27,10 @@ def rfc2822_date(date):
|
||||
return email.Utils.formatdate(time.mktime(date.timetuple()))
|
||||
|
||||
def rfc3339_date(date):
|
||||
return date.strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
if date.tzinfo:
|
||||
return date.strftime('%Y-%m-%dT%H:%M:%S%z')
|
||||
else:
|
||||
return date.strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
|
||||
def get_tag_uri(url, date):
|
||||
"Creates a TagURI. See http://diveintomark.org/archives/2004/05/28/howto-atom-id"
|
||||
|
@ -70,8 +70,9 @@ An abstraction of the following workflow:
|
||||
|
||||
"Display an HTML form, force a preview, then do something with the submission."
|
||||
|
||||
Full documentation for this feature does not yet exist, but you can read the
|
||||
code and docstrings in ``django/contrib/formtools/preview.py`` for a start.
|
||||
See the `form preview documentation`_.
|
||||
|
||||
.. _form preview documentation: ../form_preview/
|
||||
|
||||
humanize
|
||||
========
|
||||
|
97
docs/form_preview.txt
Normal file
97
docs/form_preview.txt
Normal file
@ -0,0 +1,97 @@
|
||||
============
|
||||
Form preview
|
||||
============
|
||||
|
||||
Django comes with an optional "form preview" application that helps automate
|
||||
the following workflow:
|
||||
|
||||
"Display an HTML form, force a preview, then do something with the submission."
|
||||
|
||||
To force a preview of a form submission, all you have to do is write a short
|
||||
Python class.
|
||||
|
||||
Overview
|
||||
=========
|
||||
|
||||
Given a ``django.newforms.Form`` subclass that you define, this application
|
||||
takes care of the following workflow:
|
||||
|
||||
1. Displays the form as HTML on a Web page.
|
||||
2. Validates the form data when it's submitted via POST.
|
||||
a. If it's valid, displays a preview page.
|
||||
b. If it's not valid, redisplays the form with error messages.
|
||||
3. When the "confirmation" form is submitted from the preview page, calls
|
||||
a hook that you define -- a ``done()`` method that gets passed the valid
|
||||
data.
|
||||
|
||||
The framework enforces the required preview by passing a shared-secret hash to
|
||||
the preview page via hidden form fields. If somebody tweaks the form parameters
|
||||
on the preview page, the form submission will fail the hash-comparison test.
|
||||
|
||||
How to use ``FormPreview``
|
||||
==========================
|
||||
|
||||
1. Point Django at the default FormPreview templates. There are two ways to
|
||||
do this:
|
||||
|
||||
* Add ``'django.contrib.formtools'`` to your ``INSTALLED_APPS``
|
||||
setting. This will work if your ``TEMPLATE_LOADERS`` setting includes
|
||||
the ``app_directories`` template loader (which is the case by
|
||||
default). See the `template loader docs`_ for more.
|
||||
|
||||
* Otherwise, determine the full filesystem path to the
|
||||
``django/contrib/formtools/templates`` directory, and add that
|
||||
directory to your ``TEMPLATE_DIRS`` setting.
|
||||
|
||||
2. Create a ``FormPreview`` subclass that overrides the ``done()`` method::
|
||||
|
||||
from django.contrib.formtools import FormPreview
|
||||
from myapp.models import SomeModel
|
||||
|
||||
class SomeModelFormPreview(FormPreview):
|
||||
|
||||
def done(self, request, cleaned_data):
|
||||
# Do something with the cleaned_data, then redirect
|
||||
# to a "success" page.
|
||||
return HttpResponseRedirect('/form/success')
|
||||
|
||||
This method takes an ``HttpRequest`` object and a dictionary of the form
|
||||
data after it has been validated and cleaned. It should return an
|
||||
``HttpResponseRedirect`` that is the end result of the form being
|
||||
submitted.
|
||||
|
||||
3. Change your URLconf to point to an instance of your ``FormPreview``
|
||||
subclass::
|
||||
|
||||
from myapp.preview import SomeModelFormPreview
|
||||
from myapp.models import SomeModel
|
||||
from django import newforms as forms
|
||||
|
||||
...and add the following line to the appropriate model in your URLconf::
|
||||
|
||||
(r'^post/$', SomeModelFormPreview(forms.models.form_for_model(SomeModel))),
|
||||
|
||||
Or, if you already have a Form class defined for the model::
|
||||
|
||||
(r'^post/$', SomeModelFormPreview(SomeModelForm)),
|
||||
|
||||
4. Run the Django server and visit ``/post/`` in your browser.
|
||||
|
||||
.. _template loader docs: ../templates_python/#loader-types
|
||||
|
||||
``FormPreview`` classes
|
||||
=======================
|
||||
|
||||
A ``FormPreview`` class is a simple Python class that represents the preview
|
||||
workflow. ``FormPreview`` classes must subclass
|
||||
``django.contrib.formtools.preview.FormPreview`` and override the ``done()``
|
||||
method. They can live anywhere in your codebase.
|
||||
|
||||
``FormPreview`` templates
|
||||
=========================
|
||||
|
||||
By default, the form is rendered via the template ``formtools/form.html``, and
|
||||
the preview page is rendered via the template ``formtools.preview.html``.
|
||||
These values can be overridden for a particular form preview by setting
|
||||
``preview_template`` and ``form_template`` attributes on the FormPreview
|
||||
subclass. See ``django/contrib/formtools/templates`` for the default templates.
|
@ -6,36 +6,138 @@ The package ``django.shortcuts`` collects helper functions and classes that
|
||||
"span" multiple levels of MVC. In other words, these functions/classes
|
||||
introduce controlled coupling for convenience's sake.
|
||||
|
||||
``render_to_response``
|
||||
======================
|
||||
``render_to_response()``
|
||||
========================
|
||||
|
||||
``django.shortcuts.render_to_response`` renders a given template with a given
|
||||
context dictionary and returns an ``HttpResponse`` object with that rendered
|
||||
text.
|
||||
|
||||
Example::
|
||||
Required arguments
|
||||
------------------
|
||||
|
||||
``template``
|
||||
The full name of a template to use.
|
||||
|
||||
Optional arguments
|
||||
------------------
|
||||
|
||||
``context``
|
||||
A dictionary of values to add to the template context. By default, this
|
||||
is an empty dictionary. If a value in the dictionary is callable, the
|
||||
view will call it just before rendering the template.
|
||||
|
||||
``mimetype``
|
||||
**New in Django development version:** The MIME type to use for the
|
||||
resulting document. Defaults to the value of the ``DEFAULT_CONTENT_TYPE``
|
||||
setting.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
The following example renders the template ``myapp/index.html`` with the
|
||||
MIME type ``application/xhtml+xml``::
|
||||
|
||||
from django.shortcuts import render_to_response
|
||||
r = render_to_response('myapp/template.html', {'foo': 'bar'})
|
||||
|
||||
def my_view(request):
|
||||
# View code here...
|
||||
return render_to_response('myapp/index.html', {"foo": "bar"},
|
||||
mimetype="application/xhtml+xml")
|
||||
|
||||
This example is equivalent to::
|
||||
|
||||
from django.http import HttpResponse
|
||||
from django.template import Context, loader
|
||||
t = loader.get_template('myapp/template.html')
|
||||
c = Context({'foo': 'bar'})
|
||||
r = HttpResponse(t.render(c))
|
||||
|
||||
def my_view(request):
|
||||
# View code here...
|
||||
t = loader.get_template('myapp/template.html')
|
||||
c = Context({'foo': 'bar'})
|
||||
r = HttpResponse(t.render(c),
|
||||
mimetype="application/xhtml+xml")
|
||||
|
||||
.. _an HttpResponse object: ../request_response/#httpresponse-objects
|
||||
|
||||
``get_object_or_404``
|
||||
=====================
|
||||
|
||||
``django.shortcuts.get_object_or_404`` calls ``get()`` on a given model
|
||||
``django.shortcuts.get_object_or_404`` calls `get()`_ on a given model
|
||||
manager, but it raises ``django.http.Http404`` instead of the model's
|
||||
``DoesNotExist`` exception.
|
||||
|
||||
Required arguments
|
||||
------------------
|
||||
|
||||
``klass``
|
||||
A ``Model``, ``Manager`` or ``QuerySet`` instance from which to get the
|
||||
object.
|
||||
|
||||
``**kwargs``
|
||||
Lookup parameters, which should be in the format accepted by ``get()`` and
|
||||
``filter()``.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
The following example gets the object with the primary key of 1 from
|
||||
``MyModel``::
|
||||
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
def my_view(request):
|
||||
my_object = get_object_or_404(MyModel, pk=1)
|
||||
|
||||
This example is equivalent to::
|
||||
|
||||
from django.http import Http404
|
||||
|
||||
def my_view(request):
|
||||
try:
|
||||
my_object = MyModel.object.get(pk=1)
|
||||
except MyModel.DoesNotExist:
|
||||
raise Http404
|
||||
|
||||
Note: As with ``get()``, an ``AssertionError`` will be raised if more than
|
||||
one object is found.
|
||||
|
||||
.. _get(): ../db-api/#get-kwargs
|
||||
|
||||
``get_list_or_404``
|
||||
===================
|
||||
|
||||
``django.shortcuts.get_list_or_404`` returns the result of ``filter()`` on a
|
||||
``django.shortcuts.get_list_or_404`` returns the result of `filter()`_ on a
|
||||
given model manager, raising ``django.http.Http404`` if the resulting list is
|
||||
empty.
|
||||
|
||||
Required arguments
|
||||
------------------
|
||||
|
||||
``klass``
|
||||
A ``Model``, ``Manager`` or ``QuerySet`` instance from which to get the
|
||||
object.
|
||||
|
||||
``**kwargs``
|
||||
Lookup parameters, which should be in the format accepted by ``get()`` and
|
||||
``filter()``.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
The following example gets all published objects from ``MyModel``::
|
||||
|
||||
from django.shortcuts import get_list_or_404
|
||||
|
||||
def my_view(request):
|
||||
my_objects = get_list_or_404(MyModel, published=True)
|
||||
|
||||
This example is equivalent to::
|
||||
|
||||
from django.http import Http404
|
||||
|
||||
def my_view(request):
|
||||
my_objects = MyModels.object.filter(published=True)
|
||||
if not my_objects:
|
||||
raise Http404
|
||||
|
||||
.. _filter(): ../db-api/#filter-kwargs
|
||||
|
@ -1135,12 +1135,15 @@ Returns a boolean of whether the value's length is the argument.
|
||||
linebreaks
|
||||
~~~~~~~~~~
|
||||
|
||||
Converts newlines into ``<p>`` and ``<br />`` tags.
|
||||
Replaces line breaks in plain text with appropriate HTML; a single
|
||||
newline becomes an HTML line break (``<br />``) and a new line
|
||||
followed by a blank line becomes a paragraph break (``</p>``).
|
||||
|
||||
linebreaksbr
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Converts newlines into ``<br />`` tags.
|
||||
Converts all newlines in a piece of plain text to HTML line breaks
|
||||
(``<br />``).
|
||||
|
||||
linenumbers
|
||||
~~~~~~~~~~~
|
||||
|
@ -41,6 +41,16 @@ From the command line, ``cd`` into a directory where you'd like to store your
|
||||
code, then run the command ``django-admin.py startproject mysite``. This
|
||||
will create a ``mysite`` directory in your current directory.
|
||||
|
||||
.. admonition:: Max OS X permissions
|
||||
|
||||
If you're using Mac OS X, you may see the message "permission
|
||||
denied" when you try to run ``django-admin.py startproject``. This
|
||||
is because, on Unix-based systems like OS X, a file must be marked
|
||||
as "exceutable" before it can be run as a program. To do this, open
|
||||
Terminal.app and navigate (using the `cd` command) to the directory
|
||||
where ``django-admin.py`` is installed, then run the command
|
||||
``chmod +x django-admin.py``.
|
||||
|
||||
.. note::
|
||||
|
||||
You'll need to avoid naming projects after built-in Python or Django
|
||||
|
@ -115,7 +115,7 @@ True
|
||||
>>> obj = f.save()
|
||||
>>> obj
|
||||
<Category: It's a test>
|
||||
>>> Category.objects.all()
|
||||
>>> Category.objects.order_by('name')
|
||||
[<Category: Entertainment>, <Category: It's a test>]
|
||||
|
||||
If you call save() with commit=False, then it will return an object that
|
||||
@ -129,10 +129,10 @@ True
|
||||
>>> obj = f.save(commit=False)
|
||||
>>> obj
|
||||
<Category: Third test>
|
||||
>>> Category.objects.all()
|
||||
>>> Category.objects.order_by('name')
|
||||
[<Category: Entertainment>, <Category: It's a test>]
|
||||
>>> obj.save()
|
||||
>>> Category.objects.all()
|
||||
>>> Category.objects.order_by('name')
|
||||
[<Category: Entertainment>, <Category: It's a test>, <Category: Third test>]
|
||||
|
||||
If you call save() with invalid data, you'll get a ValueError.
|
||||
@ -306,7 +306,7 @@ Add some categories and test the many-to-many form output.
|
||||
>>> new_art.id
|
||||
1
|
||||
>>> new_art = Article.objects.get(id=1)
|
||||
>>> new_art.categories.all()
|
||||
>>> new_art.categories.order_by('name')
|
||||
[<Category: Entertainment>, <Category: It's a test>]
|
||||
|
||||
Now, submit form data with no categories. This deletes the existing categories.
|
||||
@ -327,7 +327,7 @@ Create a new article, with categories, via the form.
|
||||
>>> new_art.id
|
||||
2
|
||||
>>> new_art = Article.objects.get(id=2)
|
||||
>>> new_art.categories.all()
|
||||
>>> new_art.categories.order_by('name')
|
||||
[<Category: Entertainment>, <Category: It's a test>]
|
||||
|
||||
Create a new article, with no categories, via the form.
|
||||
@ -360,7 +360,7 @@ The m2m data won't be saved until save_m2m() is invoked on the form.
|
||||
|
||||
# Save the m2m data on the form
|
||||
>>> f.save_m2m()
|
||||
>>> new_art.categories.all()
|
||||
>>> new_art.categories.order_by('name')
|
||||
[<Category: Entertainment>, <Category: It's a test>]
|
||||
|
||||
Here, we define a custom Form. Because it happens to have the same fields as
|
||||
|
@ -17,11 +17,7 @@ __test__ = {'API_TESTS': """
|
||||
>>> Square.objects.order_by('root')
|
||||
[<Square: -5 ** 2 == 25>, <Square: -4 ** 2 == 16>, <Square: -3 ** 2 == 9>, <Square: -2 ** 2 == 4>, <Square: -1 ** 2 == 1>, <Square: 0 ** 2 == 0>, <Square: 1 ** 2 == 1>, <Square: 2 ** 2 == 4>, <Square: 3 ** 2 == 9>, <Square: 4 ** 2 == 16>, <Square: 5 ** 2 == 25>]
|
||||
|
||||
#4765: executemany with params=None or params=[] does nothing
|
||||
>>> cursor.executemany('INSERT INTO BACKENDS_SQUARE (ROOT, SQUARE) VALUES (%s, %s)', None) and None or None
|
||||
>>> Square.objects.count()
|
||||
11
|
||||
|
||||
#4765: executemany with params=[] does nothing
|
||||
>>> cursor.executemany('INSERT INTO BACKENDS_SQUARE (ROOT, SQUARE) VALUES (%s, %s)', []) and None or None
|
||||
>>> Square.objects.count()
|
||||
11
|
||||
|
@ -1,5 +1,6 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from django.conf import settings
|
||||
|
||||
class Animal(models.Model):
|
||||
name = models.CharField(max_length=150)
|
||||
@ -20,7 +21,12 @@ class Stuff(models.Model):
|
||||
owner = models.ForeignKey(User, null=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.name) + u' is owned by ' + unicode(self.owner)
|
||||
# Oracle doesn't distinguish between None and the empty string.
|
||||
# This hack makes the test case pass using Oracle.
|
||||
name = self.name
|
||||
if settings.DATABASE_ENGINE == 'oracle' and name == u'':
|
||||
name = None
|
||||
return unicode(name) + u' is owned by ' + unicode(self.owner)
|
||||
|
||||
__test__ = {'API_TESTS':"""
|
||||
>>> from django.core import management
|
||||
|
Loading…
x
Reference in New Issue
Block a user