mirror of
https://github.com/django/django.git
synced 2025-07-04 09:49:12 +00:00
sqlalchemy: Merged revisions 3832 to 3917 from trunk.
git-svn-id: http://code.djangoproject.com/svn/django/branches/sqlalchemy@3918 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
1bb4fa2cb6
commit
0b059aa4ea
8
AUTHORS
8
AUTHORS
@ -64,6 +64,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Ian Clelland <clelland@gmail.com>
|
||||
crankycoder@gmail.com
|
||||
Matt Croydon <http://www.postneo.com/>
|
||||
dackze+django@gmail.com
|
||||
Jonathan Daugherty (cygnus) <http://www.cprogrammer.org/>
|
||||
Jason Davies (Esaj) <http://www.jasondavies.com/>
|
||||
Alex Dedul
|
||||
@ -74,6 +75,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Jeremy Dunck <http://dunck.us/>
|
||||
Andy Dustman <farcepest@gmail.com>
|
||||
Clint Ecker
|
||||
Enrico <rico.bl@gmail.com>
|
||||
favo@exoweb.net
|
||||
gandalf@owca.info
|
||||
Baishampayan Ghose
|
||||
@ -82,6 +84,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Espen Grindhaug <http://grindhaug.org/>
|
||||
Brant Harris
|
||||
heckj@mac.com
|
||||
Joel Heenan <joelh-django@planetjoel.com>
|
||||
hipertracker@gmail.com
|
||||
Ian Holsman <http://feh.holsman.net/>
|
||||
Kieran Holland <http://www.kieranholland.com>
|
||||
@ -95,6 +98,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
kilian <kilian.cavalotti@lip6.fr>
|
||||
Sune Kirkeby <http://ibofobi.dk/>
|
||||
Cameron Knight (ckknight)
|
||||
Meir Kriheli <http://mksoft.co.il/>
|
||||
Bruce Kroeze <http://coderseye.com/>
|
||||
Joseph Kocherhans
|
||||
konrad@gwu.edu
|
||||
@ -103,7 +107,9 @@ answer newbie questions, and generally made Django that much better:
|
||||
Eugene Lazutkin <http://lazutkin.com/blog/>
|
||||
Jeong-Min Lee
|
||||
Christopher Lenz <http://www.cmlenz.net/>
|
||||
lerouxb@gmail.com
|
||||
limodou
|
||||
mattmcc
|
||||
Martin Maney <http://www.chipy.org/Martin_Maney>
|
||||
Manuzhai
|
||||
Petar Marić
|
||||
@ -115,6 +121,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Eric Moritz <http://eric.themoritzfamily.com/>
|
||||
Robin Munn <http://www.geekforgod.com/>
|
||||
Nebojša Dorđević
|
||||
Fraser Nevett <mail@nevett.org>
|
||||
Sam Newman <http://www.magpiebrain.com/>
|
||||
Neal Norwitz <nnorwitz@google.com>
|
||||
oggie rob <oz.robharvey@gmail.com>
|
||||
@ -142,6 +149,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Radek Švarz <http://www.svarz.cz/translate/>
|
||||
Swaroop C H <http://www.swaroopch.info>
|
||||
Aaron Swartz <http://www.aaronsw.com/>
|
||||
Tyson Tate <tyson@fallingbullets.com>
|
||||
Tom Tobin
|
||||
Tom Insam
|
||||
Joe Topjian <http://joe.terrarum.net/geek/code/python/django/>
|
||||
|
8
MANIFEST.in
Normal file
8
MANIFEST.in
Normal file
@ -0,0 +1,8 @@
|
||||
include AUTHORS
|
||||
include INSTALL
|
||||
include LICENSE
|
||||
recursive-include django/conf/locale *
|
||||
recursive-include django/contrib/admin/templates
|
||||
recursive-include django/contrib/admin/media
|
||||
recursive-include django/contrib/comments/templates
|
||||
recursive-include django/contrib/sitemaps/templates
|
@ -1,16 +1,17 @@
|
||||
"Daily cleanup file"
|
||||
"""
|
||||
Daily cleanup job.
|
||||
|
||||
Can be run as a cronjob to clean out old data from the database (only expired
|
||||
sessions at the moment).
|
||||
"""
|
||||
|
||||
from django.db import backend, connection, transaction
|
||||
|
||||
DOCUMENTATION_DIRECTORY = '/home/html/documentation/'
|
||||
|
||||
def clean_up():
|
||||
# Clean up old database records
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("DELETE FROM %s WHERE %s < NOW()" % \
|
||||
(backend.quote_name('core_sessions'), backend.quote_name('expire_date')))
|
||||
cursor.execute("DELETE FROM %s WHERE %s < NOW() - INTERVAL '1 week'" % \
|
||||
(backend.quote_name('registration_challenges'), backend.quote_name('request_date')))
|
||||
(backend.quote_name('django_session'), backend.quote_name('expire_date')))
|
||||
transaction.commit_unless_managed()
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -56,6 +56,7 @@ LANGUAGES = (
|
||||
('ja', gettext_noop('Japanese')),
|
||||
('nl', gettext_noop('Dutch')),
|
||||
('no', gettext_noop('Norwegian')),
|
||||
('pl', gettext_noop('Polish')),
|
||||
('pt-br', gettext_noop('Brazilian')),
|
||||
('ro', gettext_noop('Romanian')),
|
||||
('ru', gettext_noop('Russian')),
|
||||
@ -223,10 +224,6 @@ YEAR_MONTH_FORMAT = 'F Y'
|
||||
# http://www.djangoproject.com/documentation/templates/#now
|
||||
MONTH_DAY_FORMAT = 'F j'
|
||||
|
||||
# Whether to enable Psyco, which optimizes Python code. Requires Psyco.
|
||||
# http://psyco.sourceforge.net/
|
||||
ENABLE_PSYCO = False
|
||||
|
||||
# Do you want to manage transactions manually?
|
||||
# Hint: you really don't!
|
||||
TRANSACTIONS_MANAGED = False
|
||||
@ -274,8 +271,8 @@ CACHE_MIDDLEWARE_KEY_PREFIX = ''
|
||||
COMMENTS_ALLOW_PROFANITIES = False
|
||||
|
||||
# The profanities that will trigger a validation error in the
|
||||
# 'hasNoProfanities' validator. All of these should be in lower-case.
|
||||
PROFANITIES_LIST = ['asshat', 'asshead', 'asshole', 'cunt', 'fuck', 'gook', 'nigger', 'shit']
|
||||
# 'hasNoProfanities' validator. All of these should be in lowercase.
|
||||
PROFANITIES_LIST = ('asshat', 'asshead', 'asshole', 'cunt', 'fuck', 'gook', 'nigger', 'shit')
|
||||
|
||||
# The group ID that designates which users are banned.
|
||||
# Set to None if you're not using it.
|
||||
|
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.
@ -7,8 +7,8 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Django 1.0\n"
|
||||
"Report-Msgid-Bugs-To: Django-users Japan <django-ja@googlegroups.com>\n"
|
||||
"POT-Creation-Date: 2006-05-02 23:06+0900\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2006-10-06 00:30+0900\n"
|
||||
"PO-Revision-Date: 2006-05-08 13:39+0900\n"
|
||||
"Last-Translator: makoto tsuyuki <mtsuyuki@gmail.com>\n"
|
||||
"Language-Team: Japanese <django-ja@googlegroups.com>\n"
|
||||
@ -61,50 +61,58 @@ msgstr "選択してクリック"
|
||||
msgid "Clear all"
|
||||
msgstr "全てクリア"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
|
||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
|
||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
|
||||
msgid "Show"
|
||||
msgstr "表示"
|
||||
|
||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
|
||||
msgid "Hide"
|
||||
msgstr "非表示"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
|
||||
msgid "Now"
|
||||
msgstr "現在"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
|
||||
msgid "Clock"
|
||||
msgstr "時計"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
|
||||
msgid "Choose a time"
|
||||
msgstr "時間を選択"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
||||
msgid "Midnight"
|
||||
msgstr "夜中"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
|
||||
msgid "6 a.m."
|
||||
msgstr "午前 6 時"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
|
||||
msgid "Noon"
|
||||
msgstr "正午"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
|
||||
msgid "Cancel"
|
||||
msgstr "キャンセル"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
|
||||
msgid "Today"
|
||||
msgstr "今日"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
|
||||
msgid "Calendar"
|
||||
msgstr "カレンダー"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
|
||||
msgid "Yesterday"
|
||||
msgstr "昨日"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
|
||||
msgid "Tomorrow"
|
||||
msgstr "明日"
|
||||
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
django/conf/locale/tr/LC_MESSAGES/djangojs.mo
Normal file
BIN
django/conf/locale/tr/LC_MESSAGES/djangojs.mo
Normal file
Binary file not shown.
109
django/conf/locale/tr/LC_MESSAGES/djangojs.po
Normal file
109
django/conf/locale/tr/LC_MESSAGES/djangojs.po
Normal file
@ -0,0 +1,109 @@
|
||||
# Django 0.95
|
||||
# Copyright (C) 2006 Django
|
||||
# This file is distributed under the same license as the Django package.
|
||||
# Bahadır Kandemir <bahadir@pardus.org.tr>, 2006.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Django 0.95\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2006-09-30 01:31+0300\n"
|
||||
"PO-Revision-Date: 2006-09-30 01:31+0300\n"
|
||||
"Last-Translator: Bahadır Kandemir <bahadir@pardus.org.tr>\n"
|
||||
"Language-Team: Bahadır Kandemir <bahadir@pardus.org.tr>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||
#, perl-format
|
||||
msgid "Available %s"
|
||||
msgstr "Mevcut %s"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:41
|
||||
msgid "Choose all"
|
||||
msgstr "Hepsini seç"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:46
|
||||
msgid "Add"
|
||||
msgstr "Ekle"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:48
|
||||
msgid "Remove"
|
||||
msgstr "Kaldır"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:53
|
||||
#, perl-format
|
||||
msgid "Chosen %s"
|
||||
msgstr "Seçilen %s"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:54
|
||||
msgid "Select your choice(s) and click "
|
||||
msgstr "Seçiminizi yapın ve tıklayın "
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:59
|
||||
msgid "Clear all"
|
||||
msgstr "Hepsini temizle"
|
||||
|
||||
#: 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 "Ocak Şubat Mart Nisan Mayıs Haziran Temmuz Ağustos Eylül Ekim Kasım "
|
||||
"Aralık"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:27
|
||||
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
||||
msgstr "Pazar Pazartesi Salı Çarşamba Perşembe Cuma Cumartesi"
|
||||
|
||||
#: contrib/admin/media/js/calendar.js:25
|
||||
msgid "S M T W T F S"
|
||||
msgstr "P P S Ç P C C"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
|
||||
msgid "Now"
|
||||
msgstr "Şimdi"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
|
||||
msgid "Clock"
|
||||
msgstr "Saat"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
|
||||
msgid "Choose a time"
|
||||
msgstr "Saat seçin"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
|
||||
msgid "Midnight"
|
||||
msgstr "Geceyarısı"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
||||
msgid "6 a.m."
|
||||
msgstr "Sabah 6"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
|
||||
msgid "Noon"
|
||||
msgstr "Öğle"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
|
||||
msgid "Cancel"
|
||||
msgstr "İptal"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
|
||||
msgid "Today"
|
||||
msgstr "Bugün"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
|
||||
msgid "Calendar"
|
||||
msgstr "Takvim"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
|
||||
msgid "Yesterday"
|
||||
msgstr "Dün"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
|
||||
msgid "Tomorrow"
|
||||
msgstr "Yarın"
|
@ -8,7 +8,7 @@
|
||||
|
||||
<h1>{{ name }}</h1>
|
||||
|
||||
<h2 class="subhead">{{ summary|escape }}</h2>
|
||||
<h2 class="subhead">{{ summary }}</h2>
|
||||
|
||||
<p>{{ body }}</p>
|
||||
|
||||
|
@ -87,7 +87,7 @@ def staff_member_required(view_func):
|
||||
|
||||
# The user data is correct; log in the user in and continue.
|
||||
else:
|
||||
if user.is_staff:
|
||||
if user.is_active and user.is_staff:
|
||||
login(request, user)
|
||||
# TODO: set last_login with an event.
|
||||
user.last_login = datetime.datetime.now()
|
||||
|
@ -46,6 +46,7 @@ def createsuperuser(username=None, email=None, password=None):
|
||||
if not username.isalnum():
|
||||
sys.stderr.write("Error: That username is invalid. Use only letters, digits and underscores.\n")
|
||||
username = None
|
||||
continue
|
||||
try:
|
||||
User.objects.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
|
@ -29,8 +29,8 @@ login_required.__doc__ = (
|
||||
|
||||
def permission_required(perm, login_url=LOGIN_URL):
|
||||
"""
|
||||
Decorator for views that checks if a user has a particular permission
|
||||
enabled, redirectiing to the log-in page if necessary.
|
||||
Decorator for views that checks whether a user has a particular permission
|
||||
enabled, redirecting to the log-in page if necessary.
|
||||
"""
|
||||
return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)
|
||||
|
||||
|
@ -13,7 +13,7 @@ class UserCreationForm(forms.Manipulator):
|
||||
validator_list=[validators.isAlphaNumeric, self.isValidUsername]),
|
||||
forms.PasswordField(field_name='password1', length=30, maxlength=60, is_required=True),
|
||||
forms.PasswordField(field_name='password2', length=30, maxlength=60, is_required=True,
|
||||
validator_list=[validators.AlwaysMatchesOtherField('password1', "The two password fields didn't match.")]),
|
||||
validator_list=[validators.AlwaysMatchesOtherField('password1', _("The two password fields didn't match."))]),
|
||||
)
|
||||
|
||||
def isValidUsername(self, field_data, all_data):
|
||||
@ -21,7 +21,7 @@ class UserCreationForm(forms.Manipulator):
|
||||
User.objects.get(username=field_data)
|
||||
except User.DoesNotExist:
|
||||
return
|
||||
raise validators.ValidationError, 'A user with that username already exists.'
|
||||
raise validators.ValidationError, _('A user with that username already exists.')
|
||||
|
||||
def save(self, new_data):
|
||||
"Creates the user."
|
||||
@ -81,7 +81,7 @@ class PasswordResetForm(forms.Manipulator):
|
||||
try:
|
||||
self.user_cache = User.objects.get(email__iexact=new_data)
|
||||
except User.DoesNotExist:
|
||||
raise validators.ValidationError, _("That e-mail address doesn't have an associated user acount. Are you sure you've registered?")
|
||||
raise validators.ValidationError, _("That e-mail address doesn't have an associated user account. Are you sure you've registered?")
|
||||
|
||||
def save(self, domain_override=None, email_template_name='registration/password_reset_email.html'):
|
||||
"Calculates a new password randomly and sends it to the user"
|
||||
|
@ -216,6 +216,8 @@ class User(models.Model):
|
||||
|
||||
def has_module_perms(self, app_label):
|
||||
"Returns True if the user has any permissions in the given app label."
|
||||
if not self.is_active:
|
||||
return False
|
||||
if self.is_superuser:
|
||||
return True
|
||||
return bool(len([p for p in self.get_all_permissions() if p[:p.index('.')] == app_label]))
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.google.com/schemas/sitemap/0.84">
|
||||
{% spaceless %}
|
||||
{% for url in urlset %}
|
||||
<url>
|
||||
<loc>{{ url.location|escape }}</loc>
|
||||
@ -8,4 +9,5 @@
|
||||
{% if url.priority %}<priority>{{ url.priority }}</priority>{% endif %}
|
||||
</url>
|
||||
{% endfor %}
|
||||
{% endspaceless %}
|
||||
</urlset>
|
||||
|
@ -1,8 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sitemapindex xmlns="http://www.google.com/schemas/sitemap/0.84">
|
||||
{% for location in sitemaps %}
|
||||
<sitemap>
|
||||
<loc>{{ location|escape }}</loc>
|
||||
</sitemap>
|
||||
{% endfor %}
|
||||
{% for location in sitemaps %}<sitemap><loc>{{ location|escape }}</loc></sitemap>{% endfor %}
|
||||
</sitemapindex>
|
||||
|
@ -48,7 +48,7 @@ class BaseHandler(object):
|
||||
if hasattr(mw_instance, 'process_exception'):
|
||||
self._exception_middleware.insert(0, mw_instance.process_exception)
|
||||
|
||||
def get_response(self, path, request):
|
||||
def get_response(self, request):
|
||||
"Returns an HttpResponse object for the given HttpRequest"
|
||||
from django.core import exceptions, urlresolvers
|
||||
from django.core.mail import mail_admins
|
||||
@ -62,7 +62,7 @@ class BaseHandler(object):
|
||||
|
||||
resolver = urlresolvers.RegexURLResolver(r'^/', settings.ROOT_URLCONF)
|
||||
try:
|
||||
callback, callback_args, callback_kwargs = resolver.resolve(path)
|
||||
callback, callback_args, callback_kwargs = resolver.resolve(request.path)
|
||||
|
||||
# Apply view middleware
|
||||
for middleware_method in self._view_middleware:
|
||||
@ -89,7 +89,8 @@ class BaseHandler(object):
|
||||
return response
|
||||
except http.Http404, e:
|
||||
if settings.DEBUG:
|
||||
return self.get_technical_error_response(request, is404=True, exception=e)
|
||||
from django.views import debug
|
||||
return debug.technical_404_response(request, e)
|
||||
else:
|
||||
callback, param_dict = resolver.resolve404()
|
||||
return callback(request, **param_dict)
|
||||
@ -99,40 +100,24 @@ class BaseHandler(object):
|
||||
pass # See http://code.djangoproject.com/ticket/1023
|
||||
except: # Handle everything else, including SuspiciousOperation, etc.
|
||||
if settings.DEBUG:
|
||||
return self.get_technical_error_response(request)
|
||||
from django.views import debug
|
||||
return debug.technical_500_response(request, *sys.exc_info())
|
||||
else:
|
||||
# Get the exception info now, in case another exception is thrown later.
|
||||
exc_info = sys.exc_info()
|
||||
receivers = dispatcher.send(signal=signals.got_request_exception)
|
||||
# When DEBUG is False, send an error message to the admins.
|
||||
subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), getattr(request, 'path', ''))
|
||||
subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), request.path)
|
||||
try:
|
||||
request_repr = repr(request)
|
||||
except:
|
||||
request_repr = "Request repr() unavailable"
|
||||
message = "%s\n\n%s" % (self._get_traceback(exc_info), request_repr)
|
||||
mail_admins(subject, message, fail_silently=True)
|
||||
return self.get_friendly_error_response(request, resolver)
|
||||
|
||||
def get_friendly_error_response(self, request, resolver):
|
||||
"""
|
||||
Returns an HttpResponse that displays a PUBLIC error message for a
|
||||
fundamental error.
|
||||
"""
|
||||
# Return an HttpResponse that displays a friendly error message.
|
||||
callback, param_dict = resolver.resolve500()
|
||||
return callback(request, **param_dict)
|
||||
|
||||
def get_technical_error_response(self, request, is404=False, exception=None):
|
||||
"""
|
||||
Returns an HttpResponse that displays a TECHNICAL error message for a
|
||||
fundamental error.
|
||||
"""
|
||||
from django.views import debug
|
||||
if is404:
|
||||
return debug.technical_404_response(request, exception)
|
||||
else:
|
||||
return debug.technical_500_response(request, *sys.exc_info())
|
||||
|
||||
def _get_traceback(self, exc_info=None):
|
||||
"Helper function to return the traceback as a string"
|
||||
import traceback
|
||||
|
@ -102,7 +102,7 @@ class ModPythonRequest(http.HttpRequest):
|
||||
'REQUEST_METHOD': self._req.method,
|
||||
'SCRIPT_NAME': None, # Not supported
|
||||
'SERVER_NAME': self._req.server.server_hostname,
|
||||
'SERVER_PORT': self._req.server.port,
|
||||
'SERVER_PORT': str(self._req.connection.local_addr[1]),
|
||||
'SERVER_PROTOCOL': self._req.protocol,
|
||||
'SERVER_SOFTWARE': 'mod_python'
|
||||
}
|
||||
@ -139,10 +139,6 @@ class ModPythonHandler(BaseHandler):
|
||||
# that use settings now can work
|
||||
from django.conf import settings
|
||||
|
||||
if settings.ENABLE_PSYCO:
|
||||
import psyco
|
||||
psyco.profile()
|
||||
|
||||
# if we need to set up middleware, now that settings works we can do it now.
|
||||
if self._request_middleware is None:
|
||||
self.load_middleware()
|
||||
@ -150,7 +146,7 @@ class ModPythonHandler(BaseHandler):
|
||||
dispatcher.send(signal=signals.request_started)
|
||||
try:
|
||||
request = ModPythonRequest(req)
|
||||
response = self.get_response(req.uri, request)
|
||||
response = self.get_response(request)
|
||||
|
||||
# Apply response middleware
|
||||
for middleware_method in self._response_middleware:
|
||||
@ -160,23 +156,20 @@ class ModPythonHandler(BaseHandler):
|
||||
dispatcher.send(signal=signals.request_finished)
|
||||
|
||||
# Convert our custom HttpResponse object back into the mod_python req.
|
||||
populate_apache_request(response, req)
|
||||
return 0 # mod_python.apache.OK
|
||||
|
||||
def populate_apache_request(http_response, mod_python_req):
|
||||
"Populates the mod_python request object with an HttpResponse"
|
||||
mod_python_req.content_type = http_response['Content-Type']
|
||||
for key, value in http_response.headers.items():
|
||||
req.content_type = response['Content-Type']
|
||||
for key, value in response.headers.items():
|
||||
if key != 'Content-Type':
|
||||
mod_python_req.headers_out[key] = value
|
||||
for c in http_response.cookies.values():
|
||||
mod_python_req.headers_out.add('Set-Cookie', c.output(header=''))
|
||||
mod_python_req.status = http_response.status_code
|
||||
req.headers_out[key] = value
|
||||
for c in response.cookies.values():
|
||||
req.headers_out.add('Set-Cookie', c.output(header=''))
|
||||
req.status = response.status_code
|
||||
try:
|
||||
for chunk in http_response:
|
||||
mod_python_req.write(chunk)
|
||||
for chunk in response:
|
||||
req.write(chunk)
|
||||
finally:
|
||||
http_response.close()
|
||||
response.close()
|
||||
|
||||
return 0 # mod_python.apache.OK
|
||||
|
||||
def handler(req):
|
||||
# mod_python hooks into this function.
|
||||
|
@ -174,10 +174,6 @@ class WSGIHandler(BaseHandler):
|
||||
def __call__(self, environ, start_response):
|
||||
from django.conf import settings
|
||||
|
||||
if settings.ENABLE_PSYCO:
|
||||
import psyco
|
||||
psyco.profile()
|
||||
|
||||
# Set up middleware if needed. We couldn't do this earlier, because
|
||||
# settings weren't available.
|
||||
if self._request_middleware is None:
|
||||
@ -186,7 +182,7 @@ class WSGIHandler(BaseHandler):
|
||||
dispatcher.send(signal=signals.request_started)
|
||||
try:
|
||||
request = WSGIRequest(environ)
|
||||
response = self.get_response(request.path, request)
|
||||
response = self.get_response(request)
|
||||
|
||||
# Apply response middleware
|
||||
for middleware_method in self._response_middleware:
|
||||
|
@ -103,7 +103,6 @@ def get_sql_create(app):
|
||||
known_models = set([model for model in _get_installed_models(_get_table_list()) if model not in app_models])
|
||||
pending_references = {}
|
||||
|
||||
|
||||
for model in app_models:
|
||||
output, references = _get_sql_model_create(model, known_models)
|
||||
final_output.extend(output)
|
||||
@ -147,7 +146,7 @@ def _get_sql_model_create(model, known_models=set()):
|
||||
table_output = []
|
||||
pending_references = {}
|
||||
for f in opts.fields:
|
||||
if isinstance(f, models.ForeignKey):
|
||||
if isinstance(f, (models.ForeignKey, models.OneToOneField)):
|
||||
rel_field = f.rel.get_related_field()
|
||||
data_type = get_rel_data_type(rel_field)
|
||||
else:
|
||||
@ -398,11 +397,20 @@ get_sql_sequence_reset.help_doc = "Prints the SQL statements for resetting Postg
|
||||
get_sql_sequence_reset.args = APP_ARGS
|
||||
|
||||
def get_sql_indexes(app):
|
||||
"Returns a list of the CREATE INDEX SQL statements for the given app."
|
||||
from django.db import backend, models
|
||||
"Returns a list of the CREATE INDEX SQL statements for all models in the given app."
|
||||
from django.db import models
|
||||
output = []
|
||||
for model in models.get_models(app):
|
||||
output.extend(get_sql_indexes_for_model(model))
|
||||
return output
|
||||
get_sql_indexes.help_doc = "Prints the CREATE INDEX SQL statements for the given model module name(s)."
|
||||
get_sql_indexes.args = APP_ARGS
|
||||
|
||||
def get_sql_indexes_for_model(model):
|
||||
"Returns the CREATE INDEX SQL statements for a single model"
|
||||
from django.db import backend
|
||||
output = []
|
||||
|
||||
for model in models.get_models(app):
|
||||
for f in model._meta.fields:
|
||||
if f.db_index:
|
||||
unique = f.unique and 'UNIQUE ' or ''
|
||||
@ -414,8 +422,6 @@ def get_sql_indexes(app):
|
||||
"(%s);" % style.SQL_FIELD(backend.quote_name(f.column))
|
||||
)
|
||||
return output
|
||||
get_sql_indexes.help_doc = "Prints the CREATE INDEX SQL statements for the given model module name(s)."
|
||||
get_sql_indexes.args = APP_ARGS
|
||||
|
||||
def get_sql_all(app):
|
||||
"Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
|
||||
@ -423,7 +429,7 @@ def get_sql_all(app):
|
||||
get_sql_all.help_doc = "Prints the CREATE TABLE, initial-data and CREATE INDEX SQL statements for the given model module name(s)."
|
||||
get_sql_all.args = APP_ARGS
|
||||
|
||||
def syncdb(verbosity=2, interactive=True):
|
||||
def syncdb(verbosity=1, interactive=True):
|
||||
"Creates the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
|
||||
from django.db import connection, transaction, models, get_creation_module
|
||||
from django.db.models import signals
|
||||
@ -457,21 +463,21 @@ def syncdb(verbosity=2, interactive=True):
|
||||
pending_references = {}
|
||||
|
||||
for app in models.get_apps():
|
||||
app_name = app.__name__.split('.')[-2]
|
||||
model_list = models.get_models(app)
|
||||
for model in model_list:
|
||||
# Create the model's database table, if it doesn't already exist.
|
||||
if verbosity >= 2:
|
||||
print "Processing %s.%s model" % (app_name, model._meta.object_name)
|
||||
if model._meta.db_table in table_list:
|
||||
continue
|
||||
sql, references = _get_sql_model_create(model, seen_models)
|
||||
seen_models.add(model)
|
||||
created_models.add(model)
|
||||
for refto, refs in references.items():
|
||||
try:
|
||||
pending_references[refto].extend(refs)
|
||||
except KeyError:
|
||||
pending_references[refto] = refs
|
||||
pending_references.setdefault(refto, []).extend(refs)
|
||||
sql.extend(_get_sql_for_pending_references(model, pending_references))
|
||||
if verbosity >= 2:
|
||||
if verbosity >= 1:
|
||||
print "Creating table %s" % model._meta.db_table
|
||||
for statement in sql:
|
||||
cursor.execute(statement)
|
||||
@ -482,7 +488,7 @@ def syncdb(verbosity=2, interactive=True):
|
||||
sql = _get_many_to_many_sql_for_model(model)
|
||||
if sql:
|
||||
if verbosity >= 2:
|
||||
print "Creating many-to-many tables for %s model" % model.__name__
|
||||
print "Creating many-to-many tables for %s.%s model" % (app_name, model._meta.object_name)
|
||||
for statement in sql:
|
||||
cursor.execute(statement)
|
||||
|
||||
@ -491,6 +497,9 @@ def syncdb(verbosity=2, interactive=True):
|
||||
# Send the post_syncdb signal, so individual apps can do whatever they need
|
||||
# to do at this point.
|
||||
for app in models.get_apps():
|
||||
app_name = app.__name__.split('.')[-2]
|
||||
if verbosity >= 2:
|
||||
print "Running post-sync handlers for application", app_name
|
||||
dispatcher.send(signal=signals.post_syncdb, sender=app,
|
||||
app=app, created_models=created_models,
|
||||
verbosity=verbosity, interactive=interactive)
|
||||
@ -501,14 +510,33 @@ def syncdb(verbosity=2, interactive=True):
|
||||
if model in created_models:
|
||||
initial_sql = get_sql_initial_data_for_model(model)
|
||||
if initial_sql:
|
||||
if verbosity >= 2:
|
||||
print "Installing initial data for %s model" % model._meta.object_name
|
||||
if verbosity >= 1:
|
||||
print "Installing initial data for %s.%s model" % (app_name, model._meta.object_name)
|
||||
try:
|
||||
for sql in initial_sql:
|
||||
cursor.execute(sql)
|
||||
except Exception, e:
|
||||
sys.stderr.write("Failed to install initial SQL data for %s model: %s" % \
|
||||
(model._meta.object_name, e))
|
||||
sys.stderr.write("Failed to install initial SQL data for %s.%s model: %s" % \
|
||||
(app_name, model._meta.object_name, e))
|
||||
transaction.rollback_unless_managed()
|
||||
else:
|
||||
transaction.commit_unless_managed()
|
||||
|
||||
# Install SQL indicies for all newly created models
|
||||
for app in models.get_apps():
|
||||
app_name = app.__name__.split('.')[-2]
|
||||
for model in models.get_models(app):
|
||||
if model in created_models:
|
||||
index_sql = get_sql_indexes_for_model(model)
|
||||
if index_sql:
|
||||
if verbosity >= 1:
|
||||
print "Installing index for %s.%s model" % (app_name, model._meta.object_name)
|
||||
try:
|
||||
for sql in index_sql:
|
||||
cursor.execute(sql)
|
||||
except Exception, e:
|
||||
sys.stderr.write("Failed to install index for %s.%s model: %s" % \
|
||||
(app_name, model._meta.object_name, e))
|
||||
transaction.rollback_unless_managed()
|
||||
else:
|
||||
transaction.commit_unless_managed()
|
||||
@ -596,7 +624,7 @@ The full error: """ % (app_name, app_name)) + style.ERROR_OUTPUT(str(e)) + '\n')
|
||||
install.help_doc = "Executes ``sqlall`` for the given app(s) in the current database."
|
||||
install.args = APP_ARGS
|
||||
|
||||
def reset(app):
|
||||
def reset(app, interactive=True):
|
||||
"Executes the equivalent of 'get_sql_reset' in the current database."
|
||||
from django.db import connection, transaction
|
||||
app_name = app.__name__.split('.')[-2]
|
||||
@ -607,21 +635,25 @@ def reset(app):
|
||||
_check_for_validation_errors(app)
|
||||
sql_list = get_sql_reset(app)
|
||||
|
||||
if interactive:
|
||||
confirm = raw_input("""
|
||||
You have requested a database reset.
|
||||
This will IRREVERSIBLY DESTROY any data in your database.
|
||||
Are you sure you want to do this?
|
||||
|
||||
Type 'yes' to continue, or 'no' to cancel: """)
|
||||
else:
|
||||
confirm = 'yes'
|
||||
|
||||
if confirm == 'yes':
|
||||
try:
|
||||
cursor = connection.cursor()
|
||||
for sql in sql_list:
|
||||
cursor.execute(sql)
|
||||
except Exception, e:
|
||||
sys.stderr.write(style.ERROR("""Error: %s couldn't be installed. Possible reasons:
|
||||
sys.stderr.write(style.ERROR("""Error: %s couldn't be reset. Possible reasons:
|
||||
* The database isn't running or isn't configured correctly.
|
||||
* At least one of the database tables already exists.
|
||||
* At least one of the database tables doesn't exist.
|
||||
* The SQL was invalid.
|
||||
Hint: Look at the output of 'django-admin.py sqlreset %s'. That's the SQL this command wasn't able to run.
|
||||
The full error: """ % (app_name, app_name)) + style.ERROR_OUTPUT(str(e)) + '\n')
|
||||
@ -820,7 +852,8 @@ def get_validation_errors(outfile, app=None):
|
||||
validates all models of all installed apps. Writes errors, if any, to outfile.
|
||||
Returns number of errors.
|
||||
"""
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from django.db import models, connection
|
||||
from django.db.models.loading import get_app_errors
|
||||
from django.db.models.fields.related import RelatedObject
|
||||
|
||||
@ -862,6 +895,12 @@ def get_validation_errors(outfile, app=None):
|
||||
if f.db_index not in (None, True, False):
|
||||
e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name)
|
||||
|
||||
# Check that maxlength <= 255 if using older MySQL versions.
|
||||
if settings.DATABASE_ENGINE == 'mysql':
|
||||
db_version = connection.get_server_version()
|
||||
if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.maxlength > 255:
|
||||
e.add(opts, '"%s": %s cannot have a "maxlength" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]])))
|
||||
|
||||
# Check to see if the related field will clash with any
|
||||
# existing fields, m2m fields, m2m related objects or related objects
|
||||
if f.rel:
|
||||
@ -1169,7 +1208,7 @@ def runfcgi(args):
|
||||
runfastcgi(args)
|
||||
runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]'
|
||||
|
||||
def test(verbosity, app_labels):
|
||||
def test(app_labels, verbosity=1):
|
||||
"Runs the test suite for the specified applications"
|
||||
from django.conf import settings
|
||||
from django.db.models import get_app, get_apps
|
||||
@ -1271,10 +1310,10 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
|
||||
help='Tells Django to NOT prompt the user for input of any kind.')
|
||||
parser.add_option('--noreload', action='store_false', dest='use_reloader', default=True,
|
||||
help='Tells Django to NOT use the auto-reloader when running the development server.')
|
||||
parser.add_option('--verbosity', action='store', dest='verbosity', default='2',
|
||||
parser.add_option('--verbosity', action='store', dest='verbosity', default='1',
|
||||
type='choice', choices=['0', '1', '2'],
|
||||
help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
|
||||
parser.add_option('--adminmedia', dest='admin_media_path', default='', help='Lets you manually specify the directory to serve admin media from when running the development server.'),
|
||||
parser.add_option('--adminmedia', dest='admin_media_path', default='', help='Specifies the directory from which to serve admin media for runserver.'),
|
||||
|
||||
options, args = parser.parse_args(argv[1:])
|
||||
|
||||
@ -1320,7 +1359,7 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
|
||||
parser.print_usage_and_exit()
|
||||
elif action == 'test':
|
||||
try:
|
||||
action_mapping[action](int(options.verbosity), args[1:])
|
||||
action_mapping[action](args[1:], int(options.verbosity))
|
||||
except IndexError:
|
||||
parser.print_usage_and_exit()
|
||||
elif action in ('startapp', 'startproject'):
|
||||
@ -1354,6 +1393,9 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
|
||||
if action not in NO_SQL_TRANSACTION:
|
||||
print style.SQL_KEYWORD("BEGIN;")
|
||||
for mod in mod_list:
|
||||
if action == 'reset':
|
||||
output = action_mapping[action](mod, options.interactive)
|
||||
else:
|
||||
output = action_mapping[action](mod)
|
||||
if output:
|
||||
print '\n'.join(output)
|
||||
|
@ -594,7 +594,7 @@ class AdminMediaHandler(object):
|
||||
Use this ONLY LOCALLY, for development! This hasn't been tested for
|
||||
security and is not super efficient.
|
||||
"""
|
||||
def __init__(self, application, media_dir = None):
|
||||
def __init__(self, application, media_dir=None):
|
||||
from django.conf import settings
|
||||
self.application = application
|
||||
if not media_dir:
|
||||
|
@ -15,7 +15,8 @@ class Resolver404(Http404):
|
||||
pass
|
||||
|
||||
class NoReverseMatch(Exception):
|
||||
pass
|
||||
# Don't make this raise an error when used in a template.
|
||||
silent_variable_failure = True
|
||||
|
||||
def get_mod_func(callback):
|
||||
# Converts 'django.views.news.stories.story_detail' to
|
||||
|
@ -249,7 +249,7 @@ def hasNoProfanities(field_data, all_data):
|
||||
Watch your mouth! The words "f--k" and "s--t" are not allowed here.
|
||||
"""
|
||||
field_data = field_data.lower() # normalize
|
||||
words_seen = [w for w in settings.PROFANITIES_LIST if field_data.find(w) > -1]
|
||||
words_seen = [w for w in settings.PROFANITIES_LIST if w in field_data]
|
||||
if words_seen:
|
||||
from django.utils.text import get_text_list
|
||||
plural = len(words_seen) > 1
|
||||
@ -377,7 +377,7 @@ class IsValidFloat(object):
|
||||
if len(data) > max_allowed_length:
|
||||
raise ValidationError, ngettext("Please enter a valid decimal number with at most %s total digit.",
|
||||
"Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits
|
||||
if (not '.' in data and len(data) > (max_allowed_length - self.decimal_places)) or ('.' in data and len(data) > (self.max_digits - (self.decimal_places - len(data.split('.')[1])) + 1)):
|
||||
if (not '.' in data and len(data) > (max_allowed_length - self.decimal_places - 1)) or ('.' in data and len(data) > (max_allowed_length - (self.decimal_places - len(data.split('.')[1])))):
|
||||
raise ValidationError, ngettext( "Please enter a valid decimal number with a whole part of at most %s digit.",
|
||||
"Please enter a valid decimal number with a whole part of at most %s digits.", str(self.max_digits-self.decimal_places)) % str(self.max_digits-self.decimal_places)
|
||||
if '.' in data and len(data.split('.')[1]) > self.decimal_places:
|
||||
|
@ -13,6 +13,7 @@ except ImportError, e:
|
||||
from MySQLdb.converters import conversions
|
||||
from MySQLdb.constants import FIELD_TYPE
|
||||
import types
|
||||
import re
|
||||
|
||||
DatabaseError = Database.DatabaseError
|
||||
|
||||
@ -24,6 +25,12 @@ django_conversions.update({
|
||||
FIELD_TYPE.TIME: util.typecast_time,
|
||||
})
|
||||
|
||||
# This should match the numerical portion of the version numbers (we can treat
|
||||
# versions like 5.0.24 and 5.0.24a as the same). Based on the list of version
|
||||
# at http://dev.mysql.com/doc/refman/4.1/en/news.html and
|
||||
# http://dev.mysql.com/doc/refman/5.0/en/news.html .
|
||||
server_version_re = re.compile(r'(\d{1,2})\.(\d{1,2})\.(\d{1,2})')
|
||||
|
||||
# This is an extra debug layer over MySQL queries, to display warnings.
|
||||
# It's only used when DEBUG=True.
|
||||
class MysqlDebugWrapper:
|
||||
@ -61,6 +68,7 @@ class DatabaseWrapper(local):
|
||||
def __init__(self):
|
||||
self.connection = None
|
||||
self.queries = []
|
||||
self.server_version = None
|
||||
|
||||
def _valid_connection(self):
|
||||
if self.connection is not None:
|
||||
@ -110,6 +118,16 @@ class DatabaseWrapper(local):
|
||||
self.connection.close()
|
||||
self.connection = None
|
||||
|
||||
def get_server_version(self):
|
||||
if not self.server_version:
|
||||
if not self._valid_connection():
|
||||
self.cursor()
|
||||
m = server_version_re.match(self.connection.get_server_info())
|
||||
if not m:
|
||||
raise Exception('Unable to determine MySQL version from version string %r' % self.connection.get_server_info())
|
||||
self.server_version = tuple([int(x) for x in m.groups()])
|
||||
return self.server_version
|
||||
|
||||
supports_constraints = True
|
||||
|
||||
def quote_name(name):
|
||||
|
@ -5,6 +5,7 @@ from django.core import validators
|
||||
from django import forms
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.utils.functional import curry
|
||||
from django.utils.itercompat import tee
|
||||
from django.utils.text import capfirst
|
||||
from django.utils.translation import gettext, gettext_lazy
|
||||
import datetime, os, time
|
||||
@ -80,7 +81,7 @@ class Field(object):
|
||||
self.prepopulate_from = prepopulate_from
|
||||
self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month
|
||||
self.unique_for_year = unique_for_year
|
||||
self.choices = choices or []
|
||||
self._choices = choices or []
|
||||
self.radio_admin = radio_admin
|
||||
self.help_text = help_text
|
||||
self.db_column = db_column
|
||||
@ -324,6 +325,14 @@ class Field(object):
|
||||
def bind(self, fieldmapping, original, bound_field_class):
|
||||
return bound_field_class(self, fieldmapping, original)
|
||||
|
||||
def _get_choices(self):
|
||||
if hasattr(self._choices, 'next'):
|
||||
choices, self._choices = tee(self._choices)
|
||||
return choices
|
||||
else:
|
||||
return self._choices
|
||||
choices = property(_get_choices)
|
||||
|
||||
class AutoField(Field):
|
||||
empty_strings_allowed = False
|
||||
def __init__(self, *args, **kwargs):
|
||||
@ -367,8 +376,8 @@ class BooleanField(Field):
|
||||
|
||||
def to_python(self, value):
|
||||
if value in (True, False): return value
|
||||
if value in ('t', 'True'): return True
|
||||
if value in ('f', 'False'): return False
|
||||
if value in ('t', 'True', '1'): return True
|
||||
if value in ('f', 'False', '0'): return False
|
||||
raise validators.ValidationError, gettext("This value must be either True or False.")
|
||||
|
||||
def get_manipulator_field_objs(self):
|
||||
|
@ -618,7 +618,7 @@ class ManyToManyField(RelatedField, Field):
|
||||
msg = gettext_lazy('Separate multiple IDs with commas.')
|
||||
else:
|
||||
msg = gettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.')
|
||||
self.help_text = string_concat(self.help_text, msg)
|
||||
self.help_text = string_concat(self.help_text, ' ', msg)
|
||||
|
||||
def get_manipulator_field_objs(self):
|
||||
if self.rel.raw_id_admin:
|
||||
|
@ -177,7 +177,7 @@ class AutomaticManipulator(forms.Manipulator):
|
||||
# case, because they'll be dealt with later.
|
||||
|
||||
if f == related.field:
|
||||
param = getattr(new_object, related.field.rel.field_name)
|
||||
param = getattr(new_object, related.field.rel.get_related_field().attname)
|
||||
elif (not self.change) and isinstance(f, AutoField):
|
||||
param = None
|
||||
elif self.change and (isinstance(f, FileField) or not child_follow.get(f.name, None)):
|
||||
@ -215,7 +215,10 @@ class AutomaticManipulator(forms.Manipulator):
|
||||
# Save many-to-many objects.
|
||||
for f in related.opts.many_to_many:
|
||||
if child_follow.get(f.name, None) and not f.rel.edit_inline:
|
||||
setattr(new_rel_obj, f.name, f.rel.to.objects.filter(pk__in=rel_new_data[f.attname]))
|
||||
new_value = rel_new_data[f.attname]
|
||||
if f.rel.raw_id_admin:
|
||||
new_value = new_value[0]
|
||||
setattr(new_rel_obj, f.name, f.rel.to.objects.filter(pk__in=new_value))
|
||||
if self.change:
|
||||
self.fields_changed.append('%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj))
|
||||
|
||||
@ -300,7 +303,7 @@ def manipulator_validator_unique_together(field_name_list, opts, self, field_dat
|
||||
pass
|
||||
else:
|
||||
raise validators.ValidationError, _("%(object)s with this %(type)s already exists for the given %(field)s.") % \
|
||||
{'object': capfirst(opts.verbose_name), 'type': field_list[0].verbose_name, 'field': get_text_list(field_name_list[1:], 'and')}
|
||||
{'object': capfirst(opts.verbose_name), 'type': field_list[0].verbose_name, 'field': get_text_list([f.verbose_name for f in field_list[1:]], 'and')}
|
||||
|
||||
def manipulator_validator_unique_for_date(from_field, date_field, opts, lookup_type, self, field_data, all_data):
|
||||
from django.db.models.fields.related import ManyToOneRel
|
||||
|
@ -707,7 +707,6 @@ def parse_lookup(kwarg_items, opts):
|
||||
joins, where, params = SortedDict(), [], []
|
||||
|
||||
for kwarg, value in kwarg_items:
|
||||
if value is not None:
|
||||
path = kwarg.split(LOOKUP_SEPARATOR)
|
||||
# Extract the last elements of the kwarg.
|
||||
# The very-last is the lookup_type (equals, like, etc).
|
||||
@ -727,6 +726,12 @@ def parse_lookup(kwarg_items, opts):
|
||||
if len(path) < 1:
|
||||
raise TypeError, "Cannot parse keyword query %r" % kwarg
|
||||
|
||||
if value is None:
|
||||
# Interpret '__exact=None' as the sql '= NULL'; otherwise, reject
|
||||
# all uses of None as a query value.
|
||||
if lookup_type != 'exact':
|
||||
raise ValueError, "Cannot use None as a query value"
|
||||
|
||||
joins2, where2, params2 = lookup_inner(path, lookup_type, value, opts, opts.db_table, None)
|
||||
joins.update(joins2)
|
||||
where.extend(where2)
|
||||
|
@ -54,6 +54,7 @@ class Manipulator(object):
|
||||
def get_validation_errors(self, new_data):
|
||||
"Returns dictionary mapping field_names to error-message lists"
|
||||
errors = {}
|
||||
self.prepare(new_data)
|
||||
for field in self.fields:
|
||||
errors.update(field.get_validation_errors(new_data))
|
||||
val_name = 'validate_%s' % field.field_name
|
||||
@ -638,7 +639,7 @@ class CheckboxSelectMultipleField(SelectMultipleField):
|
||||
if str(value) in str_data_list:
|
||||
checked_html = ' checked="checked"'
|
||||
field_name = '%s%s' % (self.field_name, value)
|
||||
output.append('<li><input type="checkbox" id="%s" class="v%s" name="%s"%s /> <label for="%s">%s</label></li>' % \
|
||||
output.append('<li><input type="checkbox" id="%s" class="v%s" name="%s"%s value="on" /> <label for="%s">%s</label></li>' % \
|
||||
(self.get_id() + escape(value), self.__class__.__name__, field_name, checked_html,
|
||||
self.get_id() + escape(value), choice))
|
||||
output.append('</ul>')
|
||||
|
@ -2,6 +2,7 @@ from django.conf import settings
|
||||
from django import http
|
||||
from django.core.mail import mail_managers
|
||||
import md5
|
||||
import re
|
||||
|
||||
class CommonMiddleware(object):
|
||||
"""
|
||||
@ -61,12 +62,12 @@ class CommonMiddleware(object):
|
||||
# send a note to the managers.
|
||||
domain = http.get_host(request)
|
||||
referer = request.META.get('HTTP_REFERER', None)
|
||||
is_internal = referer and (domain in referer)
|
||||
is_internal = _is_internal_request(domain, referer)
|
||||
path = request.get_full_path()
|
||||
if referer and not _is_ignorable_404(path) and (is_internal or '?' not in referer):
|
||||
ua = request.META.get('HTTP_USER_AGENT','<none>')
|
||||
ua = request.META.get('HTTP_USER_AGENT', '<none>')
|
||||
mail_managers("Broken %slink on %s" % ((is_internal and 'INTERNAL ' or ''), domain),
|
||||
"Referrer: %s\nRequested URL: %s\nUser Agent: %s\n" % (referer, request.get_full_path(), ua))
|
||||
"Referrer: %s\nRequested URL: %s\nUser agent: %s\n" % (referer, request.get_full_path(), ua))
|
||||
return response
|
||||
|
||||
# Use ETags, if requested.
|
||||
@ -88,3 +89,8 @@ def _is_ignorable_404(uri):
|
||||
if uri.endswith(end):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _is_internal_request(domain, referer):
|
||||
"Return true if the referring URL is the same domain as the current request"
|
||||
# Different subdomains are treated as different domains.
|
||||
return referer is not None and re.match("^https?://%s/" % re.escape(domain), referer)
|
||||
|
@ -532,7 +532,7 @@ class FilterExpression(object):
|
||||
constant_arg, i18n_arg, var_arg = match.group("constant_arg", "i18n_arg", "var_arg")
|
||||
if i18n_arg:
|
||||
args.append((False, _(i18n_arg.replace(r'\"', '"'))))
|
||||
elif constant_arg:
|
||||
elif constant_arg is not None:
|
||||
args.append((False, constant_arg.replace(r'\"', '"')))
|
||||
elif var_arg:
|
||||
args.append((True, var_arg))
|
||||
|
@ -24,7 +24,7 @@ class ClientHandler(BaseHandler):
|
||||
dispatcher.send(signal=signals.request_started)
|
||||
try:
|
||||
request = WSGIRequest(environ)
|
||||
response = self.get_response(request.path, request)
|
||||
response = self.get_response(request)
|
||||
|
||||
# Apply response middleware
|
||||
for middleware_method in self._response_middleware:
|
||||
|
31
django/utils/itercompat.py
Normal file
31
django/utils/itercompat.py
Normal file
@ -0,0 +1,31 @@
|
||||
"""
|
||||
Providing iterator functions that are not in all version of Python we support.
|
||||
Where possible, we try to use the system-native version and only fall back to
|
||||
these implementations if necessary.
|
||||
"""
|
||||
|
||||
import itertools
|
||||
|
||||
def compat_tee(iterable):
|
||||
"""Return two independent iterators from a single iterable.
|
||||
|
||||
Based on http://www.python.org/doc/2.3.5/lib/itertools-example.html
|
||||
"""
|
||||
# Note: Using a dictionary and a list as the default arguments here is
|
||||
# deliberate and safe in this instance.
|
||||
def gen(next, data={}, cnt=[0]):
|
||||
dpop = data.pop
|
||||
for i in itertools.count():
|
||||
if i == cnt[0]:
|
||||
item = data[i] = next()
|
||||
cnt[0] += 1
|
||||
else:
|
||||
item = dpop(i)
|
||||
yield item
|
||||
next = iter(iterable).next
|
||||
return gen(next), gen(next)
|
||||
|
||||
if hasattr(itertools, 'tee'):
|
||||
tee = itertools.tee
|
||||
else:
|
||||
tee = compat_tee
|
@ -102,7 +102,7 @@ def update_object(request, model, object_id=None, slug=None,
|
||||
except ObjectDoesNotExist:
|
||||
raise Http404, "No %s found for %s" % (model._meta.verbose_name, lookup_kwargs)
|
||||
|
||||
manipulator = model.ChangeManipulator(getattr(object, object._meta.pk.name), follow=follow)
|
||||
manipulator = model.ChangeManipulator(getattr(object, object._meta.pk.attname), follow=follow)
|
||||
|
||||
if request.POST:
|
||||
new_data = request.POST.copy()
|
||||
@ -142,7 +142,7 @@ def update_object(request, model, object_id=None, slug=None,
|
||||
else:
|
||||
c[key] = value
|
||||
response = HttpResponse(t.render(c))
|
||||
populate_xheaders(request, response, model, getattr(object, object._meta.pk.name))
|
||||
populate_xheaders(request, response, model, getattr(object, object._meta.pk.attname))
|
||||
return response
|
||||
|
||||
def delete_object(request, model, post_delete_redirect,
|
||||
@ -196,5 +196,5 @@ def delete_object(request, model, post_delete_redirect,
|
||||
else:
|
||||
c[key] = value
|
||||
response = HttpResponse(t.render(c))
|
||||
populate_xheaders(request, response, model, getattr(object, object._meta.pk.name))
|
||||
populate_xheaders(request, response, model, getattr(object, object._meta.pk.attname))
|
||||
return response
|
||||
|
@ -82,7 +82,7 @@ There are also a few styles for styling text.
|
||||
.help
|
||||
This is a custom class for blocks of inline help text explaining the
|
||||
function of form elements. It makes text smaller and gray, and when applied
|
||||
to ``p`` elements withing ``.form-row`` elements (see Form Styles below),
|
||||
to ``p`` elements within ``.form-row`` elements (see Form Styles below),
|
||||
it will offset the text to align with the form field. Use this for help
|
||||
text, instead of ``small quiet``. It works on other elements, but try to
|
||||
put the class on a ``p`` whenever you can.
|
||||
|
@ -6,7 +6,7 @@ Since keeping multiple authentication databases in sync is a common problem when
|
||||
dealing with Apache, you can configuring Apache to authenticate against Django's
|
||||
`authentication system`_ directly. For example, you could:
|
||||
|
||||
* Serve media files directly from Apache only to authenticated users.
|
||||
* Serve static/media files directly from Apache only to authenticated users.
|
||||
|
||||
* Authenticate access to a Subversion_ repository against Django users with
|
||||
a certain permission.
|
||||
|
@ -82,7 +82,7 @@ that 90% of Django can be considered forwards-compatible at this point.
|
||||
That said, these APIs should *not* be considered stable, and are likely to
|
||||
change:
|
||||
|
||||
- `Forms and validation`_ will most likely be compeltely rewritten to
|
||||
- `Forms and validation`_ will most likely be completely rewritten to
|
||||
deemphasize Manipulators in favor of validation-aware models.
|
||||
|
||||
- `Serialization`_ is under heavy development; changes are likely.
|
||||
@ -91,7 +91,7 @@ change:
|
||||
API changes may be necessary.
|
||||
|
||||
- Generic relations will most likely be moved out of core and into the
|
||||
content-types contrib package to avoid core dependacies on optional
|
||||
content-types contrib package to avoid core dependancies on optional
|
||||
components.
|
||||
|
||||
- The comments framework, which is yet undocumented, will likely get a complete
|
||||
|
@ -66,8 +66,8 @@ Fields
|
||||
long and can contain any character. See the "Passwords" section below.
|
||||
* ``is_staff`` -- Boolean. Designates whether this user can access the
|
||||
admin site.
|
||||
* ``is_active`` -- Boolean. Designates whether this user can log into the
|
||||
Django admin. Set this to ``False`` instead of deleting accounts.
|
||||
* ``is_active`` -- Boolean. Designates whether this account can be used
|
||||
to log in. Set this flag to ``False`` instead of deleting accounts.
|
||||
* ``is_superuser`` -- Boolean. Designates that this user has all permissions
|
||||
without explicitly assigning them.
|
||||
* ``last_login`` -- A datetime of the user's last login. Is set to the
|
||||
@ -99,7 +99,9 @@ custom methods:
|
||||
should prefer using ``is_authenticated()`` to this method.
|
||||
|
||||
* ``is_authenticated()`` -- Always returns ``True``. This is a way to
|
||||
tell if the user has been authenticated.
|
||||
tell if the user has been authenticated. This does not imply any
|
||||
permissions, and doesn't check if the user is active - it only indicates
|
||||
that the user has provided a valid username and password.
|
||||
|
||||
* ``get_full_name()`` -- Returns the ``first_name`` plus the ``last_name``,
|
||||
with a space in between.
|
||||
@ -120,13 +122,16 @@ custom methods:
|
||||
|
||||
* ``has_perm(perm)`` -- Returns ``True`` if the user has the specified
|
||||
permission, where perm is in the format ``"package.codename"``.
|
||||
If the user is inactive, this method will always return ``False``.
|
||||
|
||||
* ``has_perms(perm_list)`` -- Returns ``True`` if the user has each of the
|
||||
specified permissions, where each perm is in the format
|
||||
``"package.codename"``.
|
||||
``"package.codename"``. If the user is inactive, this method will
|
||||
always return ``False``.
|
||||
|
||||
* ``has_module_perms(package_name)`` -- Returns ``True`` if the user has
|
||||
any permissions in the given package (the Django app label).
|
||||
If the user is inactive, this method will always return ``False``.
|
||||
|
||||
* ``get_and_delete_messages()`` -- Returns a list of ``Message`` objects in
|
||||
the user's queue and deletes the messages from the queue.
|
||||
@ -283,7 +288,10 @@ password is invalid, ``authenticate()`` returns ``None``. Example::
|
||||
from django.contrib.auth import authenticate
|
||||
user = authenticate(username='john', password='secret')
|
||||
if user is not None:
|
||||
if user.is_active:
|
||||
print "You provided a correct username and password!"
|
||||
else:
|
||||
print "Your account has been disabled!"
|
||||
else:
|
||||
print "Your username and password were incorrect."
|
||||
|
||||
@ -301,10 +309,13 @@ This example shows how you might use both ``authenticate()`` and ``login()``::
|
||||
password = request.POST['password']
|
||||
user = authenticate(username=username, password=password)
|
||||
if user is not None:
|
||||
if user.is_active:
|
||||
login(request, user)
|
||||
# Redirect to a success page.
|
||||
else:
|
||||
# Return an error message.
|
||||
# Return a 'disabled account' error message
|
||||
else:
|
||||
# Return an 'invalid login' error message.
|
||||
|
||||
How to log a user out
|
||||
---------------------
|
||||
@ -456,9 +467,9 @@ As a shortcut, you can use the convenient ``user_passes_test`` decorator::
|
||||
# ...
|
||||
my_view = user_passes_test(lambda u: u.has_perm('polls.can_vote'))(my_view)
|
||||
|
||||
We are using this particular test as a relatively simple example, however be
|
||||
aware that if you just want to test if a permission is available to a user,
|
||||
you can use the ``permission_required()`` decorator described below.
|
||||
We're using this particular test as a relatively simple example. However, if
|
||||
you just want to test whether a permission is available to a user, you can use
|
||||
the ``permission_required()`` decorator, described later in this document.
|
||||
|
||||
Here's the same thing, using Python 2.4's decorator syntax::
|
||||
|
||||
@ -495,20 +506,30 @@ Example in Python 2.4 syntax::
|
||||
The permission_required decorator
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Since checking whether a user has a particular permission available to them is a
|
||||
relatively common operation, Django provides a shortcut for that particular
|
||||
case: the ``permission_required()`` decorator. Using this decorator, the
|
||||
earlier example can be written as::
|
||||
**New in Django development version**
|
||||
|
||||
It's a relatively common task to check whether a user has a particular
|
||||
permission. For that reason, Django provides a shortcut for that case: the
|
||||
``permission_required()`` decorator. Using this decorator, the earlier example
|
||||
can be written as::
|
||||
|
||||
from django.contrib.auth.decorators import permission_required
|
||||
|
||||
def my_view(request):
|
||||
# ...
|
||||
|
||||
my_view = permission_required('polls.can_vote')(my_view)
|
||||
|
||||
Note that ``permission_required()`` also takes an optional ``login_url``
|
||||
parameter.
|
||||
parameter. Example::
|
||||
|
||||
from django.contrib.auth.decorators import permission_required
|
||||
|
||||
def my_view(request):
|
||||
# ...
|
||||
my_view = permission_required('polls.can_vote', login_url='/loginpage/')(my_view)
|
||||
|
||||
As in the ``login_required`` decorator, ``login_url`` defaults to
|
||||
``'/accounts/login/'``.
|
||||
|
||||
Limiting access to generic views
|
||||
--------------------------------
|
||||
|
@ -259,10 +259,10 @@ The tests cover:
|
||||
We appreciate any and all contributions to the test suite!
|
||||
|
||||
The Django tests all use the testing infrastructure that ships with Django for
|
||||
testing applications. See `Testing Django Applications`_ for an explanation of
|
||||
testing applications. See `Testing Django applications`_ for an explanation of
|
||||
how to write new tests.
|
||||
|
||||
.. _Testing Django Applications: http://www.djangoproject.com/documentation/testing/
|
||||
.. _Testing Django applications: http://www.djangoproject.com/documentation/testing/
|
||||
|
||||
Running the unit tests
|
||||
----------------------
|
||||
@ -273,7 +273,7 @@ To run the tests, ``cd`` to the ``tests/`` directory and type::
|
||||
|
||||
Yes, the unit tests need a settings module, but only for database connection
|
||||
info -- the ``DATABASE_ENGINE``, ``DATABASE_USER`` and ``DATABASE_PASSWORD``.
|
||||
You will also need a ``ROOT_URLCONF`` setting (it's value is ignored; it just
|
||||
You will also need a ``ROOT_URLCONF`` setting (its value is ignored; it just
|
||||
needs to be present) and a ``SITE_ID`` setting (any integer value will do) in
|
||||
order for all the tests to pass.
|
||||
|
||||
|
@ -876,15 +876,18 @@ The database API supports the following lookup types:
|
||||
exact
|
||||
~~~~~
|
||||
|
||||
Exact match.
|
||||
Exact match. If the value provided for comparison is ``None``, it will
|
||||
be interpreted as an SQL ``NULL`` (See isnull_ for more details).
|
||||
|
||||
Example::
|
||||
Examples::
|
||||
|
||||
Entry.objects.get(id__exact=14)
|
||||
Entry.objects.get(id__exact=None)
|
||||
|
||||
SQL equivalent::
|
||||
SQL equivalents::
|
||||
|
||||
SELECT ... WHERE id = 14;
|
||||
SELECT ... WHERE id = NULL;
|
||||
|
||||
iexact
|
||||
~~~~~~
|
||||
@ -1103,8 +1106,8 @@ such as January 3, July 3, etc.
|
||||
isnull
|
||||
~~~~~~
|
||||
|
||||
``NULL`` or ``IS NOT NULL`` match. Takes either ``True`` or ``False``, which
|
||||
correspond to ``IS NULL`` and ``IS NOT NULL``, respectively.
|
||||
Takes either ``True`` or ``False``, which correspond to SQL queries of
|
||||
``IS NULL`` and ``IS NOT NULL``, respectively.
|
||||
|
||||
Example::
|
||||
|
||||
@ -1114,6 +1117,14 @@ SQL equivalent::
|
||||
|
||||
SELECT ... WHERE pub_date IS NULL;
|
||||
|
||||
.. admonition:: ``__isnull=True`` vs ``__exact=None``
|
||||
|
||||
There is an important difference between ``__isnull=True`` and
|
||||
``__exact=None``. ``__exact=None`` will *always* return an empty result
|
||||
set, because SQL requires that no value is equal to ``NULL``.
|
||||
``__isnull`` determines if the field is currently holding the value
|
||||
of ``NULL`` without performing a comparison.
|
||||
|
||||
search
|
||||
~~~~~~
|
||||
|
||||
|
@ -392,10 +392,10 @@ and `2` is verbose output.
|
||||
Example usage::
|
||||
django-admin.py manage.py --adminmedia=/tmp/new-admin-style/
|
||||
|
||||
Tell Django where to find the various stylesheets and Javascript files for the
|
||||
admin interface when running the development server. Normally these files are
|
||||
served out of the Django source tree, but since some designers change these
|
||||
files for their site, this option allows you to test against custom versions.
|
||||
Tells Django where to find the various CSS and JavaScript files for the admin
|
||||
interface when running the development server. Normally these files are served
|
||||
out of the Django source tree, but because some designers customize these files
|
||||
for their site, this option allows you to test against custom versions.
|
||||
|
||||
Extra niceties
|
||||
==============
|
||||
|
18
docs/faq.txt
18
docs/faq.txt
@ -227,9 +227,7 @@ When will you release Django 1.0?
|
||||
|
||||
Short answer: When we're comfortable with Django's APIs, have added all
|
||||
features that we feel are necessary to earn a "1.0" status, and are ready to
|
||||
begin maintaining backwards compatibility. This should happen in a couple of
|
||||
months or so, although it's entirely possible that it could happen earlier.
|
||||
That translates into summer 2006.
|
||||
begin maintaining backwards compatibility.
|
||||
|
||||
The merging of Django's `magic-removal branch`_ went a long way toward Django
|
||||
1.0.
|
||||
@ -313,6 +311,18 @@ PostgreSQL fans, and MySQL_ and `SQLite 3`_ are also supported.
|
||||
.. _MySQL: http://www.mysql.com/
|
||||
.. _`SQLite 3`: http://www.sqlite.org/
|
||||
|
||||
Do I lose anything by using Python 2.3 versus newer Python versions, such as Python 2.5?
|
||||
----------------------------------------------------------------------------------------
|
||||
|
||||
No. Django itself is guaranteed to work with any version of Python from 2.3
|
||||
and higher.
|
||||
|
||||
If you use a Python version newer than 2.3, you will, of course, be able to
|
||||
take advantage of newer Python features in your own code, along with the speed
|
||||
improvements and other optimizations that have been made to the Python language
|
||||
itself. But the Django framework itself should work equally well on 2.3 as it
|
||||
does on 2.4 or 2.5.
|
||||
|
||||
Do I have to use mod_python?
|
||||
----------------------------
|
||||
|
||||
@ -487,7 +497,7 @@ specify an object to edit or delete.
|
||||
How do I add database-specific options to my CREATE TABLE statements, such as specifying MyISAM as the table type?
|
||||
------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
We try to avoid adding special cases in the Django code to accomodate all the
|
||||
We try to avoid adding special cases in the Django code to accommodate all the
|
||||
database-specific options such as table type, etc. If you'd like to use any of
|
||||
these options, create an `SQL initial data file`_ that contains ``ALTER TABLE``
|
||||
statements that do what you want to do. The initial data files are executed in
|
||||
|
@ -211,7 +211,7 @@ Below is the finished view::
|
||||
def create_place(request):
|
||||
manipulator = Place.AddManipulator()
|
||||
|
||||
if request.POST:
|
||||
if request.method == 'POST':
|
||||
# If data was POSTed, we're trying to create a new Place.
|
||||
new_data = request.POST.copy()
|
||||
|
||||
@ -309,7 +309,7 @@ about editing an existing one? It's shockingly similar to creating a new one::
|
||||
# Grab the Place object in question for future use.
|
||||
place = manipulator.original_object
|
||||
|
||||
if request.POST:
|
||||
if request.method == 'POST':
|
||||
new_data = request.POST.copy()
|
||||
errors = manipulator.get_validation_errors(new_data)
|
||||
if not errors:
|
||||
@ -391,7 +391,7 @@ Here's a simple function that might drive the above form::
|
||||
|
||||
def contact_form(request):
|
||||
manipulator = ContactManipulator()
|
||||
if request.POST:
|
||||
if request.method == 'POST':
|
||||
new_data = request.POST.copy()
|
||||
errors = manipulator.get_validation_errors(new_data)
|
||||
if not errors:
|
||||
@ -481,15 +481,15 @@ the data being validated.
|
||||
Also, because consistency in user interfaces is important, we strongly urge you
|
||||
to put punctuation at the end of your validation messages.
|
||||
|
||||
When Are Validators Called?
|
||||
When are validators called?
|
||||
---------------------------
|
||||
|
||||
After a form has been submitted, Django first checks to see that all the
|
||||
required fields are present and non-empty. For each field that passes that
|
||||
test *and if the form submission contained data* for that field, all the
|
||||
validators for that field are called in turn. The emphasised portion in the
|
||||
validators for that field are called in turn. The emphasized portion in the
|
||||
last sentence is important: if a form field is not submitted (because it
|
||||
contains no data -- which is normal HTML behaviour), the validators are not
|
||||
contains no data -- which is normal HTML behavior), the validators are not
|
||||
run against the field.
|
||||
|
||||
This feature is particularly important for models using
|
||||
@ -497,18 +497,17 @@ This feature is particularly important for models using
|
||||
``forms.CheckBoxField``. If the checkbox is not selected, it will not
|
||||
contribute to the form submission.
|
||||
|
||||
If you would like your validator to *always* run, regardless of whether the
|
||||
field it is attached to contains any data, set the ``always_test`` attribute
|
||||
on the validator function. For example::
|
||||
If you would like your validator to run *always*, regardless of whether its
|
||||
attached field contains any data, set the ``always_test`` attribute on the
|
||||
validator function. For example::
|
||||
|
||||
def my_custom_validator(field_data, all_data):
|
||||
# ...
|
||||
|
||||
my_custom_validator.always_test = True
|
||||
|
||||
This validator will always be executed for any field it is attached to.
|
||||
|
||||
Ready-made Validators
|
||||
Ready-made validators
|
||||
---------------------
|
||||
|
||||
Writing your own validator is not difficult, but there are some situations
|
||||
@ -580,7 +579,7 @@ fails. If no message is passed in, a default message is used.
|
||||
``ValidateIfOtherFieldEquals``
|
||||
Takes three parameters: ``other_field``, ``other_value`` and
|
||||
``validator_list``, in that order. If ``other_field`` has a value of
|
||||
``other_vaue``, then the validators in ``validator_list`` are all run
|
||||
``other_value``, then the validators in ``validator_list`` are all run
|
||||
against the current field.
|
||||
|
||||
``RequiredIfOtherFieldNotGiven``
|
||||
|
@ -184,7 +184,7 @@ a date in the *future* are not included unless you set ``allow_future`` to
|
||||
the view's template. See the `RequestContext docs`_.
|
||||
|
||||
* ``mimetype``: The MIME type to use for the resulting document. Defaults
|
||||
to the value of the ``DEFAULT_MIME_TYPE`` setting.
|
||||
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
|
||||
|
||||
* ``allow_future``: A boolean specifying whether to include "future"
|
||||
objects on this page, where "future" means objects in which the field
|
||||
@ -270,7 +270,7 @@ to ``True``.
|
||||
this is ``False``.
|
||||
|
||||
* ``mimetype``: The MIME type to use for the resulting document. Defaults
|
||||
to the value of the ``DEFAULT_MIME_TYPE`` setting.
|
||||
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
|
||||
|
||||
* ``allow_future``: A boolean specifying whether to include "future"
|
||||
objects on this page, where "future" means objects in which the field
|
||||
@ -357,7 +357,7 @@ date in the *future* are not displayed unless you set ``allow_future`` to
|
||||
determining the variable's name.
|
||||
|
||||
* ``mimetype``: The MIME type to use for the resulting document. Defaults
|
||||
to the value of the ``DEFAULT_MIME_TYPE`` setting.
|
||||
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
|
||||
|
||||
* ``allow_future``: A boolean specifying whether to include "future"
|
||||
objects on this page, where "future" means objects in which the field
|
||||
@ -438,7 +438,7 @@ in the *future* are not displayed unless you set ``allow_future`` to ``True``.
|
||||
determining the variable's name.
|
||||
|
||||
* ``mimetype``: The MIME type to use for the resulting document. Defaults
|
||||
to the value of the ``DEFAULT_MIME_TYPE`` setting.
|
||||
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
|
||||
|
||||
* ``allow_future``: A boolean specifying whether to include "future"
|
||||
objects on this page, where "future" means objects in which the field
|
||||
@ -523,7 +523,7 @@ you set ``allow_future`` to ``True``.
|
||||
determining the variable's name.
|
||||
|
||||
* ``mimetype``: The MIME type to use for the resulting document. Defaults
|
||||
to the value of the ``DEFAULT_MIME_TYPE`` setting.
|
||||
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
|
||||
|
||||
* ``allow_future``: A boolean specifying whether to include "future"
|
||||
objects on this page, where "future" means objects in which the field
|
||||
@ -633,7 +633,7 @@ future, the view will throw a 404 error by default, unless you set
|
||||
to use in the template context. By default, this is ``'object'``.
|
||||
|
||||
* ``mimetype``: The MIME type to use for the resulting document. Defaults
|
||||
to the value of the ``DEFAULT_MIME_TYPE`` setting.
|
||||
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
|
||||
|
||||
* ``allow_future``: A boolean specifying whether to include "future"
|
||||
objects on this page, where "future" means objects in which the field
|
||||
@ -707,7 +707,7 @@ A page representing a list of objects.
|
||||
determining the variable's name.
|
||||
|
||||
* ``mimetype``: The MIME type to use for the resulting document. Defaults
|
||||
to the value of the ``DEFAULT_MIME_TYPE`` setting.
|
||||
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
|
||||
|
||||
**Template name:**
|
||||
|
||||
@ -819,7 +819,7 @@ A page representing an individual object.
|
||||
to use in the template context. By default, this is ``'object'``.
|
||||
|
||||
* ``mimetype``: The MIME type to use for the resulting document. Defaults
|
||||
to the value of the ``DEFAULT_MIME_TYPE`` setting.
|
||||
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
|
||||
|
||||
**Template name:**
|
||||
|
||||
|
@ -84,9 +84,12 @@ Installing the official version
|
||||
|
||||
Note that the last command will automatically download and install setuptools_
|
||||
if you don't already have it installed. This requires a working Internet
|
||||
connection and may cause problems on Python 2.5. If you run into problems,
|
||||
try using our development version by following the instructions below. The
|
||||
development version no longer uses setuptools nor requires an Internet
|
||||
connection.
|
||||
|
||||
This will install Django in your Python installation's ``site-packages``
|
||||
The command will install Django in your Python installation's ``site-packages``
|
||||
directory.
|
||||
|
||||
.. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools
|
||||
@ -94,19 +97,34 @@ directory.
|
||||
Installing the development version
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
1. Make sure you have Subversion_ installed.
|
||||
2. ``svn co http://code.djangoproject.com/svn/django/trunk/ django_src``
|
||||
3. Symlink ``django_src/django`` so that ``django`` is within your Python
|
||||
``site-packages`` directory:
|
||||
If you'd like to be able to update your Django code occasionally with the
|
||||
latest bug fixes and improvements, follow these instructions:
|
||||
|
||||
``ln -s `pwd`/django_src/django /usr/lib/python2.3/site-packages/django``
|
||||
1. Make sure you have Subversion_ installed.
|
||||
2. Check out the Django code into your Python ``site-packages`` directory.
|
||||
On Linux / Mac OSX / Unix, do this::
|
||||
|
||||
svn co http://code.djangoproject.com/svn/django/trunk/ django_src
|
||||
ln -s `pwd`/django_src/django /usr/lib/python2.3/site-packages/django
|
||||
|
||||
(In the above line, change ``python2.3`` to match your current Python version.)
|
||||
|
||||
You don't have to run ``python setup.py install``.
|
||||
On Windows, do this::
|
||||
|
||||
When you want to update your code, just run the command ``svn update`` from
|
||||
within the ``django_src`` directory.
|
||||
svn co http://code.djangoproject.com/svn/django/trunk/django c:\Python24\lib\site-packages\django
|
||||
|
||||
4. Copy the file ``django_src/django/bin/django-admin.py`` to somewhere on your
|
||||
system path, such as ``/usr/local/bin`` (Unix) or ``C:\Python24\Scripts``
|
||||
(Windows). This step simply lets you type ``django-admin.py`` from within
|
||||
any directory, rather than having to qualify the command with the full path
|
||||
to the file.
|
||||
|
||||
You *don't* have to run ``python setup.py install``, because that command
|
||||
takes care of steps 3 and 4 for you.
|
||||
|
||||
When you want to update your copy of the Django source code, just run the
|
||||
command ``svn update`` from within the ``django`` directory. When you do this,
|
||||
Subversion will automatically download any changes.
|
||||
|
||||
.. _`download page`: http://www.djangoproject.com/download/
|
||||
.. _Subversion: http://subversion.tigris.org/
|
||||
|
@ -188,7 +188,8 @@ JavaScript shortcuts.
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
A ``CharField`` that checks that the value is a valid e-mail address.
|
||||
This doesn't accept ``maxlength``.
|
||||
This doesn't accept ``maxlength``; its ``maxlength`` is automatically set to
|
||||
75.
|
||||
|
||||
``FileField``
|
||||
~~~~~~~~~~~~~
|
||||
|
@ -110,7 +110,7 @@ many common questions appear with some regularity, and any particular problem
|
||||
may already have been answered.
|
||||
|
||||
Finally, for those who prefer the more immediate feedback offered by IRC,
|
||||
there's a #django channel or irc.freenode.net that is regularly populated by
|
||||
there's a #django channel on irc.freenode.net that is regularly populated by
|
||||
Django users and developers from around the world. Friendly people are usually
|
||||
available at any hour of the day -- to help, or just to chat.
|
||||
|
||||
|
@ -341,9 +341,9 @@ hard-coded strings. If you use this technique, follow these guidelines:
|
||||
Methods
|
||||
-------
|
||||
|
||||
``__init__(content='', mimetype=DEFAULT_MIME_TYPE)``
|
||||
``__init__(content='', mimetype=DEFAULT_CONTENT_TYPE)``
|
||||
Instantiates an ``HttpResponse`` object with the given page content (a
|
||||
string) and MIME type. The ``DEFAULT_MIME_TYPE`` is ``'text/html'``.
|
||||
string) and MIME type. The ``DEFAULT_CONTENT_TYPE`` is ``'text/html'``.
|
||||
|
||||
``content`` can be an iterator or a string. If it's an iterator, it should
|
||||
return strings, and those strings will be joined together to form the
|
||||
|
@ -96,15 +96,15 @@ Django "ships" with a few included serializers:
|
||||
.. _json: http://json.org/
|
||||
.. _simplejson: http://undefined.org/python/#simplejson
|
||||
|
||||
Notes For Specific Serialization Formats
|
||||
Notes for specific serialization formats
|
||||
----------------------------------------
|
||||
|
||||
json
|
||||
~~~~
|
||||
|
||||
If you are using UTF-8 (or any other non-ASCII encoding) data with the JSON
|
||||
If you're using UTF-8 (or any other non-ASCII encoding) data with the JSON
|
||||
serializer, you must pass ``ensure_ascii=False`` as a parameter to the
|
||||
``serialize()`` call. Otherwise the output will not be encoded correctly.
|
||||
``serialize()`` call. Otherwise, the output won't be encoded correctly.
|
||||
|
||||
For example::
|
||||
|
||||
|
@ -401,15 +401,6 @@ Subject-line prefix for e-mail messages sent with ``django.core.mail.mail_admins
|
||||
or ``django.core.mail.mail_managers``. You'll probably want to include the
|
||||
trailing space.
|
||||
|
||||
ENABLE_PSYCO
|
||||
------------
|
||||
|
||||
Default: ``False``
|
||||
|
||||
Whether to enable Psyco, which optimizes Python code. Requires Psyco_.
|
||||
|
||||
.. _Psyco: http://psyco.sourceforge.net/
|
||||
|
||||
IGNORABLE_404_ENDS
|
||||
------------------
|
||||
|
||||
@ -599,8 +590,11 @@ See also ``APPEND_SLASH``.
|
||||
PROFANITIES_LIST
|
||||
----------------
|
||||
|
||||
A list of profanities that will trigger a validation error when the
|
||||
``hasNoProfanities`` validator is called.
|
||||
A tuple of profanities, as strings, that will trigger a validation error when
|
||||
the ``hasNoProfanities`` validator is called.
|
||||
|
||||
We don't list the default values here, because that would be profane. To see
|
||||
the default values, see the file ``django/conf/global_settings.py``.
|
||||
|
||||
ROOT_URLCONF
|
||||
------------
|
||||
|
@ -540,6 +540,11 @@ The arguments can be hard-coded strings, so the following is valid::
|
||||
...
|
||||
{% endifequal %}
|
||||
|
||||
It is only possible to compare an argument to template variables or strings.
|
||||
You cannot check for equality with Python objects such as ``True`` or
|
||||
``False``. If you need to test if something is true or false, use the ``if``
|
||||
and ``ifnot`` tags instead.
|
||||
|
||||
ifnotequal
|
||||
~~~~~~~~~~
|
||||
|
||||
@ -1051,7 +1056,7 @@ Formats a date as the time since that date (i.e. "4 days, 6 hours").
|
||||
Takes an optional argument that is a variable containing the date to use as
|
||||
the comparison point (without the argument, the comparison point is *now*).
|
||||
For example, if ``blog_date`` is a date instance representing midnight on 1
|
||||
June 2006, and ``comment_date`` is a date instanace for 08:00 on 1 June 2006,
|
||||
June 2006, and ``comment_date`` is a date instance for 08:00 on 1 June 2006,
|
||||
then ``{{ comment_date|timesince:blog_date }}`` would return "8 hours".
|
||||
|
||||
timeuntil
|
||||
|
@ -212,6 +212,21 @@ template tags. If an invalid variable is provided to one of these template
|
||||
tags, the variable will be interpreted as ``None``. Filters are always
|
||||
applied to invalid variables within these template tags.
|
||||
|
||||
.. admonition:: For debug purposes only!
|
||||
|
||||
While ``TEMPLATE_STRING_IF_INVALID`` can be a useful debugging tool,
|
||||
it is a bad idea to turn it on as a 'development default'.
|
||||
|
||||
Many templates, including those in the Admin site, rely upon the
|
||||
silence of the template system when a non-existent variable is
|
||||
encountered. If you assign a value other than ``''`` to
|
||||
``TEMPLATE_STRING_IF_INVALID``, you will experience rendering
|
||||
problems with these templates and sites.
|
||||
|
||||
Generally, ``TEMPLATE_STRING_IF_INVALID`` should only be enabled
|
||||
in order to debug a specific template problem, then cleared
|
||||
once debugging is complete.
|
||||
|
||||
Playing with Context objects
|
||||
----------------------------
|
||||
|
||||
@ -296,6 +311,20 @@ optional, third positional argument, ``processors``. In this example, the
|
||||
'foo': 'bar',
|
||||
}, [ip_address_processor])
|
||||
|
||||
Note::
|
||||
If you are using Django's ``render_to_response()`` shortcut to populate a
|
||||
template with the contents of a dictionary, your template will be passed a
|
||||
``Context`` instance by default (not a ``RequestContext``). If you wish to
|
||||
use a ``RequestContext`` in your template rendering, you need to pass an
|
||||
optional third argument to ``render_to_response()``: a ``RequestContext``
|
||||
instance. Your code might look like this::
|
||||
|
||||
def some_view(request):
|
||||
# ...
|
||||
return render_to_response('my_template'html',
|
||||
my_data_dictionary,
|
||||
context_instance = RequestContext(request))
|
||||
|
||||
Here's what each of the default processors does:
|
||||
|
||||
.. _HttpRequest object: http://www.djangoproject.com/documentation/request_response/#httprequest-objects
|
||||
@ -366,6 +395,18 @@ If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every
|
||||
`HttpRequest object`_. Note that this processor is not enabled by default;
|
||||
you'll have to activate it.
|
||||
|
||||
Writing your own context processors
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A context processor has a very simple interface: It's just a Python function
|
||||
that takes one argument, an ``HttpRequest`` object, and returns a dictionary
|
||||
that gets added to the template context. Each context processor *must* return
|
||||
a dictionary.
|
||||
|
||||
Custom context processors can live anywhere in your code base. All Django cares
|
||||
about is that your custom context processors are pointed-to by your
|
||||
``TEMPLATE_CONTEXT_PROCESSORS`` setting.
|
||||
|
||||
Loading templates
|
||||
-----------------
|
||||
|
||||
@ -805,7 +846,7 @@ Inclusion tags
|
||||
|
||||
Another common type of template tag is the type that displays some data by
|
||||
rendering *another* template. For example, Django's admin interface uses custom
|
||||
template tags to display the buttons along the botton of the "add/change" form
|
||||
template tags to display the buttons along the bottom of the "add/change" form
|
||||
pages. Those buttons always look the same, but the link targets change depending
|
||||
on the object being edited -- so they're a perfect case for using a small
|
||||
template that is filled with details from the current object. (In the admin's
|
||||
|
@ -389,7 +389,7 @@ an alternative framework as if they were normal Django tests.
|
||||
|
||||
When you run ``./manage.py test``, Django looks at the ``TEST_RUNNER``
|
||||
setting to determine what to do. By default, ``TEST_RUNNER`` points to ``django.test.simple.run_tests``. This method defines the default Django
|
||||
testing behaviour. This behaviour involves:
|
||||
testing behavior. This behavior involves:
|
||||
|
||||
#. Performing global pre-test setup
|
||||
#. Creating the test database
|
||||
@ -435,7 +435,7 @@ a number of utility methods in the ``django.test.utils`` module.
|
||||
``create_test_db(verbosity=1, autoclobber=False)``
|
||||
Creates a new test database, and run ``syncdb`` against it.
|
||||
|
||||
``verbosity`` has the same behaviour as in the test runner.
|
||||
``verbosity`` has the same behavior as in the test runner.
|
||||
|
||||
``Autoclobber`` describes the behavior that will occur if a database with
|
||||
the same name as the test database is discovered. If ``autoclobber`` is False,
|
||||
@ -450,4 +450,4 @@ a number of utility methods in the ``django.test.utils`` module.
|
||||
Destroys the database with the name ``settings.DATABASE_NAME`` matching,
|
||||
and restores the value of ``settings.DATABASE_NAME`` to the provided name.
|
||||
|
||||
``verbosity`` has the same behaviour as in the test runner.
|
||||
``verbosity`` has the same behavior as in the test runner.
|
||||
|
@ -377,7 +377,7 @@ By default, ``TEMPLATE_DIRS`` is empty. So, let's add a line to it, to tell
|
||||
Django where our templates live::
|
||||
|
||||
TEMPLATE_DIRS = (
|
||||
"/home/mytemplates", # Change this to your own directory.
|
||||
"/home/my_username/mytemplates", # Change this to your own directory.
|
||||
)
|
||||
|
||||
Now copy the template ``admin/base_site.html`` from within the default Django
|
||||
|
@ -91,7 +91,7 @@ Finally, it calls that ``detail()`` function like so::
|
||||
The ``poll_id='23'`` part comes from ``(?P<poll_id>\d+)``. Using parenthesis around a
|
||||
pattern "captures" the text matched by that pattern and sends it as an argument
|
||||
to the view function; the ``?P<poll_id>`` defines the name that will be used to
|
||||
identify the matched pattern; and ``\d+`` is a regular experession to match a sequence of
|
||||
identify the matched pattern; and ``\d+`` is a regular expression to match a sequence of
|
||||
digits (i.e., a number).
|
||||
|
||||
Because the URL patterns are regular expressions, there really is no limit on
|
||||
@ -257,7 +257,7 @@ provides a shortcut. Here's the full ``index()`` view, rewritten::
|
||||
from mysite.polls.models import Poll
|
||||
|
||||
def index(request):
|
||||
latest_poll_list = Poll.objects.all().order_by('-pub_date')
|
||||
latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
|
||||
return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list})
|
||||
|
||||
Note that we no longer need to import ``loader``, ``Context`` or
|
||||
|
@ -207,7 +207,7 @@ for the polls app, we manually specify a template name for the results view:
|
||||
template. Note that we use ``dict()`` to return an altered dictionary in place.
|
||||
|
||||
In previous parts of the tutorial, the templates have been provided with a context
|
||||
that contains the ``poll` and ``latest_poll_list`` context variables. However,
|
||||
that contains the ``poll`` and ``latest_poll_list`` context variables. However,
|
||||
the generic views provide the variables ``object`` and ``object_list`` as context.
|
||||
Therefore, you need to change your templates to match the new context variables.
|
||||
Go through your templates, and modify any reference to ``latest_poll_list`` to
|
||||
|
217
ez_setup.py
217
ez_setup.py
@ -1,217 +0,0 @@
|
||||
#!python
|
||||
"""Bootstrap setuptools installation
|
||||
|
||||
If you want to use setuptools in your package's setup.py, just include this
|
||||
file in the same directory with it, and add this to the top of your setup.py::
|
||||
|
||||
from ez_setup import use_setuptools
|
||||
use_setuptools()
|
||||
|
||||
If you want to require a specific version of setuptools, set a download
|
||||
mirror, or use an alternate download directory, you can do so by supplying
|
||||
the appropriate options to ``use_setuptools()``.
|
||||
|
||||
This file can also be run as a script to install or upgrade setuptools.
|
||||
"""
|
||||
import sys
|
||||
DEFAULT_VERSION = "0.6c1"
|
||||
DEFAULT_URL = "http://cheeseshop.python.org/packages/%s/s/setuptools/" % sys.version[:3]
|
||||
|
||||
md5_data = {
|
||||
'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
|
||||
'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
|
||||
'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
|
||||
'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
|
||||
'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
|
||||
'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
|
||||
'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
|
||||
'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
|
||||
'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
|
||||
'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
|
||||
}
|
||||
|
||||
import sys, os
|
||||
|
||||
def _validate_md5(egg_name, data):
|
||||
if egg_name in md5_data:
|
||||
from md5 import md5
|
||||
digest = md5(data).hexdigest()
|
||||
if digest != md5_data[egg_name]:
|
||||
print >>sys.stderr, (
|
||||
"md5 validation of %s failed! (Possible download problem?)"
|
||||
% egg_name
|
||||
)
|
||||
sys.exit(2)
|
||||
return data
|
||||
|
||||
|
||||
def use_setuptools(
|
||||
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
|
||||
download_delay=15
|
||||
):
|
||||
"""Automatically find/download setuptools and make it available on sys.path
|
||||
|
||||
`version` should be a valid setuptools version number that is available
|
||||
as an egg for download under the `download_base` URL (which should end with
|
||||
a '/'). `to_dir` is the directory where setuptools will be downloaded, if
|
||||
it is not already available. If `download_delay` is specified, it should
|
||||
be the number of seconds that will be paused before initiating a download,
|
||||
should one be required. If an older version of setuptools is installed,
|
||||
this routine will print a message to ``sys.stderr`` and raise SystemExit in
|
||||
an attempt to abort the calling script.
|
||||
"""
|
||||
try:
|
||||
import setuptools
|
||||
if setuptools.__version__ == '0.0.1':
|
||||
print >>sys.stderr, (
|
||||
"You have an obsolete version of setuptools installed. Please\n"
|
||||
"remove it from your system entirely before rerunning this script."
|
||||
)
|
||||
sys.exit(2)
|
||||
except ImportError:
|
||||
egg = download_setuptools(version, download_base, to_dir, download_delay)
|
||||
sys.path.insert(0, egg)
|
||||
import setuptools; setuptools.bootstrap_install_from = egg
|
||||
|
||||
import pkg_resources
|
||||
try:
|
||||
pkg_resources.require("setuptools>="+version)
|
||||
|
||||
except pkg_resources.VersionConflict:
|
||||
# XXX could we install in a subprocess here?
|
||||
print >>sys.stderr, (
|
||||
"The required version of setuptools (>=%s) is not available, and\n"
|
||||
"can't be installed while this script is running. Please install\n"
|
||||
" a more recent version first."
|
||||
) % version
|
||||
sys.exit(2)
|
||||
|
||||
def download_setuptools(
|
||||
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
|
||||
delay = 15
|
||||
):
|
||||
"""Download setuptools from a specified location and return its filename
|
||||
|
||||
`version` should be a valid setuptools version number that is available
|
||||
as an egg for download under the `download_base` URL (which should end
|
||||
with a '/'). `to_dir` is the directory where the egg will be downloaded.
|
||||
`delay` is the number of seconds to pause before an actual download attempt.
|
||||
"""
|
||||
import urllib2, shutil
|
||||
egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
|
||||
url = download_base + egg_name
|
||||
saveto = os.path.join(to_dir, egg_name)
|
||||
src = dst = None
|
||||
if not os.path.exists(saveto): # Avoid repeated downloads
|
||||
try:
|
||||
from distutils import log
|
||||
if delay:
|
||||
log.warn("""
|
||||
---------------------------------------------------------------------------
|
||||
This script requires setuptools version %s to run (even to display
|
||||
help). I will attempt to download it for you (from
|
||||
%s), but
|
||||
you may need to enable firewall access for this script first.
|
||||
I will start the download in %d seconds.
|
||||
|
||||
(Note: if this machine does not have network access, please obtain the file
|
||||
|
||||
%s
|
||||
|
||||
and place it in this directory before rerunning this script.)
|
||||
---------------------------------------------------------------------------""",
|
||||
version, download_base, delay, url
|
||||
); from time import sleep; sleep(delay)
|
||||
log.warn("Downloading %s", url)
|
||||
src = urllib2.urlopen(url)
|
||||
# Read/write all in one block, so we don't create a corrupt file
|
||||
# if the download is interrupted.
|
||||
data = _validate_md5(egg_name, src.read())
|
||||
dst = open(saveto,"wb"); dst.write(data)
|
||||
finally:
|
||||
if src: src.close()
|
||||
if dst: dst.close()
|
||||
return os.path.realpath(saveto)
|
||||
|
||||
def main(argv, version=DEFAULT_VERSION):
|
||||
"""Install or upgrade setuptools and EasyInstall"""
|
||||
|
||||
try:
|
||||
import setuptools
|
||||
except ImportError:
|
||||
import tempfile, shutil
|
||||
tmpdir = tempfile.mkdtemp(prefix="easy_install-")
|
||||
try:
|
||||
egg = download_setuptools(version, to_dir=tmpdir, delay=0)
|
||||
sys.path.insert(0,egg)
|
||||
from setuptools.command.easy_install import main
|
||||
return main(list(argv)+[egg]) # we're done here
|
||||
finally:
|
||||
shutil.rmtree(tmpdir)
|
||||
else:
|
||||
if setuptools.__version__ == '0.0.1':
|
||||
# tell the user to uninstall obsolete version
|
||||
use_setuptools(version)
|
||||
|
||||
req = "setuptools>="+version
|
||||
import pkg_resources
|
||||
try:
|
||||
pkg_resources.require(req)
|
||||
except pkg_resources.VersionConflict:
|
||||
try:
|
||||
from setuptools.command.easy_install import main
|
||||
except ImportError:
|
||||
from easy_install import main
|
||||
main(list(argv)+[download_setuptools(delay=0)])
|
||||
sys.exit(0) # try to force an exit
|
||||
else:
|
||||
if argv:
|
||||
from setuptools.command.easy_install import main
|
||||
main(argv)
|
||||
else:
|
||||
print "Setuptools version",version,"or greater has been installed."
|
||||
print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
|
||||
|
||||
|
||||
|
||||
def update_md5(filenames):
|
||||
"""Update our built-in md5 registry"""
|
||||
|
||||
import re
|
||||
from md5 import md5
|
||||
|
||||
for name in filenames:
|
||||
base = os.path.basename(name)
|
||||
f = open(name,'rb')
|
||||
md5_data[base] = md5(f.read()).hexdigest()
|
||||
f.close()
|
||||
|
||||
data = [" %r: %r,\n" % it for it in md5_data.items()]
|
||||
data.sort()
|
||||
repl = "".join(data)
|
||||
|
||||
import inspect
|
||||
srcfile = inspect.getsourcefile(sys.modules[__name__])
|
||||
f = open(srcfile, 'rb'); src = f.read(); f.close()
|
||||
|
||||
match = re.search("\nmd5_data = {\n([^}]+)}", src)
|
||||
if not match:
|
||||
print >>sys.stderr, "Internal error!"
|
||||
sys.exit(2)
|
||||
|
||||
src = src[:match.start(1)] + repl + src[match.end(1):]
|
||||
f = open(srcfile,'w')
|
||||
f.write(src)
|
||||
f.close()
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
if len(sys.argv)>2 and sys.argv[1]=='--md5update':
|
||||
update_md5(sys.argv[2:])
|
||||
else:
|
||||
main(sys.argv[1:])
|
||||
|
||||
|
||||
|
||||
|
||||
|
45
setup.py
45
setup.py
@ -1,7 +1,25 @@
|
||||
import ez_setup # From http://peak.telecommunity.com/DevCenter/setuptools
|
||||
ez_setup.use_setuptools()
|
||||
from distutils.core import setup
|
||||
from distutils.command.install import INSTALL_SCHEMES
|
||||
import os
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
# Tell distutils to put the data_files in platform-specific installation
|
||||
# locations. See here for an explanation:
|
||||
# http://groups.google.com/group/comp.lang.python/browse_thread/thread/35ec7b2fed36eaec/2105ee4d9e8042cb
|
||||
for scheme in INSTALL_SCHEMES.values():
|
||||
scheme['data'] = scheme['purelib']
|
||||
|
||||
# Compile the list of packages available, because distutils doesn't have
|
||||
# an easy way to do this.
|
||||
packages, data_files = [], []
|
||||
root_dir = os.path.join(os.path.dirname(__file__), 'django')
|
||||
for dirpath, dirnames, filenames in os.walk(root_dir):
|
||||
# Ignore dirnames that start with '.'
|
||||
for i, dirname in enumerate(dirnames):
|
||||
if dirname.startswith('.'): del dirnames[i]
|
||||
if '__init__.py' in filenames:
|
||||
packages.append(dirpath.replace('/', '.'))
|
||||
else:
|
||||
data_files.append((dirpath, [os.path.join(dirpath, f) for f in filenames]))
|
||||
|
||||
setup(
|
||||
name = "Django",
|
||||
@ -10,24 +28,7 @@ setup(
|
||||
author = 'Lawrence Journal-World',
|
||||
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', 'examples.*']),
|
||||
package_data = {
|
||||
'': ['*.TXT'],
|
||||
'django.conf': ['locale/*/LC_MESSAGES/*'],
|
||||
'django.contrib.admin': ['templates/admin/*.html',
|
||||
'templates/admin/auth/user/*.html',
|
||||
'templates/admin_doc/*.html',
|
||||
'templates/registration/*.html',
|
||||
'templates/widget/*.html',
|
||||
'media/css/*.css',
|
||||
'media/img/admin/*.gif',
|
||||
'media/img/admin/*.png',
|
||||
'media/js/*.js',
|
||||
'media/js/admin/*js'],
|
||||
'django.contrib.comments': ['templates/comments/*.html'],
|
||||
'django.contrib.sitemaps': ['templates/*.xml'],
|
||||
},
|
||||
packages = packages,
|
||||
data_files = data_files,
|
||||
scripts = ['django/bin/django-admin.py'],
|
||||
zip_safe = False,
|
||||
)
|
||||
|
@ -30,6 +30,14 @@ class Waiter(models.Model):
|
||||
def __str__(self):
|
||||
return "%s the waiter at %s" % (self.name, self.restaurant)
|
||||
|
||||
class ManualPrimaryKey(models.Model):
|
||||
primary_key = models.CharField(maxlength=10, primary_key=True)
|
||||
name = models.CharField(maxlength = 50)
|
||||
|
||||
class RelatedModel(models.Model):
|
||||
link = models.OneToOneField(ManualPrimaryKey)
|
||||
name = models.CharField(maxlength = 50)
|
||||
|
||||
__test__ = {'API_TESTS':"""
|
||||
# Create a couple of Places.
|
||||
>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
|
||||
@ -151,4 +159,10 @@ DoesNotExist: Restaurant matching query does not exist.
|
||||
# Delete the restaurant; the waiter should also be removed
|
||||
>>> r = Restaurant.objects.get(pk=1)
|
||||
>>> r.delete()
|
||||
|
||||
# One-to-one fields still work if you create your own primary key
|
||||
>>> o1 = ManualPrimaryKey(primary_key="abc123", name="primary")
|
||||
>>> o1.save()
|
||||
>>> o2 = RelatedModel(link=o1, name="secondary")
|
||||
>>> o2.save()
|
||||
"""}
|
||||
|
@ -21,22 +21,22 @@ r"""
|
||||
'7'
|
||||
>>> format(my_birthday, 'N')
|
||||
'July'
|
||||
>>> format(my_birthday, 'O')
|
||||
'+0100'
|
||||
>>> no_tz or format(my_birthday, 'O') == '+0100'
|
||||
True
|
||||
>>> format(my_birthday, 'P')
|
||||
'10 p.m.'
|
||||
>>> format(my_birthday, 'r')
|
||||
'Sun, 8 Jul 1979 22:00:00 +0100'
|
||||
>>> no_tz or format(my_birthday, 'r') == 'Sun, 8 Jul 1979 22:00:00 +0100'
|
||||
True
|
||||
>>> format(my_birthday, 's')
|
||||
'00'
|
||||
>>> format(my_birthday, 'S')
|
||||
'th'
|
||||
>>> format(my_birthday, 't')
|
||||
'31'
|
||||
>>> format(my_birthday, 'T')
|
||||
'CET'
|
||||
>>> format(my_birthday, 'U')
|
||||
'300531600'
|
||||
>>> no_tz or format(my_birthday, 'T') == 'CET'
|
||||
True
|
||||
>>> no_tz or format(my_birthday, 'U') == '300531600'
|
||||
True
|
||||
>>> format(my_birthday, 'w')
|
||||
'0'
|
||||
>>> format(my_birthday, 'W')
|
||||
@ -47,17 +47,17 @@ r"""
|
||||
'1979'
|
||||
>>> format(my_birthday, 'z')
|
||||
'189'
|
||||
>>> format(my_birthday, 'Z')
|
||||
'3600'
|
||||
>>> no_tz or format(my_birthday, 'Z') == '3600'
|
||||
True
|
||||
|
||||
>>> format(summertime, 'I')
|
||||
'1'
|
||||
>>> format(summertime, 'O')
|
||||
'+0200'
|
||||
>>> format(wintertime, 'I')
|
||||
'0'
|
||||
>>> format(wintertime, 'O')
|
||||
'+0100'
|
||||
>>> no_tz or format(summertime, 'I') == '1'
|
||||
True
|
||||
>>> no_tz or format(summertime, 'O') == '+0200'
|
||||
True
|
||||
>>> no_tz or format(wintertime, 'I') == '0'
|
||||
True
|
||||
>>> no_tz or format(wintertime, 'O') == '+0100'
|
||||
True
|
||||
|
||||
>>> format(my_birthday, r'Y z \C\E\T')
|
||||
'1979 189 CET'
|
||||
@ -73,7 +73,11 @@ format = dateformat.format
|
||||
os.environ['TZ'] = 'Europe/Copenhagen'
|
||||
translation.activate('en-us')
|
||||
|
||||
time.tzset()
|
||||
try:
|
||||
time.tzset()
|
||||
no_tz = False
|
||||
except AttributeError:
|
||||
no_tz = True
|
||||
|
||||
my_birthday = datetime.datetime(1979, 7, 8, 22, 00)
|
||||
summertime = datetime.datetime(2005, 10, 30, 1, 00)
|
||||
|
0
tests/regressiontests/null_queries/__init__.py
Normal file
0
tests/regressiontests/null_queries/__init__.py
Normal file
54
tests/regressiontests/null_queries/models.py
Normal file
54
tests/regressiontests/null_queries/models.py
Normal file
@ -0,0 +1,54 @@
|
||||
from django.db import models
|
||||
|
||||
class Poll(models.Model):
|
||||
question = models.CharField(maxlength=200)
|
||||
|
||||
def __str__(self):
|
||||
return "Q: %s " % self.question
|
||||
|
||||
class Choice(models.Model):
|
||||
poll = models.ForeignKey(Poll)
|
||||
choice = models.CharField(maxlength=200)
|
||||
|
||||
def __str__(self):
|
||||
return "Choice: %s in poll %s" % (self.choice, self.poll)
|
||||
|
||||
__test__ = {'API_TESTS':"""
|
||||
# Regression test for the use of None as a query value. None is interpreted as
|
||||
# an SQL NULL, but only in __exact queries.
|
||||
# Set up some initial polls and choices
|
||||
>>> p1 = Poll(question='Why?')
|
||||
>>> p1.save()
|
||||
>>> c1 = Choice(poll=p1, choice='Because.')
|
||||
>>> c1.save()
|
||||
>>> c2 = Choice(poll=p1, choice='Why Not?')
|
||||
>>> c2.save()
|
||||
|
||||
# Exact query with value None returns nothing (=NULL in sql)
|
||||
>>> Choice.objects.filter(id__exact=None)
|
||||
[]
|
||||
|
||||
# Valid query, but fails because foo isn't a keyword
|
||||
>>> Choice.objects.filter(foo__exact=None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: Cannot resolve keyword 'foo' into field
|
||||
|
||||
# Can't use None on anything other than __exact
|
||||
>>> Choice.objects.filter(id__gt=None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Cannot use None as a query value
|
||||
|
||||
# Can't use None on anything other than __exact
|
||||
>>> Choice.objects.filter(foo__gt=None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Cannot use None as a query value
|
||||
|
||||
# Related managers use __exact=None implicitly if the object hasn't been saved.
|
||||
>>> p2 = Poll(question="How?")
|
||||
>>> p2.choice_set.all()
|
||||
[]
|
||||
|
||||
"""}
|
@ -170,6 +170,9 @@ class Templates(unittest.TestCase):
|
||||
# Escaped backslash using known escape char
|
||||
'basic-syntax35': (r'{{ var|default_if_none:"foo\now" }}', {"var": None}, r'foo\now'),
|
||||
|
||||
# Empty strings can be passed as arguments to filters
|
||||
'basic-syntax36': (r'{{ var|join:"" }}', {'var': ['a', 'b', 'c']}, 'abc'),
|
||||
|
||||
### COMMENT TAG ###########################################################
|
||||
'comment-tag01': ("{% comment %}this is hidden{% endcomment %}hello", {}, "hello"),
|
||||
'comment-tag02': ("{% comment %}this is hidden{% endcomment %}hello{% comment %}foo{% endcomment %}", {}, "hello"),
|
||||
|
Loading…
x
Reference in New Issue
Block a user