mirror of
https://github.com/django/django.git
synced 2025-07-04 09:49:12 +00:00
multi-auth: Merged to [2919]
git-svn-id: http://code.djangoproject.com/svn/django/branches/multi-auth@2921 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
93937ed38a
commit
e1184016a2
3
AUTHORS
3
AUTHORS
@ -51,6 +51,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Matt Croydon <http://www.postneo.com/>
|
||||
Jonathan Daugherty (cygnus) <http://www.cprogrammer.org/>
|
||||
Jason Davies (Esaj) <http://www.jasondavies.com/>
|
||||
Alex Dedul
|
||||
deric@monowerks.com
|
||||
Jeremy Dunck <http://dunck.us/>
|
||||
Clint Ecker
|
||||
@ -88,6 +89,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Robin Munn <http://www.geekforgod.com/>
|
||||
Nebojša Dorđević
|
||||
Sam Newman <http://www.magpiebrain.com/>
|
||||
Neal Norwitz <nnorwitz@google.com>
|
||||
oggie rob <oz.robharvey@gmail.com>
|
||||
pgross@thoughtworks.com
|
||||
phaedo <http://phaedo.cx/>
|
||||
@ -106,6 +108,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Swaroop C H <http://www.swaroopch.info>
|
||||
Aaron Swartz <http://www.aaronsw.com/>
|
||||
Tom Tobin
|
||||
Tom Insam
|
||||
Joe Topjian <http://joe.terrarum.net/geek/code/python/django/>
|
||||
Malcolm Tredinnick
|
||||
Amit Upadhyay
|
||||
|
@ -44,6 +44,7 @@ LANGUAGES = (
|
||||
('es', _('Spanish')),
|
||||
('fr', _('French')),
|
||||
('gl', _('Galician')),
|
||||
('hu', _('Hungarian')),
|
||||
('he', _('Hebrew')),
|
||||
('is', _('Icelandic')),
|
||||
('it', _('Italian')),
|
||||
@ -62,6 +63,9 @@ LANGUAGES = (
|
||||
('zh-tw', _('Traditional Chinese')),
|
||||
)
|
||||
|
||||
# Languages using BiDi (right-to-left) layout
|
||||
LANGUAGES_BIDI = ("he",)
|
||||
|
||||
# Not-necessarily-technical managers of the site. They get broken link
|
||||
# notifications and other various e-mails.
|
||||
MANAGERS = ADMINS
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
django/conf/locale/el/LC_MESSAGES/django.mo
Normal file
BIN
django/conf/locale/el/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
django/conf/locale/hu/LC_MESSAGES/django.mo
Normal file
BIN
django/conf/locale/hu/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
2022
django/conf/locale/hu/LC_MESSAGES/django.po
Normal file
2022
django/conf/locale/hu/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
BIN
django/conf/locale/hu/LC_MESSAGES/djangojs.mo
Normal file
BIN
django/conf/locale/hu/LC_MESSAGES/djangojs.mo
Normal file
Binary file not shown.
110
django/conf/locale/hu/LC_MESSAGES/djangojs.po
Normal file
110
django/conf/locale/hu/LC_MESSAGES/djangojs.po
Normal file
@ -0,0 +1,110 @@
|
||||
# translation of djangojs.po to
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER.
|
||||
# Nagy Károly <charlie@rendszergazda.com>, 2006.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: djangojs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2005-12-09 11:51+0100\n"
|
||||
"PO-Revision-Date: 2006-05-10 11:59+0200\n"
|
||||
"Last-Translator: Nagy Károly <charlie@rendszergazda.com>\n"
|
||||
"Language-Team: <hu@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: KBabel 1.9.1\n"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||
#, perl-format
|
||||
msgid "Available %s"
|
||||
msgstr "Elérhető %s"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:41
|
||||
msgid "Choose all"
|
||||
msgstr "Mindent kijelöl"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:46
|
||||
msgid "Add"
|
||||
msgstr "Hozzáad"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:48
|
||||
msgid "Remove"
|
||||
msgstr "Eltávolít"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:53
|
||||
#, perl-format
|
||||
msgid "Chosen %s"
|
||||
msgstr "%s kiválasztva"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:54
|
||||
msgid "Select your choice(s) and click "
|
||||
msgstr "Válaszd ki a kért elemeket és kattints"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:59
|
||||
msgid "Clear all"
|
||||
msgstr "Összes törlése"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:26
|
||||
#: contrib/admin/media/js/calendar.js:24
|
||||
msgid ""
|
||||
"January February March April May June July August September October November "
|
||||
"December"
|
||||
msgstr "Január Február Március Április Május Június Július Szeptember Október November December"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:27
|
||||
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
||||
msgstr "Vasárnap Hétfő Kedd Szerda Csütörtök Péntek Szombat"
|
||||
|
||||
#: contrib/admin/media/js/calendar.js:25
|
||||
msgid "S M T W T F S"
|
||||
msgstr "V H K Sz Cs P Szo"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
|
||||
msgid "Now"
|
||||
msgstr "Most"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
|
||||
msgid "Clock"
|
||||
msgstr "Óra"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
|
||||
msgid "Choose a time"
|
||||
msgstr "Válaszd ki az időt"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
|
||||
msgid "Midnight"
|
||||
msgstr "Éjfél"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
||||
msgid "6 a.m."
|
||||
msgstr "Reggel 6 óra"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
|
||||
msgid "Noon"
|
||||
msgstr "Dél"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
|
||||
msgid "Cancel"
|
||||
msgstr "Mégsem"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
|
||||
msgid "Today"
|
||||
msgstr "Ma"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
|
||||
msgid "Calendar"
|
||||
msgstr "Naptár"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
|
||||
msgid "Yesterday"
|
||||
msgstr "Tegnap"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
|
||||
msgid "Tomorrow"
|
||||
msgstr "Holnap"
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
django/conf/locale/is/LC_MESSAGES/djangojs.mo
Normal file
BIN
django/conf/locale/is/LC_MESSAGES/djangojs.mo
Normal file
Binary file not shown.
109
django/conf/locale/is/LC_MESSAGES/djangojs.po
Normal file
109
django/conf/locale/is/LC_MESSAGES/djangojs.po
Normal file
@ -0,0 +1,109 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Djangojs CVS\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2005-12-09 11:51+0100\n"
|
||||
"PO-Revision-Date: 2006-05-13 11:48-0000\n"
|
||||
"Last-Translator: Dagur Páll Ammendrup <dagurp@gmail.com>\n"
|
||||
"Language-Team: Icelandic <dagurp@gmail.com>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Poedit-Language: Icelandic\n"
|
||||
"X-Poedit-Country: ICELAND\n"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||
#, perl-format
|
||||
msgid "Available %s"
|
||||
msgstr "Fáanleg %s"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:41
|
||||
msgid "Choose all"
|
||||
msgstr "Velja öll"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:46
|
||||
msgid "Add"
|
||||
msgstr "Bæta við"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:48
|
||||
msgid "Remove"
|
||||
msgstr "Fjarlægja"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:53
|
||||
#, perl-format
|
||||
msgid "Chosen %s"
|
||||
msgstr "Valin %s"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:54
|
||||
msgid "Select your choice(s) and click "
|
||||
msgstr "Veldu úr valmöguleikunum og smelltu"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:59
|
||||
msgid "Clear all"
|
||||
msgstr "Hreinsa öll"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:26
|
||||
#: contrib/admin/media/js/calendar.js:24
|
||||
msgid "January February March April May June July August September October November December"
|
||||
msgstr "janúar febrúar mars apríl maí júní júlí ágúst september október nóvember desember"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:27
|
||||
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
||||
msgstr "sunnudagur mánudagur þriðjudagur miðvikudagur fimmtudagur föstudagur laugardagur"
|
||||
|
||||
#: contrib/admin/media/js/calendar.js:25
|
||||
msgid "S M T W T F S"
|
||||
msgstr "S M Þ M F F L"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
|
||||
msgid "Now"
|
||||
msgstr "Núna"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
|
||||
msgid "Clock"
|
||||
msgstr "Klukka"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
|
||||
msgid "Choose a time"
|
||||
msgstr "Veldu tíma"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
|
||||
msgid "Midnight"
|
||||
msgstr "Miðnætti"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
||||
msgid "6 a.m."
|
||||
msgstr "6 f.h."
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
|
||||
msgid "Noon"
|
||||
msgstr "Hádegi"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
|
||||
msgid "Cancel"
|
||||
msgstr "Hætta við"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
|
||||
msgid "Today"
|
||||
msgstr "Í dag"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
|
||||
msgid "Calendar"
|
||||
msgstr "Dagatal"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
|
||||
msgid "Yesterday"
|
||||
msgstr "Í gær"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
|
||||
msgid "Tomorrow"
|
||||
msgstr "Á morgun"
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,7 @@ function URLify(s, num_chars) {
|
||||
s = s.replace(r, '');
|
||||
s = s.replace(/[^-A-Z0-9\s]/gi, ''); // remove unneeded chars
|
||||
s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces
|
||||
s = s.replace(/\s+/g, '-'); // convert spaces to hyphens
|
||||
s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens
|
||||
s = s.toLowerCase(); // convert to lowercase
|
||||
return s.substring(0, num_chars);// trim to first num_chars chars
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,16 @@ class AdminApplistNode(template.Node):
|
||||
|
||||
def get_admin_app_list(parser, token):
|
||||
"""
|
||||
{% get_admin_app_list as app_list %}
|
||||
Returns a list of installed applications and models for which the current user
|
||||
has at least one permission.
|
||||
|
||||
Syntax::
|
||||
|
||||
{% get_admin_app_list as [context_var_containing_app_list] %}
|
||||
|
||||
Example usage::
|
||||
|
||||
{% get_admin_app_list as admin_app_list %}
|
||||
"""
|
||||
tokens = token.contents.split()
|
||||
if len(tokens) < 3:
|
||||
|
@ -3,6 +3,9 @@ from django.template import Library
|
||||
register = Library()
|
||||
|
||||
def admin_media_prefix():
|
||||
"""
|
||||
Returns the string contained in the setting ADMIN_MEDIA_PREFIX.
|
||||
"""
|
||||
try:
|
||||
from django.conf import settings
|
||||
except ImportError:
|
||||
|
@ -31,7 +31,7 @@ class ContentType(models.Model):
|
||||
ordering = ('name',)
|
||||
unique_together = (('app_label', 'model'),)
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def model_class(self):
|
||||
|
@ -9,6 +9,7 @@ from django.conf import settings
|
||||
from django.http import HttpResponseForbidden
|
||||
import md5
|
||||
import re
|
||||
import itertools
|
||||
|
||||
_ERROR_MSG = "<h1>403 Forbidden</h1><p>Cross Site Request Forgery detected. Request aborted.</p>"
|
||||
|
||||
@ -19,7 +20,7 @@ _HTML_TYPES = ('text/html', 'application/xhtml+xml')
|
||||
|
||||
def _make_token(session_id):
|
||||
return md5.new(settings.SECRET_KEY + session_id).hexdigest()
|
||||
|
||||
|
||||
class CsrfMiddleware(object):
|
||||
"""Django middleware that adds protection against Cross Site
|
||||
Request Forgeries by adding hidden form fields to POST forms and
|
||||
@ -57,7 +58,7 @@ class CsrfMiddleware(object):
|
||||
return HttpResponseForbidden(_ERROR_MSG)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def process_response(self, request, response):
|
||||
csrf_token = None
|
||||
try:
|
||||
@ -74,11 +75,18 @@ class CsrfMiddleware(object):
|
||||
pass
|
||||
|
||||
if csrf_token is not None and \
|
||||
response['Content-Type'].split(';')[0] in _HTML_TYPES:
|
||||
|
||||
response['Content-Type'].split(';')[0] in _HTML_TYPES:
|
||||
|
||||
# ensure we don't add the 'id' attribute twice (HTML validity)
|
||||
idattributes = itertools.chain(("id='csrfmiddlewaretoken'",),
|
||||
itertools.repeat(''))
|
||||
def add_csrf_field(match):
|
||||
"""Returns the matched <form> tag plus the added <input> element"""
|
||||
return match.group() + "<div style='display:none;'>" + \
|
||||
"<input type='hidden' " + idattributes.next() + \
|
||||
" name='csrfmiddlewaretoken' value='" + csrf_token + \
|
||||
"' /></div>"
|
||||
|
||||
# Modify any POST forms
|
||||
extra_field = "<div style='display:none;'>" + \
|
||||
"<input type='hidden' name='csrfmiddlewaretoken' value='" + \
|
||||
csrf_token + "' /></div>"
|
||||
response.content = _POST_FORM_RE.sub('\\1' + extra_field, response.content)
|
||||
response.content = _POST_FORM_RE.sub(add_csrf_field, response.content)
|
||||
return response
|
||||
|
@ -26,7 +26,7 @@ class FlatPage(models.Model):
|
||||
list_filter = ('sites',)
|
||||
search_fields = ('url', 'title')
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return "%s -- %s" % (self.url, self.title)
|
||||
|
||||
def get_absolute_url(self):
|
||||
|
@ -19,5 +19,5 @@ class Site(models.Model):
|
||||
list_display = ('domain', 'name')
|
||||
search_fields = ('domain', 'name')
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return self.domain
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
from django.conf import settings
|
||||
from email.MIMEText import MIMEText
|
||||
from email.Header import Header
|
||||
import smtplib
|
||||
|
||||
class BadHeaderError(ValueError):
|
||||
@ -12,6 +13,8 @@ class SafeMIMEText(MIMEText):
|
||||
"Forbids multi-line headers, to prevent header injection."
|
||||
if '\n' in val or '\r' in val:
|
||||
raise BadHeaderError, "Header values can't contain newlines (got %r for header %r)" % (val, name)
|
||||
if name == "Subject":
|
||||
val = Header(val, settings.DEFAULT_CHARSET)
|
||||
MIMEText.__setitem__(self, name, val)
|
||||
|
||||
def send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=settings.EMAIL_HOST_USER, auth_password=settings.EMAIL_HOST_PASSWORD):
|
||||
@ -42,7 +45,7 @@ def send_mass_mail(datatuple, fail_silently=False, auth_user=settings.EMAIL_HOST
|
||||
if not recipient_list:
|
||||
continue
|
||||
from_email = from_email or settings.DEFAULT_FROM_EMAIL
|
||||
msg = SafeMIMEText(message)
|
||||
msg = SafeMIMEText(message, 'plain', settings.DEFAULT_CHARSET)
|
||||
msg['Subject'] = subject
|
||||
msg['From'] = from_email
|
||||
msg['To'] = ', '.join(recipient_list)
|
||||
|
@ -14,12 +14,56 @@ import re
|
||||
class Resolver404(Http404):
|
||||
pass
|
||||
|
||||
class NoReverseMatch(Exception):
|
||||
pass
|
||||
|
||||
def get_mod_func(callback):
|
||||
# Converts 'django.views.news.stories.story_detail' to
|
||||
# ['django.views.news.stories', 'story_detail']
|
||||
dot = callback.rindex('.')
|
||||
return callback[:dot], callback[dot+1:]
|
||||
|
||||
class MatchChecker(object):
|
||||
"Class used in reverse RegexURLPattern lookup."
|
||||
def __init__(self, args, kwargs):
|
||||
self.args, self.kwargs = args, kwargs
|
||||
self.current_arg = 0
|
||||
|
||||
def __call__(self, match_obj):
|
||||
# match_obj.group(1) is the contents of the parenthesis.
|
||||
# First we need to figure out whether it's a named or unnamed group.
|
||||
#
|
||||
grouped = match_obj.group(1)
|
||||
m = re.search(r'^\?P<(\w+)>(.*?)$', grouped)
|
||||
if m: # If this was a named group...
|
||||
# m.group(1) is the name of the group
|
||||
# m.group(2) is the regex.
|
||||
try:
|
||||
value = self.kwargs[m.group(1)]
|
||||
except KeyError:
|
||||
# It was a named group, but the arg was passed in as a
|
||||
# positional arg or not at all.
|
||||
try:
|
||||
value = self.args[self.current_arg]
|
||||
self.current_arg += 1
|
||||
except IndexError:
|
||||
# The arg wasn't passed in.
|
||||
raise NoReverseMatch('Not enough positional arguments passed in')
|
||||
test_regex = m.group(2)
|
||||
else: # Otherwise, this was a positional (unnamed) group.
|
||||
try:
|
||||
value = self.args[self.current_arg]
|
||||
self.current_arg += 1
|
||||
except IndexError:
|
||||
# The arg wasn't passed in.
|
||||
raise NoReverseMatch('Not enough positional arguments passed in')
|
||||
test_regex = grouped
|
||||
# Note we're using re.match here on purpose because the start of
|
||||
# to string needs to match.
|
||||
if not re.match(test_regex + '$', str(value)): # TODO: Unicode?
|
||||
raise NoReverseMatch("Value %r didn't match regular expression %r" % (value, test_regex))
|
||||
return str(value) # TODO: Unicode?
|
||||
|
||||
class RegexURLPattern:
|
||||
def __init__(self, regex, callback, default_args=None):
|
||||
# regex is a string representing a regular expression.
|
||||
@ -58,12 +102,37 @@ class RegexURLPattern:
|
||||
except AttributeError, e:
|
||||
raise ViewDoesNotExist, "Tried %s in module %s. Error was: %s" % (func_name, mod_name, str(e))
|
||||
|
||||
def reverse(self, viewname, *args, **kwargs):
|
||||
if viewname != self.callback:
|
||||
raise NoReverseMatch
|
||||
return self.reverse_helper(*args, **kwargs)
|
||||
|
||||
def reverse_helper(self, *args, **kwargs):
|
||||
"""
|
||||
Does a "reverse" lookup -- returns the URL for the given args/kwargs.
|
||||
The args/kwargs are applied to the regular expression in this
|
||||
RegexURLPattern. For example:
|
||||
|
||||
>>> RegexURLPattern('^places/(\d+)/$').reverse_helper(3)
|
||||
'places/3/'
|
||||
>>> RegexURLPattern('^places/(?P<id>\d+)/$').reverse_helper(id=3)
|
||||
'places/3/'
|
||||
>>> RegexURLPattern('^people/(?P<state>\w\w)/(\w+)/$').reverse_helper('adrian', state='il')
|
||||
'people/il/adrian/'
|
||||
|
||||
Raises NoReverseMatch if the args/kwargs aren't valid for the RegexURLPattern.
|
||||
"""
|
||||
# TODO: Handle nested parenthesis in the following regex.
|
||||
result = re.sub(r'\(([^)]+)\)', MatchChecker(args, kwargs), self.regex.pattern)
|
||||
return result.replace('^', '').replace('$', '')
|
||||
|
||||
class RegexURLResolver(object):
|
||||
def __init__(self, regex, urlconf_name):
|
||||
# regex is a string representing a regular expression.
|
||||
# urlconf_name is a string representing the module containing urlconfs.
|
||||
self.regex = re.compile(regex)
|
||||
self.urlconf_name = urlconf_name
|
||||
self.callback = None
|
||||
|
||||
def resolve(self, path):
|
||||
tried = []
|
||||
@ -110,3 +179,12 @@ class RegexURLResolver(object):
|
||||
|
||||
def resolve500(self):
|
||||
return self._resolve_special('500')
|
||||
|
||||
def reverse(self, viewname, *args, **kwargs):
|
||||
for pattern in self.urlconf_module.urlpatterns:
|
||||
if pattern.callback == viewname:
|
||||
try:
|
||||
return pattern.reverse_helper(*args, **kwargs)
|
||||
except NoReverseMatch:
|
||||
continue
|
||||
raise NoReverseMatch
|
||||
|
@ -69,7 +69,10 @@ class Model(object):
|
||||
return getattr(self, self._meta.pk.attname)
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s object>' % self.__class__.__name__
|
||||
return '<%s: %s>' % (self.__class__.__name__, self)
|
||||
|
||||
def __str__(self):
|
||||
return '%s object' % self.__class__.__name__
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val()
|
||||
@ -295,7 +298,7 @@ class Model(object):
|
||||
return ''
|
||||
|
||||
def _get_FIELD_size(self, field):
|
||||
return os.path.getsize(self.__get_FIELD_filename(field))
|
||||
return os.path.getsize(self._get_FIELD_filename(field))
|
||||
|
||||
def _save_FIELD_file(self, field, filename, raw_contents):
|
||||
directory = field.get_directory_name()
|
||||
|
@ -9,7 +9,7 @@ from bisect import bisect
|
||||
import re
|
||||
|
||||
# Calculate the verbose_name by converting from InitialCaps to "lowercase with spaces".
|
||||
get_verbose_name = lambda class_name: re.sub('([A-Z])', ' \\1', class_name).lower().strip()
|
||||
get_verbose_name = lambda class_name: re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', ' \\1', class_name).lower().strip()
|
||||
|
||||
DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
|
||||
'unique_together', 'permissions', 'get_latest_by',
|
||||
|
@ -182,7 +182,12 @@ class QuerySet(object):
|
||||
counter._select_related = False
|
||||
select, sql, params = counter._get_sql_clause()
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT COUNT(*)" + sql, params)
|
||||
if self._distinct:
|
||||
id_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table),
|
||||
backend.quote_name(self.model._meta.pk.column))
|
||||
cursor.execute("SELECT COUNT(DISTINCT(%s))" % id_col + sql, params)
|
||||
else:
|
||||
cursor.execute("SELECT COUNT(*)" + sql, params)
|
||||
return cursor.fetchone()[0]
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
|
@ -91,7 +91,20 @@ libraries = {}
|
||||
builtins = []
|
||||
|
||||
class TemplateSyntaxError(Exception):
|
||||
pass
|
||||
def __str__(self):
|
||||
try:
|
||||
import cStringIO as StringIO
|
||||
except ImportError:
|
||||
import StringIO
|
||||
output = StringIO.StringIO()
|
||||
output.write(Exception.__str__(self))
|
||||
# Check if we wrapped an exception and print that too.
|
||||
if hasattr(self, 'exc_info'):
|
||||
import traceback
|
||||
output.write('\n\nOriginal ')
|
||||
e = self.exc_info
|
||||
traceback.print_exception(e[0], e[1], e[2], 500, output)
|
||||
return output.getvalue()
|
||||
|
||||
class TemplateDoesNotExist(Exception):
|
||||
pass
|
||||
|
@ -66,7 +66,7 @@ def make_list(value):
|
||||
def slugify(value):
|
||||
"Converts to lowercase, removes non-alpha chars and converts spaces to hyphens"
|
||||
value = re.sub('[^\w\s-]', '', value).strip().lower()
|
||||
return re.sub('\s+', '-', value)
|
||||
return re.sub('[-\s]+', '-', value)
|
||||
|
||||
def stringformat(value, arg):
|
||||
"""
|
||||
|
@ -23,6 +23,14 @@ class GetCurrentLanguageNode(Node):
|
||||
context[self.variable] = translation.get_language()
|
||||
return ''
|
||||
|
||||
class GetCurrentLanguageBidiNode(Node):
|
||||
def __init__(self, variable):
|
||||
self.variable = variable
|
||||
|
||||
def render(self, context):
|
||||
context[self.variable] = translation.get_language_bidi()
|
||||
return ''
|
||||
|
||||
class TranslateNode(Node):
|
||||
def __init__(self, value, noop):
|
||||
self.value = value
|
||||
@ -102,9 +110,26 @@ def do_get_current_language(parser, token):
|
||||
"""
|
||||
args = token.contents.split()
|
||||
if len(args) != 3 or args[1] != 'as':
|
||||
raise TemplateSyntaxError, "'get_available_languages' requires 'as variable' (got %r)" % args
|
||||
raise TemplateSyntaxError, "'get_current_language' requires 'as variable' (got %r)" % args
|
||||
return GetCurrentLanguageNode(args[2])
|
||||
|
||||
def do_get_current_language_bidi(parser, token):
|
||||
"""
|
||||
This will store the current language layout in the context.
|
||||
|
||||
Usage::
|
||||
|
||||
{% get_current_language_bidi as bidi %}
|
||||
|
||||
This will fetch the currently active language's layout and
|
||||
put it's value into the ``bidi`` context variable.
|
||||
True indicates right-to-left layout, otherwise left-to-right
|
||||
"""
|
||||
args = token.contents.split()
|
||||
if len(args) != 3 or args[1] != 'as':
|
||||
raise TemplateSyntaxError, "'get_current_language_bidi' requires 'as variable' (got %r)" % args
|
||||
return GetCurrentLanguageBidiNode(args[2])
|
||||
|
||||
def do_translate(parser, token):
|
||||
"""
|
||||
This will mark a string for translation and will
|
||||
@ -217,5 +242,6 @@ def do_block_translate(parser, token):
|
||||
|
||||
register.tag('get_available_languages', do_get_available_languages)
|
||||
register.tag('get_current_language', do_get_current_language)
|
||||
register.tag('get_current_language_bidi', do_get_current_language_bidi)
|
||||
register.tag('trans', do_translate)
|
||||
register.tag('blocktrans', do_block_translate)
|
||||
|
@ -16,8 +16,8 @@ MONTHS = {
|
||||
12:_('December')
|
||||
}
|
||||
MONTHS_3 = {
|
||||
1:'jan', 2:'feb', 3:'mar', 4:'apr', 5:'may', 6:'jun', 7:'jul', 8:'aug',
|
||||
9:'sep', 10:'oct', 11:'nov', 12:'dec'
|
||||
1:_('jan'), 2:_('feb'), 3:_('mar'), 4:_('apr'), 5:_('may'), 6:_('jun'),
|
||||
7:_('jul'), 8:_('aug'), 9:_('sep'), 10:_('oct'), 11:_('nov'), 12:_('dec')
|
||||
}
|
||||
MONTHS_3_REV = {
|
||||
'jan':1, 'feb':2, 'mar':3, 'apr':4, 'may':5, 'jun':6, 'jul':7, 'aug':8,
|
||||
|
@ -212,6 +212,16 @@ def get_language():
|
||||
from django.conf import settings
|
||||
return settings.LANGUAGE_CODE
|
||||
|
||||
def get_language_bidi():
|
||||
"""
|
||||
Returns selected language's BiDi layout.
|
||||
False = left-to-right layout
|
||||
True = right-to-left layout
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
return get_language() in settings.LANGUAGES_BIDI
|
||||
|
||||
def catalog():
|
||||
"""
|
||||
This function returns the current active catalog for further processing.
|
||||
|
@ -215,7 +215,7 @@ Anonymous users
|
||||
---------------
|
||||
|
||||
``django.contrib.auth.models.AnonymousUser`` is a class that implements
|
||||
the ``django.contirb.auth.models.User`` interface, with these differences:
|
||||
the ``django.contrib.auth.models.User`` interface, with these differences:
|
||||
|
||||
* ``id`` is always ``None``.
|
||||
* ``is_anonymous()`` returns ``True`` instead of ``False``.
|
||||
@ -445,7 +445,7 @@ permissions are added to the ``auth_permission`` database table when you run
|
||||
Note that if your model doesn't have ``class Admin`` set when you run
|
||||
``syncdb``, the permissions won't be created. If you initialize your database
|
||||
and add ``class Admin`` to models after the fact, you'll need to run
|
||||
``django-admin.py syncdb`` again. It will create any missing permissions for
|
||||
``manage.py syncdb`` again. It will create any missing permissions for
|
||||
all of your installed apps.
|
||||
|
||||
Custom permissions
|
||||
@ -492,7 +492,7 @@ Methods
|
||||
~~~~~~~
|
||||
|
||||
``Permission`` objects have the standard data-access methods like any other
|
||||
`Django model`_:
|
||||
`Django model`_.
|
||||
|
||||
Authentication data in templates
|
||||
================================
|
||||
|
@ -339,7 +339,7 @@ Here are a few examples of upstream caches:
|
||||
somedomain.com, your ISP would send you the page without having to access
|
||||
somedomain.com directly.
|
||||
|
||||
* Your Django Web site may site behind a Squid Web proxy
|
||||
* Your Django Web site may sit behind a Squid Web proxy
|
||||
(http://www.squid-cache.org/) that caches pages for performance. In this
|
||||
case, each request first would be handled by Squid, and it'd only be
|
||||
passed to your application if needed.
|
||||
|
@ -1085,7 +1085,7 @@ This spanning can be as deep as you'd like.
|
||||
It works backwards, too. To refer to a "reverse" relationship, just use the
|
||||
lowercase name of the model.
|
||||
|
||||
This example retrieves all ``Blog`` objects who have at least one ``Entry``
|
||||
This example retrieves all ``Blog`` objects which have at least one ``Entry``
|
||||
whose ``headline`` contains ``'Lennon'``::
|
||||
|
||||
Blog.objects.filter(entry__headline__contains='Lennon')
|
||||
@ -1168,7 +1168,7 @@ Complex lookups with Q objects
|
||||
==============================
|
||||
|
||||
Keyword argument queries -- in ``filter()``, etc. -- are "AND"ed together. If
|
||||
you need to execute more more complex queries (for example, queries with ``OR``
|
||||
you need to execute more complex queries (for example, queries with ``OR``
|
||||
statements), you can use ``Q`` objects.
|
||||
|
||||
A ``Q`` object (``django.db.models.Q``) is an object used to encapsulate a
|
||||
@ -1534,7 +1534,7 @@ described in `Field lookups`_ above.
|
||||
|
||||
Note that in the case of identical date values, these methods will use the ID
|
||||
as a fallback check. This guarantees that no records are skipped or duplicated.
|
||||
For a full example, see the `lookup API sample model_`.
|
||||
For a full example, see the `lookup API sample model`_.
|
||||
|
||||
.. _lookup API sample model: http://www.djangoproject.com/documentation/models/lookup/
|
||||
|
||||
|
@ -19,6 +19,13 @@ In two lines::
|
||||
|
||||
send_mail('Subject here', 'Here is the message.', 'from@example.com',
|
||||
['to@example.com'], fail_silently=False)
|
||||
|
||||
.. note::
|
||||
|
||||
The character set of email sent with ``django.core.mail`` will be set to
|
||||
the value of your `DEFAULT_CHARSET setting`_.
|
||||
|
||||
.. _DEFAULT_CHARSET setting: ../settings/#DEFAULT_CHARSET
|
||||
|
||||
send_mail()
|
||||
===========
|
||||
|
@ -122,7 +122,7 @@ Manual transaction management looks like this::
|
||||
else:
|
||||
transaction.commit()
|
||||
|
||||
..admonition:: An important note to users of earlier Django releases:
|
||||
.. admonition:: An important note to users of earlier Django releases:
|
||||
|
||||
The database ``connection.commit()`` and ``connection.rollback()`` methods
|
||||
(called ``db.commit()`` and ``db.rollback()`` in 0.91 and earlier) no longer
|
||||
|
@ -112,7 +112,7 @@ If you need help with regular expressions, see `Wikipedia's entry`_ and the
|
||||
`Python documentation`_. Also, the O'Reilly book "Mastering Regular
|
||||
Expressions" by Jeffrey Friedl is fantastic.
|
||||
|
||||
Finally, a performance note: These regular expressions are compiled the first
|
||||
Finally, a performance note: these regular expressions are compiled the first
|
||||
time the URLconf module is loaded. They're super fast.
|
||||
|
||||
.. _Wikipedia's entry: http://en.wikipedia.org/wiki/Regular_expression
|
||||
|
2
setup.py
2
setup.py
@ -11,7 +11,7 @@ setup(
|
||||
author_email = 'holovaty@gmail.com',
|
||||
description = 'A high-level Python Web framework that encourages rapid development and clean, pragmatic design.',
|
||||
license = 'BSD',
|
||||
packages = find_packages(exclude=['examples']),
|
||||
packages = find_packages(exclude=['examples', 'examples.*']),
|
||||
package_data = {
|
||||
'': ['*.TXT'],
|
||||
'django.conf': ['locale/bn/LC_MESSAGES/*',
|
||||
|
@ -197,7 +197,7 @@ TypeError: dates() takes at least 3 arguments (1 given)
|
||||
>>> Article.objects.dates('invalid_field', 'year')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
FieldDoesNotExist: name=invalid_field
|
||||
FieldDoesNotExist: Article has no field named 'invalid_field'
|
||||
|
||||
>>> Article.objects.dates('pub_date', 'bad_kind')
|
||||
Traceback (most recent call last):
|
||||
|
@ -82,6 +82,13 @@ API_TESTS = """
|
||||
>>> Article.objects.filter(publications__title__startswith="Science").distinct()
|
||||
[NASA uses Python]
|
||||
|
||||
# The count() function respects distinct() as well.
|
||||
>>> Article.objects.filter(publications__title__startswith="Science").count()
|
||||
2
|
||||
|
||||
>>> Article.objects.filter(publications__title__startswith="Science").distinct().count()
|
||||
1
|
||||
|
||||
# Reverse m2m queries are supported (i.e., starting at the table that doesn't
|
||||
# have a ManyToManyField).
|
||||
>>> Publication.objects.filter(id__exact=1)
|
||||
|
@ -205,6 +205,12 @@ John Smith
|
||||
>>> Reporter.objects.filter(article__headline__startswith='This').distinct()
|
||||
[John Smith]
|
||||
|
||||
# Counting in the opposite direction works in conjunction with distinct()
|
||||
>>> Reporter.objects.filter(article__headline__startswith='This').count()
|
||||
3
|
||||
>>> Reporter.objects.filter(article__headline__startswith='This').distinct().count()
|
||||
1
|
||||
|
||||
# Queries can go round in circles.
|
||||
>>> Reporter.objects.filter(article__reporter__first_name__startswith='John')
|
||||
[John Smith, John Smith, John Smith, John Smith]
|
||||
|
@ -103,7 +103,7 @@ None
|
||||
>>> r.article_set.remove(a4)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
DoesNotExist: 'Fourth' is not related to 'John Smith'.
|
||||
DoesNotExist: 'Article object' is not related to 'Reporter object'.
|
||||
|
||||
>>> r2.article_set.all()
|
||||
[Fourth]
|
||||
|
@ -44,10 +44,13 @@ API_TESTS = """
|
||||
>>> Article.objects.filter(Q(headline__startswith='Hello') & Q(headline__startswith='Goodbye'))
|
||||
[]
|
||||
|
||||
>>> Article.objects.filter(headline__startswith='Hello') & Article.objects.filter(headline__startswith='Goodbye')
|
||||
# You can shorten this syntax with code like the following,
|
||||
# which is especially useful if building the query in stages:
|
||||
>>> articles = Article.objects.all()
|
||||
>>> articles.filter(headline__startswith='Hello') & articles.filter(headline__startswith='Goodbye')
|
||||
[]
|
||||
|
||||
>>> Article.objects.filter(headline__startswith='Hello') & Article.objects.filter(headline__contains='bye')
|
||||
>>> articles.filter(headline__startswith='Hello') & articles.filter(headline__contains='bye')
|
||||
[Hello and goodbye]
|
||||
|
||||
>>> Article.objects.filter(Q(headline__contains='bye'), headline__startswith='Hello')
|
||||
|
Loading…
x
Reference in New Issue
Block a user