1
0
mirror of https://github.com/django/django.git synced 2025-07-04 01:39:20 +00:00

[per-object-permissions] Merged to trunk [3809]

git-svn-id: http://code.djangoproject.com/svn/django/branches/per-object-permissions@3810 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Christopher Long 2006-09-23 18:18:58 +00:00
parent 13d039ddab
commit 5ea24f0c14
61 changed files with 3353 additions and 809 deletions

View File

@ -44,6 +44,7 @@ answer newbie questions, and generally made Django that much better:
akaihola akaihola
Andreas Andreas
ant9000@netwise.it
David Ascher <http://ascher.ca/> David Ascher <http://ascher.ca/>
Arthur <avandorp@gmail.com> Arthur <avandorp@gmail.com>
Jiri Barton Jiri Barton
@ -67,15 +68,19 @@ answer newbie questions, and generally made Django that much better:
Alex Dedul Alex Dedul
deric@monowerks.com deric@monowerks.com
dne@mayonnaise.net dne@mayonnaise.net
Maximillian Dornseif <md@hudora.de>
dummy@habmalnefrage.de
Jeremy Dunck <http://dunck.us/> Jeremy Dunck <http://dunck.us/>
Andy Dustman <farcepest@gmail.com> Andy Dustman <farcepest@gmail.com>
Clint Ecker Clint Ecker
favo@exoweb.net
gandalf@owca.info gandalf@owca.info
Baishampayan Ghose Baishampayan Ghose
martin.glueck@gmail.com martin.glueck@gmail.com
Simon Greenhill <dev@simon.net.nz> Simon Greenhill <dev@simon.net.nz>
Espen Grindhaug <http://grindhaug.org/> Espen Grindhaug <http://grindhaug.org/>
Brant Harris Brant Harris
heckj@mac.com
hipertracker@gmail.com hipertracker@gmail.com
Ian Holsman <http://feh.holsman.net/> Ian Holsman <http://feh.holsman.net/>
Kieran Holland <http://www.kieranholland.com> Kieran Holland <http://www.kieranholland.com>
@ -95,6 +100,7 @@ answer newbie questions, and generally made Django that much better:
lakin.wecker@gmail.com lakin.wecker@gmail.com
Stuart Langridge <http://www.kryogenix.org/> Stuart Langridge <http://www.kryogenix.org/>
Eugene Lazutkin <http://lazutkin.com/blog/> Eugene Lazutkin <http://lazutkin.com/blog/>
Jeong-Min Lee
Christopher Lenz <http://www.cmlenz.net/> Christopher Lenz <http://www.cmlenz.net/>
limodou limodou
Martin Maney <http://www.chipy.org/Martin_Maney> Martin Maney <http://www.chipy.org/Martin_Maney>
@ -121,11 +127,13 @@ answer newbie questions, and generally made Django that much better:
Daniel Poelzleithner <http://poelzi.org/> Daniel Poelzleithner <http://poelzi.org/>
J. Rademaker J. Rademaker
Michael Radziej <mir@noris.de> Michael Radziej <mir@noris.de>
ramiro
Brian Ray <http://brianray.chipy.org/> Brian Ray <http://brianray.chipy.org/>
rhettg@gmail.com rhettg@gmail.com
Oliver Rutherfurd <http://rutherfurd.net/> Oliver Rutherfurd <http://rutherfurd.net/>
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/> Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
David Schein David Schein
serbaut@gmail.com
Pete Shinners <pete@shinners.org> Pete Shinners <pete@shinners.org>
SmileyChris <smileychris@gmail.com> SmileyChris <smileychris@gmail.com>
sopel sopel

4
README
View File

@ -25,10 +25,10 @@ http://code.djangoproject.com/newticket
To get more help: To get more help:
* Join the #django channel on irc.freenode.net. Lots of helpful people * Join the #django channel on irc.freenode.net. Lots of helpful people
hang out there. Read the archives at http://loglibrary.com/179 . hang out there. Read the archives at http://simon.bofh.ms/logger/django/ .
* Join the django-users mailing list, or read the archives, at * Join the django-users mailing list, or read the archives, at
http://groups-beta.google.com/group/django-users. http://groups.google.com/group/django-users.
To contribute to Django: To contribute to Django:

View File

@ -46,6 +46,7 @@ LANGUAGES = (
('en', gettext_noop('English')), ('en', gettext_noop('English')),
('es', gettext_noop('Spanish')), ('es', gettext_noop('Spanish')),
('es_AR', gettext_noop('Argentinean Spanish')), ('es_AR', gettext_noop('Argentinean Spanish')),
('fi', gettext_noop('Finnish')),
('fr', gettext_noop('French')), ('fr', gettext_noop('French')),
('gl', gettext_noop('Galician')), ('gl', gettext_noop('Galician')),
('hu', gettext_noop('Hungarian')), ('hu', gettext_noop('Hungarian')),
@ -271,6 +272,10 @@ CACHE_MIDDLEWARE_KEY_PREFIX = ''
COMMENTS_ALLOW_PROFANITIES = False 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']
# The group ID that designates which users are banned. # The group ID that designates which users are banned.
# Set to None if you're not using it. # Set to None if you're not using it.
COMMENTS_BANNED_USERS_GROUP = None COMMENTS_BANNED_USERS_GROUP = None

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.

View File

@ -0,0 +1,110 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2005-12-09 11:51+0100\n"
"PO-Revision-Date: 2006-08-05 15:27+0300\n"
"Last-Translator: Antti Kaihola <akaihola@ambitone.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\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 "Mahdolliset %s"
#: contrib/admin/media/js/SelectFilter2.js:41
msgid "Choose all"
msgstr "Valitse kaikki"
#: contrib/admin/media/js/SelectFilter2.js:46
msgid "Add"
msgstr "Lisää uusi"
#: contrib/admin/media/js/SelectFilter2.js:48
msgid "Remove"
msgstr "Poista"
#: contrib/admin/media/js/SelectFilter2.js:53
#, perl-format
msgid "Chosen %s"
msgstr "Valitut %s"
#: contrib/admin/media/js/SelectFilter2.js:54
msgid "Select your choice(s) and click "
msgstr "Valitse vasemmalta ja napsauta "
#: contrib/admin/media/js/SelectFilter2.js:59
msgid "Clear all"
msgstr "Tyhjennä kaikki"
#: 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 ""
"Tammikuu Helmikuu Maaliskuu Huhtikuu Toukokuu Kesäkuu Heinäkuu Elokuu "
"Syyskuu Lokakuu Marraskuu Joulukuu"
#: contrib/admin/media/js/dateparse.js:27
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr "Sunnuntai Maanantai Tiistai Keskiviikko Torstai Perjantai Lauantai"
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
msgstr "S M T K T P L"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
msgid "Now"
msgstr "Nyt"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
msgid "Clock"
msgstr "Kello"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
msgid "Choose a time"
msgstr "Valitse kellonaika"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Midnight"
msgstr "24"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "6 a.m."
msgstr "06"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "Noon"
msgstr "12"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
msgid "Cancel"
msgstr "Peruuta"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
msgid "Today"
msgstr "Tänään"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
msgid "Calendar"
msgstr "Kalenteri"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
msgid "Yesterday"
msgstr "Eilen"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
msgid "Tomorrow"
msgstr "Huomenna"

View File

@ -264,7 +264,7 @@ msgstr "Bare POST er tillatt"
#: contrib/comments/views/comments.py:193 #: contrib/comments/views/comments.py:193
#: contrib/comments/views/comments.py:284 #: contrib/comments/views/comments.py:284
msgid "One or more of the required fields wasn't submitted" msgid "One or more of the required fields wasn't submitted"
msgstr "En eller flere av feltene som er krevd ble ikke sendt." msgstr "En eller flere av feltene som er krevd ble ikke sendt."
#: contrib/comments/views/comments.py:197 #: contrib/comments/views/comments.py:197
#: contrib/comments/views/comments.py:286 #: contrib/comments/views/comments.py:286
@ -371,35 +371,32 @@ msgid "All"
msgstr "Alle" msgstr "Alle"
#: contrib/admin/filterspecs.py:109 #: contrib/admin/filterspecs.py:109
#, fuzzy
msgid "Any date" msgid "Any date"
msgstr "Alle datoer" msgstr "Når som helst"
#: contrib/admin/filterspecs.py:110 #: contrib/admin/filterspecs.py:110
#, fuzzy
msgid "Today" msgid "Today"
msgstr "Mondag" msgstr "I dag"
#: contrib/admin/filterspecs.py:113 #: contrib/admin/filterspecs.py:113
msgid "Past 7 days" msgid "Past 7 days"
msgstr "" msgstr "Siste 7 dager"
#: contrib/admin/filterspecs.py:115 #: contrib/admin/filterspecs.py:115
msgid "This month" msgid "This month"
msgstr "" msgstr "Denne måneden"
#: contrib/admin/filterspecs.py:117 #: contrib/admin/filterspecs.py:117
msgid "This year" msgid "This year"
msgstr "" msgstr "I år"
#: contrib/admin/filterspecs.py:143 #: contrib/admin/filterspecs.py:143
msgid "Yes" msgid "Yes"
msgstr "" msgstr "Ja"
#: contrib/admin/filterspecs.py:143 #: contrib/admin/filterspecs.py:143
#, fuzzy
msgid "No" msgid "No"
msgstr "Nov." msgstr "Nei"
#: contrib/admin/filterspecs.py:150 #: contrib/admin/filterspecs.py:150
msgid "Unknown" msgid "Unknown"
@ -443,11 +440,13 @@ msgid ""
"Please enter a correct username and password. Note that both fields are case-" "Please enter a correct username and password. Note that both fields are case-"
"sensitive." "sensitive."
msgstr "" msgstr ""
"Vær snill å angi korrekt brukernavn og passord. La merke til at små og "
"store bokstaver er betraktet ulik."
#: contrib/admin/views/decorators.py:23 #: contrib/admin/views/decorators.py:23
#: contrib/admin/templates/admin/login.html:25 #: contrib/admin/templates/admin/login.html:25
msgid "Log in" msgid "Log in"
msgstr "Log inn" msgstr "Logg inn"
#: contrib/admin/views/decorators.py:61 #: contrib/admin/views/decorators.py:61
msgid "" msgid ""
@ -473,12 +472,11 @@ msgstr "Brukernavnet kan ikke inneholde '@'"
#: contrib/admin/views/decorators.py:84 #: contrib/admin/views/decorators.py:84
#, python-format #, python-format
msgid "Your e-mail address is not your username. Try '%s' instead." msgid "Your e-mail address is not your username. Try '%s' instead."
msgstr "Epost adressen din er ikke brukernavnet ditt, prøv '%s' i stede." msgstr "E-post adressen din er ikke brukernavnet ditt, prøv '%s' i stede."
#: contrib/admin/views/main.py:226 #: contrib/admin/views/main.py:226
#, fuzzy
msgid "Site administration" msgid "Site administration"
msgstr "Django administrasjon" msgstr "Nettsted administrasjon"
#: contrib/admin/views/main.py:260 #: contrib/admin/views/main.py:260
#, python-format #, python-format
@ -502,7 +500,7 @@ msgstr "Ny %s"
#: contrib/admin/views/main.py:336 #: contrib/admin/views/main.py:336
#, python-format #, python-format
msgid "Added %s." msgid "Added %s."
msgstr "La til %s" msgstr "Lagt til %s"
#: contrib/admin/views/main.py:336 contrib/admin/views/main.py:338 #: contrib/admin/views/main.py:336 contrib/admin/views/main.py:338
#: contrib/admin/views/main.py:340 #: contrib/admin/views/main.py:340
@ -559,7 +557,7 @@ msgid "Are you sure?"
msgstr "Er du sikker?" msgstr "Er du sikker?"
#: contrib/admin/views/main.py:533 #: contrib/admin/views/main.py:533
#, fuzzy, python-format #, python-format
msgid "Change history: %s" msgid "Change history: %s"
msgstr "Endre historien: %s" msgstr "Endre historien: %s"
@ -580,7 +578,6 @@ msgid "Integer"
msgstr "Heltall" msgstr "Heltall"
#: contrib/admin/views/doc.py:278 #: contrib/admin/views/doc.py:278
#, fuzzy
msgid "Boolean (Either True or False)" msgid "Boolean (Either True or False)"
msgstr "Boolean (Enten \"True\" eller \"False\")" msgstr "Boolean (Enten \"True\" eller \"False\")"
@ -603,7 +600,7 @@ msgstr "Dato/tid"
#: contrib/admin/views/doc.py:283 #: contrib/admin/views/doc.py:283
msgid "E-mail address" msgid "E-mail address"
msgstr "Epost adresse" msgstr "E-post adresse"
#: contrib/admin/views/doc.py:284 contrib/admin/views/doc.py:287 #: contrib/admin/views/doc.py:284 contrib/admin/views/doc.py:287
msgid "File path" msgid "File path"
@ -614,13 +611,12 @@ msgid "Decimal number"
msgstr "Desimal tall" msgstr "Desimal tall"
#: contrib/admin/views/doc.py:291 #: contrib/admin/views/doc.py:291
#, fuzzy
msgid "Boolean (Either True, False or None)" msgid "Boolean (Either True, False or None)"
msgstr "Boolean (enten \"True\", \"False\" eller \"None\")" msgstr "Boolean (enten \"True\", \"False\" eller \"None\")"
#: contrib/admin/views/doc.py:292 #: contrib/admin/views/doc.py:292
msgid "Relation to parent model" msgid "Relation to parent model"
msgstr "" msgstr "Relasjon til forelder modell"
#: contrib/admin/views/doc.py:293 #: contrib/admin/views/doc.py:293
msgid "Phone number" msgid "Phone number"
@ -636,7 +632,7 @@ msgstr "Tid"
#: contrib/admin/views/doc.py:300 contrib/flatpages/models.py:7 #: contrib/admin/views/doc.py:300 contrib/flatpages/models.py:7
msgid "URL" msgid "URL"
msgstr "Internettadresse" msgstr "URL"
#: contrib/admin/views/doc.py:301 #: contrib/admin/views/doc.py:301
msgid "U.S. state (two uppercase letters)" msgid "U.S. state (two uppercase letters)"
@ -756,12 +752,12 @@ msgstr "Fant ikke siden"
#: contrib/admin/templates/admin/404.html:10 #: contrib/admin/templates/admin/404.html:10
msgid "We're sorry, but the requested page could not be found." msgid "We're sorry, but the requested page could not be found."
msgstr "Beklager, men siden du spør etter finnest ikke." msgstr "Beklager, men siden du spør etter finnes ikke."
#: contrib/admin/templates/admin/index.html:17 #: contrib/admin/templates/admin/index.html:17
#, python-format #, python-format
msgid "Models available in the %(name)s application." msgid "Models available in the %(name)s application."
msgstr "" msgstr "Modeller fra applikasjonen %(name)s."
#: contrib/admin/templates/admin/index.html:28 #: contrib/admin/templates/admin/index.html:28
#: contrib/admin/templates/admin/change_form.html:15 #: contrib/admin/templates/admin/change_form.html:15
@ -813,7 +809,7 @@ msgid ""
"objects, but your account doesn't have permission to delete the following " "objects, but your account doesn't have permission to delete the following "
"types of objects:" "types of objects:"
msgstr "" msgstr ""
"Vist du sletter %(object_name)s '%(object)s' vill du også slette relaterte " "Hivs du sletter %(object_name)s '%(object)s' vil du også slette relaterte "
"objekter, men du har ikke tillatelse til å slette de følgende objektene:" "objekter, men du har ikke tillatelse til å slette de følgende objektene:"
#: contrib/admin/templates/admin/delete_confirmation.html:21 #: contrib/admin/templates/admin/delete_confirmation.html:21
@ -836,11 +832,11 @@ msgstr "Av %(title)s "
#: contrib/admin/templates/admin/search_form.html:8 #: contrib/admin/templates/admin/search_form.html:8
msgid "Go" msgid "Go"
msgstr "" msgstr ""
#: contrib/admin/templates/admin/change_form.html:21 #: contrib/admin/templates/admin/change_form.html:21
msgid "View on site" msgid "View on site"
msgstr "Vis på siden" msgstr "Vis på nettsted"
#: contrib/admin/templates/admin/change_form.html:30 #: contrib/admin/templates/admin/change_form.html:30
msgid "Please correct the error below." msgid "Please correct the error below."
@ -900,12 +896,12 @@ msgid ""
"Forgotten your password? Enter your e-mail address below, and we'll reset " "Forgotten your password? Enter your e-mail address below, and we'll reset "
"your password and e-mail the new one to you." "your password and e-mail the new one to you."
msgstr "" msgstr ""
"Har du glemt passordet ditt? Skriv inn epost adressen din under, så sender " "Har du glemt passordet ditt? Skriv inn e-post adressen din under, så sender "
"vi deg et nytt passord via epost." "vi deg et nytt passord via e-post."
#: contrib/admin/templates/registration/password_reset_form.html:16 #: contrib/admin/templates/registration/password_reset_form.html:16
msgid "E-mail address:" msgid "E-mail address:"
msgstr "Epost adresse:" msgstr "E-post adresse:"
#: contrib/admin/templates/registration/password_reset_form.html:16 #: contrib/admin/templates/registration/password_reset_form.html:16
msgid "Reset my password" msgid "Reset my password"
@ -917,7 +913,7 @@ msgstr "Takk for å bruke tid på internett siden i dag."
#: contrib/admin/templates/registration/logged_out.html:10 #: contrib/admin/templates/registration/logged_out.html:10
msgid "Log in again" msgid "Log in again"
msgstr "Log inn igjen" msgstr "Logg inn igjen"
#: contrib/admin/templates/registration/password_reset_done.html:6 #: contrib/admin/templates/registration/password_reset_done.html:6
#: contrib/admin/templates/registration/password_reset_done.html:10 #: contrib/admin/templates/registration/password_reset_done.html:10
@ -929,7 +925,7 @@ msgid ""
"We've e-mailed a new password to the e-mail address you submitted. You " "We've e-mailed a new password to the e-mail address you submitted. You "
"should be receiving it shortly." "should be receiving it shortly."
msgstr "" msgstr ""
"Vi sender deg et nytt passord til epost adressen du oppgav. Du villmotta det " "Vi sender deg et nytt passord til e-post adressen du oppgav. Du villmotta det "
"snart." "snart."
#: contrib/admin/templates/registration/password_change_form.html:12 #: contrib/admin/templates/registration/password_change_form.html:12
@ -959,7 +955,7 @@ msgstr "Endre passord"
#: contrib/admin/templates/registration/password_reset_email.html:2 #: contrib/admin/templates/registration/password_reset_email.html:2
msgid "You're receiving this e-mail because you requested a password reset" msgid "You're receiving this e-mail because you requested a password reset"
msgstr "" msgstr ""
"Du har mottatt denne epost-en fordi du ba om å tilbakestille passordet ditt" "Du har mottatt denne e-posten fordi du ba om å tilbakestille passordet ditt"
#: contrib/admin/templates/registration/password_reset_email.html:3 #: contrib/admin/templates/registration/password_reset_email.html:3
#, python-format #, python-format
@ -1036,10 +1032,9 @@ msgid "Edit this object (current window)"
msgstr "Endre dette objektet (åpnes i dette vinduet)" msgstr "Endre dette objektet (åpnes i dette vinduet)"
#: contrib/admin/templates/admin_doc/bookmarklets.html:26 #: contrib/admin/templates/admin_doc/bookmarklets.html:26
#, fuzzy
msgid "Jumps to the admin page for pages that represent a single object." msgid "Jumps to the admin page for pages that represent a single object."
msgstr "" msgstr ""
"Hopp til administrasjonsiden for siden som representerer et enkelt objekt." "Hopp til administrasjonsiden for sidene som representerer et enkelt objekt."
#: contrib/admin/templates/admin_doc/bookmarklets.html:28 #: contrib/admin/templates/admin_doc/bookmarklets.html:28
msgid "Edit this object (new window)" msgid "Edit this object (new window)"
@ -1051,21 +1046,19 @@ msgstr "Samme som over, men åpner administrasjonsiden i et nytt vindu."
#: contrib/admin/templates/widget/date_time.html:3 #: contrib/admin/templates/widget/date_time.html:3
msgid "Date:" msgid "Date:"
msgstr "" msgstr "Dato:"
#: contrib/admin/templates/widget/date_time.html:4 #: contrib/admin/templates/widget/date_time.html:4
#, fuzzy
msgid "Time:" msgid "Time:"
msgstr "Tid" msgstr "Tid:"
#: contrib/admin/templates/widget/file.html:2 #: contrib/admin/templates/widget/file.html:2
msgid "Currently:" msgid "Currently:"
msgstr "" msgstr "Nå:"
#: contrib/admin/templates/widget/file.html:3 #: contrib/admin/templates/widget/file.html:3
#, fuzzy
msgid "Change:" msgid "Change:"
msgstr "Endre" msgstr "Endre:"
#: contrib/redirects/models.py:7 #: contrib/redirects/models.py:7
msgid "redirect from" msgid "redirect from"
@ -1126,7 +1119,7 @@ msgid ""
"Example: 'flatpages/contact_page'. If this isn't provided, the system will " "Example: 'flatpages/contact_page'. If this isn't provided, the system will "
"use 'flatpages/default'." "use 'flatpages/default'."
msgstr "" msgstr ""
"Eksempel: 'flatfiler/kontakt_side'. Vist denne ikke denne er gitt, vill " "Eksempel: 'flatfiler/kontakt_side'. Hvis denne ikke denne er gitt, vill "
"'flatfiles/default' bli brukt." "'flatfiles/default' bli brukt."
#: contrib/flatpages/models.py:14 #: contrib/flatpages/models.py:14
@ -1136,7 +1129,7 @@ msgstr "registrering kreves"
#: contrib/flatpages/models.py:14 #: contrib/flatpages/models.py:14
msgid "If this is checked, only logged-in users will be able to view the page." msgid "If this is checked, only logged-in users will be able to view the page."
msgstr "" msgstr ""
"Vist denne er krysset av er det bare brukere som er logget inn som kan se " "Hvis denne er krysset av er det bare brukere som er logget inn som kan se "
"siden." "siden."
#: contrib/flatpages/models.py:18 #: contrib/flatpages/models.py:18
@ -1156,24 +1149,20 @@ msgid "codename"
msgstr "kodenavn" msgstr "kodenavn"
#: contrib/auth/models.py:17 #: contrib/auth/models.py:17
#, fuzzy
msgid "permission" msgid "permission"
msgstr "Rettighet" msgstr "rettighet"
#: contrib/auth/models.py:18 contrib/auth/models.py:27 #: contrib/auth/models.py:18 contrib/auth/models.py:27
#, fuzzy
msgid "permissions" msgid "permissions"
msgstr "Rettigheter" msgstr "rettigheter"
#: contrib/auth/models.py:29 #: contrib/auth/models.py:29
#, fuzzy
msgid "group" msgid "group"
msgstr "Gruppe" msgstr "gruppe"
#: contrib/auth/models.py:30 contrib/auth/models.py:65 #: contrib/auth/models.py:30 contrib/auth/models.py:65
#, fuzzy
msgid "groups" msgid "groups"
msgstr "Grupper" msgstr "grupper"
#: contrib/auth/models.py:55 #: contrib/auth/models.py:55
msgid "username" msgid "username"
@ -1205,7 +1194,7 @@ msgstr "administrasjons status"
#: contrib/auth/models.py:60 #: contrib/auth/models.py:60
msgid "Designates whether the user can log into this admin site." msgid "Designates whether the user can log into this admin site."
msgstr "Bestemmer om brukeren kan logge inn på denne administrasjons siden." msgstr "Bestemmer om brukeren kan logge inn på dette administrasjons sted."
#: contrib/auth/models.py:61 #: contrib/auth/models.py:61
msgid "active" msgid "active"
@ -1217,7 +1206,7 @@ msgstr "super bruker"
#: contrib/auth/models.py:63 #: contrib/auth/models.py:63
msgid "last login" msgid "last login"
msgstr "liste logg inn" msgstr "siste logg inn"
#: contrib/auth/models.py:64 #: contrib/auth/models.py:64
msgid "date joined" msgid "date joined"
@ -1232,19 +1221,16 @@ msgstr ""
"tilgang til gruppene han/hun er i." "tilgang til gruppene han/hun er i."
#: contrib/auth/models.py:67 #: contrib/auth/models.py:67
#, fuzzy
msgid "user permissions" msgid "user permissions"
msgstr "Rettigheter" msgstr "Rettigheter"
#: contrib/auth/models.py:70 #: contrib/auth/models.py:70
#, fuzzy
msgid "user" msgid "user"
msgstr "Bruker" msgstr "bruker"
#: contrib/auth/models.py:71 #: contrib/auth/models.py:71
#, fuzzy
msgid "users" msgid "users"
msgstr "Brukere" msgstr "brukere"
#: contrib/auth/models.py:76 #: contrib/auth/models.py:76
msgid "Personal info" msgid "Personal info"
@ -1263,9 +1249,8 @@ msgid "Groups"
msgstr "Grupper" msgstr "Grupper"
#: contrib/auth/models.py:219 #: contrib/auth/models.py:219
#, fuzzy
msgid "message" msgid "message"
msgstr "Meldinger" msgstr "Melding"
#: contrib/auth/forms.py:30 #: contrib/auth/forms.py:30
msgid "" msgid ""
@ -1274,9 +1259,8 @@ msgid ""
msgstr "" msgstr ""
#: contrib/contenttypes/models.py:25 #: contrib/contenttypes/models.py:25
#, fuzzy
msgid "python model class name" msgid "python model class name"
msgstr "python modul navn" msgstr "python modell klasse navn"
#: contrib/contenttypes/models.py:28 #: contrib/contenttypes/models.py:28
msgid "content type" msgid "content type"
@ -1312,23 +1296,23 @@ msgstr "domene navn"
#: contrib/sites/models.py:11 #: contrib/sites/models.py:11
msgid "display name" msgid "display name"
msgstr "vist navn" msgstr "vise navn"
#: contrib/sites/models.py:15 #: contrib/sites/models.py:15
msgid "site" msgid "site"
msgstr "side" msgstr "nettsted"
#: contrib/sites/models.py:16 #: contrib/sites/models.py:16
msgid "sites" msgid "sites"
msgstr "sider" msgstr "nettsteder"
#: utils/translation.py:360 #: utils/translation.py:360
msgid "DATE_FORMAT" msgid "DATE_FORMAT"
msgstr "j. M U" msgstr "j. M Y"
#: utils/translation.py:361 #: utils/translation.py:361
msgid "DATETIME_FORMAT" msgid "DATETIME_FORMAT"
msgstr "j. M U - h:i" msgstr "j. M Y - h:i"
#: utils/translation.py:362 #: utils/translation.py:362
msgid "TIME_FORMAT" msgid "TIME_FORMAT"
@ -1336,7 +1320,7 @@ msgstr "h:i"
#: utils/dates.py:6 #: utils/dates.py:6
msgid "Monday" msgid "Monday"
msgstr "Mondag" msgstr "Mandag"
#: utils/dates.py:6 #: utils/dates.py:6
msgid "Tuesday" msgid "Tuesday"
@ -1411,54 +1395,52 @@ msgid "December"
msgstr "Desember" msgstr "Desember"
#: utils/dates.py:19 #: utils/dates.py:19
#, fuzzy
msgid "jan" msgid "jan"
msgstr "og" msgstr "jan"
#: utils/dates.py:19 #: utils/dates.py:19
msgid "feb" msgid "feb"
msgstr "" msgstr "feb"
#: utils/dates.py:19 #: utils/dates.py:19
msgid "mar" msgid "mar"
msgstr "" msgstr "mar"
#: utils/dates.py:19 #: utils/dates.py:19
msgid "apr" msgid "apr"
msgstr "" msgstr "apr"
#: utils/dates.py:19 #: utils/dates.py:19
#, fuzzy
msgid "may" msgid "may"
msgstr "Mai" msgstr "mai"
#: utils/dates.py:19 #: utils/dates.py:19
msgid "jun" msgid "jun"
msgstr "" msgstr "jun"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "jul" msgid "jul"
msgstr "" msgstr "jul"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "aug" msgid "aug"
msgstr "" msgstr "aug"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "sep" msgid "sep"
msgstr "" msgstr "sep"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "oct" msgid "oct"
msgstr "" msgstr "okt"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "nov" msgid "nov"
msgstr "" msgstr "nov"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "dec" msgid "dec"
msgstr "" msgstr "des"
#: utils/dates.py:27 #: utils/dates.py:27
msgid "Jan." msgid "Jan."
@ -1466,7 +1448,7 @@ msgstr "Jan."
#: utils/dates.py:27 #: utils/dates.py:27
msgid "Feb." msgid "Feb."
msgstr "Fef." msgstr "Feb."
#: utils/dates.py:28 #: utils/dates.py:28
msgid "Aug." msgid "Aug."
@ -1491,40 +1473,38 @@ msgstr "Des."
#: utils/timesince.py:12 #: utils/timesince.py:12
msgid "year" msgid "year"
msgid_plural "years" msgid_plural "years"
msgstr[0] "" msgstr[0] "år"
msgstr[1] "" msgstr[1] "år"
#: utils/timesince.py:13 #: utils/timesince.py:13
msgid "month" msgid "month"
msgid_plural "months" msgid_plural "months"
msgstr[0] "" msgstr[0] "måned"
msgstr[1] "" msgstr[1] "måndeder"
#: utils/timesince.py:14 #: utils/timesince.py:14
msgid "week" msgid "week"
msgid_plural "weeks" msgid_plural "weeks"
msgstr[0] "" msgstr[0] "uke"
msgstr[1] "" msgstr[1] "uker"
#: utils/timesince.py:15 #: utils/timesince.py:15
#, fuzzy
msgid "day" msgid "day"
msgid_plural "days" msgid_plural "days"
msgstr[0] "Mai" msgstr[0] "dag"
msgstr[1] "Mai" msgstr[1] "dager"
#: utils/timesince.py:16 #: utils/timesince.py:16
msgid "hour" msgid "hour"
msgid_plural "hours" msgid_plural "hours"
msgstr[0] "" msgstr[0] "time"
msgstr[1] "" msgstr[1] "timer"
#: utils/timesince.py:17 #: utils/timesince.py:17
#, fuzzy
msgid "minute" msgid "minute"
msgid_plural "minutes" msgid_plural "minutes"
msgstr[0] "side" msgstr[0] "minutt"
msgstr[1] "side" msgstr[1] "minutter"
#: conf/global_settings.py:37 #: conf/global_settings.py:37
msgid "Bengali" msgid "Bengali"
@ -1548,7 +1528,7 @@ msgstr "Tysk"
#: conf/global_settings.py:42 #: conf/global_settings.py:42
msgid "Greek" msgid "Greek"
msgstr "" msgstr "Gresk"
#: conf/global_settings.py:43 #: conf/global_settings.py:43
msgid "English" msgid "English"
@ -1568,11 +1548,11 @@ msgstr "Galisisk"
#: conf/global_settings.py:47 #: conf/global_settings.py:47
msgid "Hungarian" msgid "Hungarian"
msgstr "" msgstr "Ungarsk"
#: conf/global_settings.py:48 #: conf/global_settings.py:48
msgid "Hebrew" msgid "Hebrew"
msgstr "" msgstr "Hebraiske"
#: conf/global_settings.py:49 #: conf/global_settings.py:49
msgid "Icelandic" msgid "Icelandic"
@ -1584,11 +1564,11 @@ msgstr "Italiensk"
#: conf/global_settings.py:51 #: conf/global_settings.py:51
msgid "Japanese" msgid "Japanese"
msgstr "" msgstr "Japansk"
#: conf/global_settings.py:52 #: conf/global_settings.py:52
msgid "Dutch" msgid "Dutch"
msgstr "" msgstr "Nederlandsk"
#: conf/global_settings.py:53 #: conf/global_settings.py:53
msgid "Norwegian" msgid "Norwegian"
@ -1600,7 +1580,7 @@ msgstr "Brasiliansk"
#: conf/global_settings.py:55 #: conf/global_settings.py:55
msgid "Romanian" msgid "Romanian"
msgstr "Romansk" msgstr "Rumensk"
#: conf/global_settings.py:56 #: conf/global_settings.py:56
msgid "Russian" msgid "Russian"
@ -1611,9 +1591,8 @@ msgid "Slovak"
msgstr "Slovakisk" msgstr "Slovakisk"
#: conf/global_settings.py:58 #: conf/global_settings.py:58
#, fuzzy
msgid "Slovenian" msgid "Slovenian"
msgstr "Slovakisk" msgstr "Slovensk"
#: conf/global_settings.py:59 #: conf/global_settings.py:59
msgid "Serbian" msgid "Serbian"
@ -1624,9 +1603,8 @@ msgid "Swedish"
msgstr "Svensk" msgstr "Svensk"
#: conf/global_settings.py:61 #: conf/global_settings.py:61
#, fuzzy
msgid "Ukrainian" msgid "Ukrainian"
msgstr "Brasiliansk" msgstr "Ukrainsk"
#: conf/global_settings.py:62 #: conf/global_settings.py:62
msgid "Simplified Chinese" msgid "Simplified Chinese"
@ -1634,14 +1612,13 @@ msgstr "Simplifisert Kinesisk"
#: conf/global_settings.py:63 #: conf/global_settings.py:63
msgid "Traditional Chinese" msgid "Traditional Chinese"
msgstr "" msgstr "Tradisjonell Kinesisk"
#: core/validators.py:60 #: core/validators.py:60
msgid "This value must contain only letters, numbers and underscores." msgid "This value must contain only letters, numbers and underscores."
msgstr "Dette feltet må bare inneholde bokstaver, nummer og understreker." msgstr "Dette feltet må bare inneholde bokstaver, nummer og understreker."
#: core/validators.py:64 #: core/validators.py:64
#, fuzzy
msgid "" msgid ""
"This value must contain only letters, numbers, underscores, dashes or " "This value must contain only letters, numbers, underscores, dashes or "
"slashes." "slashes."
@ -1651,7 +1628,7 @@ msgstr ""
#: core/validators.py:72 #: core/validators.py:72
msgid "Uppercase letters are not allowed here." msgid "Uppercase letters are not allowed here."
msgstr "Tor skrift er ikke tillatt her." msgstr "Stor bokstaver er ikke tillatt her."
#: core/validators.py:76 #: core/validators.py:76
msgid "Lowercase letters are not allowed here." msgid "Lowercase letters are not allowed here."
@ -1687,19 +1664,19 @@ msgstr "Skriv inn et helt nummer."
#: core/validators.py:120 #: core/validators.py:120
msgid "Only alphabetical characters are allowed here." msgid "Only alphabetical characters are allowed here."
msgstr "Bare alfabetiske bokstaber er tillatt her." msgstr "Bare alfabetiske bokstaver er tillatt her."
#: core/validators.py:124 #: core/validators.py:124
msgid "Enter a valid date in YYYY-MM-DD format." msgid "Enter a valid date in YYYY-MM-DD format."
msgstr "Skriv inn en dato i ÅÅÅÅ-MM-DD formatet." msgstr "Skriv inn en dato i ÅÅÅÅ-MM-DD format."
#: core/validators.py:128 #: core/validators.py:128
msgid "Enter a valid time in HH:MM format." msgid "Enter a valid time in HH:MM format."
msgstr "Skriv inn tiden i TT:MM formatet." msgstr "Skriv inn tiden i TT:MM format."
#: core/validators.py:132 db/models/fields/__init__.py:468 #: core/validators.py:132 db/models/fields/__init__.py:468
msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format." msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
msgstr "Skriv inn dato og tid i ÅÅÅÅ-MM-DD TT:MM formatet." msgstr "Skriv inn dato og tid i ÅÅÅÅ-MM-DD TT:MM format."
#: core/validators.py:136 #: core/validators.py:136
msgid "Enter a valid e-mail address." msgid "Enter a valid e-mail address."
@ -1722,7 +1699,7 @@ msgstr "Internettadressen %s peker ikke til et godkjent bilde."
#, python-format #, python-format
msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid." msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
msgstr "" msgstr ""
"Telefon nummeret må være i XXX-XXX-XXXX formatet. \"%s\" er ikke godkjent." "Telefon nummeret må være i XXX-XXX-XXXX format. \"%s\" er ikke godkjent."
#: core/validators.py:167 #: core/validators.py:167
#, python-format #, python-format
@ -1731,7 +1708,7 @@ msgstr "Internettadressen %s peker ikke til en godkjent QuickTime film."
#: core/validators.py:171 #: core/validators.py:171
msgid "A valid URL is required." msgid "A valid URL is required."
msgstr "En godkjent internettadresse er påbudt." msgstr "En godkjent internettadresse er påkrevd."
#: core/validators.py:185 #: core/validators.py:185
#, python-format #, python-format
@ -1739,7 +1716,7 @@ msgid ""
"Valid HTML is required. Specific errors are:\n" "Valid HTML is required. Specific errors are:\n"
"%s" "%s"
msgstr "" msgstr ""
"Godkjent HTML er påbudt. Feilene var:\n" "Godkjent HTML er påkrevd. Feilene var:\n"
"%s" "%s"
#: core/validators.py:192 #: core/validators.py:192
@ -1750,7 +1727,7 @@ msgstr "Ikke godkjent XML: %s"
#: core/validators.py:202 #: core/validators.py:202
#, python-format #, python-format
msgid "Invalid URL: %s" msgid "Invalid URL: %s"
msgstr "Ikke godkjent internettadresse: %s" msgstr "Ikke godkjent URL: %s"
#: core/validators.py:206 core/validators.py:208 #: core/validators.py:206 core/validators.py:208
#, python-format #, python-format
@ -1759,7 +1736,7 @@ msgstr "Internettadresse fører til en side som ikke virker."
#: core/validators.py:214 #: core/validators.py:214
msgid "Enter a valid U.S. state abbreviation." msgid "Enter a valid U.S. state abbreviation."
msgstr "Skriv inn en godkjent amerikansk stats forkortelse." msgstr "Skriv inn en godkjent amerikansk delstat forkortelse."
#: core/validators.py:229 #: core/validators.py:229
#, python-format #, python-format
@ -1771,7 +1748,7 @@ msgstr[1] "Pass munnen din! Ordene %s er ikke tillatt her."
#: core/validators.py:236 #: core/validators.py:236
#, python-format #, python-format
msgid "This field must match the '%s' field." msgid "This field must match the '%s' field."
msgstr "Dette felte må være det samme som i '%s' feltet." msgstr "Dette feltet må være det samme som i '%s' feltet."
#: core/validators.py:255 #: core/validators.py:255
msgid "Please enter something for at least one field." msgid "Please enter something for at least one field."
@ -1784,12 +1761,12 @@ msgstr "Vennligst skriv inn noe i begge felta, eller la dem stå blanke."
#: core/validators.py:282 #: core/validators.py:282
#, python-format #, python-format
msgid "This field must be given if %(field)s is %(value)s" msgid "This field must be given if %(field)s is %(value)s"
msgstr "Dette feltet må bare brukes vist %(field)s er lik %(value)s" msgstr "Dette feltet må bare brukes hvis %(field)s er lik %(value)s"
#: core/validators.py:294 #: core/validators.py:294
#, python-format #, python-format
msgid "This field must be given if %(field)s is not %(value)s" msgid "This field must be given if %(field)s is not %(value)s"
msgstr "Dette feltet må bare brukes vist %(field)s ikke er lik %(value)s" msgstr "Dette feltet må bare brukes hvis %(field)s ikke er lik %(value)s"
#: core/validators.py:313 #: core/validators.py:313
msgid "Duplicate values are not allowed." msgid "Duplicate values are not allowed."
@ -1824,13 +1801,13 @@ msgstr[1] "Skriv inn et desimal tall med maksimum %s tall bak komma. "
#, python-format #, python-format
msgid "Make sure your uploaded file is at least %s bytes big." msgid "Make sure your uploaded file is at least %s bytes big."
msgstr "" msgstr ""
"Er du sikker på at fila du prøver å laste opp er minimum %s bytes stor?" "Vær sikker på at fila du prøver å laste opp er minimum %s bytes stor."
#: core/validators.py:363 #: core/validators.py:363
#, python-format #, python-format
msgid "Make sure your uploaded file is at most %s bytes big." msgid "Make sure your uploaded file is at most %s bytes big."
msgstr "" msgstr ""
"Er du sikker på at fila du prøver å laste opp er maksimum %s bytes stor?" "Vær sikker på at fila du prøver å laste opp er maksimum %s bytes stor."
#: core/validators.py:376 #: core/validators.py:376
msgid "The format for this field is wrong." msgid "The format for this field is wrong."
@ -1850,7 +1827,7 @@ msgstr "Klarte ikke å motta noe fra %s."
msgid "" msgid ""
"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
msgstr "" msgstr ""
"Tnternettadressen %(url)s returnerte en ikke godkjent Content-Type '%" "Internettadressen %(url)s returnerte en ikke godkjent Content-Type '%"
"(contenttype)s'." "(contenttype)s'."
#: core/validators.py:462 #: core/validators.py:462
@ -1859,7 +1836,7 @@ msgid ""
"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with " "Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "
"\"%(start)s\".)" "\"%(start)s\".)"
msgstr "" msgstr ""
"Vennligst lukk taggen %(tag)s på linje %(line)s. (Linja starer med \"%(start)" "Vennligst lukk taggen %(tag)s på linje %(line)s. (Linjen starer med \"%(start)"
"s\".)" "s\".)"
#: core/validators.py:466 #: core/validators.py:466
@ -1868,7 +1845,7 @@ msgid ""
"Some text starting on line %(line)s is not allowed in that context. (Line " "Some text starting on line %(line)s is not allowed in that context. (Line "
"starts with \"%(start)s\".)" "starts with \"%(start)s\".)"
msgstr "" msgstr ""
"Noe av teksten som starter på linje %(line)s er ikke tillatt. (Linja starter " "Noe av teksten som starter på linje %(line)s er ikke tillatt. (Linjen starter "
"med \"%(start)s\".)" "med \"%(start)s\".)"
#: core/validators.py:471 #: core/validators.py:471
@ -1877,7 +1854,7 @@ msgid ""
"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%" "\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%"
"(start)s\".)" "(start)s\".)"
msgstr "" msgstr ""
"\"%(attr)s\" på linje %(line)s er ikke en godkjent tillegg. (Linja starter " "\"%(attr)s\" på linje %(line)s er ikke en godkjent tillegg. (Linjen starter "
"med \"%(start)s\".)" "med \"%(start)s\".)"
#: core/validators.py:476 #: core/validators.py:476
@ -1886,7 +1863,7 @@ msgid ""
"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%" "\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%"
"(start)s\".)" "(start)s\".)"
msgstr "" msgstr ""
"\"<%(tag)s>\" på linje %(line)s er ikke en godkjent tag. (linja starter med " "\"<%(tag)s>\" på linje %(line)s er ikke en godkjent tag. (linjen starter med "
"\"%(start)s\".)" "\"%(start)s\".)"
#: core/validators.py:480 #: core/validators.py:480
@ -1895,7 +1872,7 @@ msgid ""
"A tag on line %(line)s is missing one or more required attributes. (Line " "A tag on line %(line)s is missing one or more required attributes. (Line "
"starts with \"%(start)s\".)" "starts with \"%(start)s\".)"
msgstr "" msgstr ""
"En tag på linje %(line)s mangler en av de påbydte tillegga. (linja starter " "En tag på linje %(line)s mangler en av de påkrevde attributtene. (linjen starter "
"med \"%(start)s\".)" "med \"%(start)s\".)"
#: core/validators.py:485 #: core/validators.py:485
@ -1904,13 +1881,13 @@ msgid ""
"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line " "The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line "
"starts with \"%(start)s\".)" "starts with \"%(start)s\".)"
msgstr "" msgstr ""
"\"%(attr)s\" tillegg på linje $(line)s har en ikke godkjent verdi. (Linja " "\"%(attr)s\" tillegg på linje $(line)s har en ikke godkjent verdi. (Linjen "
"starter med \"%(start)s\".)" "starter med \"%(start)s\".)"
#: db/models/manipulators.py:302 #: db/models/manipulators.py:302
#, fuzzy, python-format #, python-format
msgid "%(object)s with this %(type)s already exists for the given %(field)s." msgid "%(object)s with this %(type)s already exists for the given %(field)s."
msgstr "$(optname)s med %(fieldname)s finnes allerede." msgstr "%(object)s med %(type)s finnes allerede for angitt %(field)s."
#: db/models/fields/__init__.py:40 #: db/models/fields/__init__.py:40
#, python-format #, python-format
@ -1924,37 +1901,31 @@ msgid "This field is required."
msgstr "Dette feltet er påkrevd." msgstr "Dette feltet er påkrevd."
#: db/models/fields/__init__.py:337 #: db/models/fields/__init__.py:337
#, fuzzy
msgid "This value must be an integer." msgid "This value must be an integer."
msgstr "Denne verdien må være 'power' av %s." msgstr "Denne verdien må være et heltall."
#: db/models/fields/__init__.py:369 #: db/models/fields/__init__.py:369
#, fuzzy
msgid "This value must be either True or False." msgid "This value must be either True or False."
msgstr "Denne verdien må være 'power' av %s." msgstr "Denne verdien må være enten \"True\" eller \"False\"."
#: db/models/fields/__init__.py:385 #: db/models/fields/__init__.py:385
#, fuzzy
msgid "This field cannot be null." msgid "This field cannot be null."
msgstr "Dette feltet er feil." msgstr "Dette feltet kan ikke være null/tom."
#: db/models/fields/__init__.py:562 #: db/models/fields/__init__.py:562
#, fuzzy
msgid "Enter a valid filename." msgid "Enter a valid filename."
msgstr "Skriv inn en godkjent e-post adresse." msgstr "Skriv inn et godkjent fil navn."
#: db/models/fields/related.py:43 #: db/models/fields/related.py:43
#, fuzzy, python-format #, python-format
msgid "Please enter a valid %s." msgid "Please enter a valid %s."
msgstr "Vennligst skriv inn en godkjent IP adresse." msgstr "Vennligst skriv inn en/et gyldig %s."
#: db/models/fields/related.py:579 #: db/models/fields/related.py:579
#, fuzzy
msgid "Separate multiple IDs with commas." msgid "Separate multiple IDs with commas."
msgstr "Separer Id-ene med kommaer." msgstr "Separer Id-ene med kommaer."
#: db/models/fields/related.py:581 #: db/models/fields/related.py:581
#, fuzzy
msgid "" msgid ""
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one." "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgstr "" msgstr ""
@ -1965,14 +1936,14 @@ msgstr ""
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid." msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
msgid_plural "" msgid_plural ""
"Please enter valid %(self)s IDs. The values %(value)r are invalid." "Please enter valid %(self)s IDs. The values %(value)r are invalid."
msgstr[0] "" msgstr[0] "Skriv inn gyldige %(self)s ID-er. Verdien %(value)r er ikke gyldig."
msgstr[1] "" msgstr[1] "Skriv inn gyldige %(self)s ID-er. Verdiene %(value)r er ikke gyldige."
#: forms/__init__.py:380 #: forms/__init__.py:380
#, fuzzy, python-format #, python-format
msgid "Ensure your text is less than %s character." msgid "Ensure your text is less than %s character."
msgid_plural "Ensure your text is less than %s characters." msgid_plural "Ensure your text is less than %s characters."
msgstr[0] "Sjekk at teksten er kortere enn %s bokstaver" msgstr[0] "Sjekk at teksten er kortere enn %s bokstav"
msgstr[1] "Sjekk at teksten er kortere enn %s bokstaver" msgstr[1] "Sjekk at teksten er kortere enn %s bokstaver"
#: forms/__init__.py:385 #: forms/__init__.py:385
@ -1982,7 +1953,7 @@ msgstr "Det er ikke tillatt med flere linjer her."
#: forms/__init__.py:480 forms/__init__.py:551 forms/__init__.py:589 #: forms/__init__.py:480 forms/__init__.py:551 forms/__init__.py:589
#, python-format #, python-format
msgid "Select a valid choice; '%(data)s' is not in %(choices)s." msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
msgstr "Velg et av valga; '%(data)s' er ikke i %(choices)s." msgstr "Velg et gyldig valg; '%(data)s' er ikke i %(choices)s."
#: forms/__init__.py:645 #: forms/__init__.py:645
msgid "The submitted file is empty." msgid "The submitted file is empty."
@ -2002,7 +1973,7 @@ msgstr "Skriv inn et heltall mellom 0 og 32767."
#: template/defaultfilters.py:379 #: template/defaultfilters.py:379
msgid "yes,no,maybe" msgid "yes,no,maybe"
msgstr "" msgstr "ja,nei,kanskje"
#, fuzzy #, fuzzy
#~ msgid "Comments" #~ msgid "Comments"

View File

@ -61,6 +61,15 @@ msgstr "Søndag Mandag Tirsdag Onsdag Torsdag Fredag Lørdag"
msgid "S M T W T F S" msgid "S M T W T F S"
msgstr "S M T O T F L" msgstr "S M T O T F L"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
msgid "Show"
msgstr "Vis"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
msgid "Hide"
msgstr "Skjul"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
msgid "Now" msgid "Now"
@ -80,7 +89,7 @@ msgstr "24.00"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "6 a.m." msgid "6 a.m."
msgstr "18.00" msgstr "06.00"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "Noon" msgid "Noon"

View File

@ -126,12 +126,10 @@ msgid "approved by staff"
msgstr "zaakceptowano" msgstr "zaakceptowano"
#: contrib/comments/models.py:176 #: contrib/comments/models.py:176
#, fuzzy
msgid "free comment" msgid "free comment"
msgstr "wolny komentarz" msgstr "wolny komentarz"
#: contrib/comments/models.py:177 #: contrib/comments/models.py:177
#, fuzzy
msgid "free comments" msgid "free comments"
msgstr "wolne komentarze" msgstr "wolne komentarze"
@ -144,7 +142,6 @@ msgid "score date"
msgstr "data przyznania punktów" msgstr "data przyznania punktów"
#: contrib/comments/models.py:237 #: contrib/comments/models.py:237
#, fuzzy
msgid "karma score" msgid "karma score"
msgstr "ilość punktów" msgstr "ilość punktów"
@ -243,6 +240,9 @@ msgid ""
"\n" "\n"
"%(text)s" "%(text)s"
msgstr "" msgstr ""
"Ten komentarze został dodany przez użytkownika::\n"
"\n"
"%(text)s"
#: contrib/comments/views/comments.py:189 #: contrib/comments/views/comments.py:189
#: contrib/comments/views/comments.py:280 #: contrib/comments/views/comments.py:280
@ -257,19 +257,20 @@ msgstr "Jedno lub więcej wymaganych pól nie zostało wypełnionych"
#: contrib/comments/views/comments.py:197 #: contrib/comments/views/comments.py:197
#: contrib/comments/views/comments.py:286 #: contrib/comments/views/comments.py:286
msgid "Somebody tampered with the comment form (security violation)" msgid "Somebody tampered with the comment form (security violation)"
msgstr "" msgstr "Ktoś próbował obejść zabezpieczenia formularza komentarzy"
#: contrib/comments/views/comments.py:207 #: contrib/comments/views/comments.py:207
#: contrib/comments/views/comments.py:292 #: contrib/comments/views/comments.py:292
msgid "" msgid ""
"The comment form had an invalid 'target' parameter -- the object ID was " "The comment form had an invalid 'target' parameter -- the object ID was "
"invalid" "invalid"
msgstr "" msgstr "Formularz komentarza miał niepoprawny parametr 'target' -- ID obiektu było "
"niepoprawne"
#: contrib/comments/views/comments.py:257 #: contrib/comments/views/comments.py:257
#: contrib/comments/views/comments.py:321 #: contrib/comments/views/comments.py:321
msgid "The comment form didn't provide either 'preview' or 'post'" msgid "The comment form didn't provide either 'preview' or 'post'"
msgstr "" msgstr "Formularz komentarza nie zapewnił obiektów 'preview' ani 'post'"
#: contrib/comments/templates/comments/form.html:6 #: contrib/comments/templates/comments/form.html:6
#: contrib/comments/templates/comments/form.html:8 #: contrib/comments/templates/comments/form.html:8
@ -600,7 +601,7 @@ msgstr "Wartość logiczna (True, False, None - prawda, fałsz lub nic)"
#: contrib/admin/views/doc.py:292 #: contrib/admin/views/doc.py:292
msgid "Relation to parent model" msgid "Relation to parent model"
msgstr "" msgstr "Relacja do modelu rodzica"
#: contrib/admin/views/doc.py:293 #: contrib/admin/views/doc.py:293
msgid "Phone number" msgid "Phone number"
@ -794,6 +795,9 @@ msgid ""
"objects, but your account doesn't have permission to delete the following " "objects, but your account doesn't have permission to delete the following "
"types of objects:" "types of objects:"
msgstr "" msgstr ""
"Skasowanie %(object_name)s '%(object)s' spowoduje kasację zależnych "
"obiektów, lecz twoje uprawnienia nie pozwalają na usunięcie następujących "
"typów obiektów:"
#: contrib/admin/templates/admin/delete_confirmation.html:21 #: contrib/admin/templates/admin/delete_confirmation.html:21
#, python-format #, python-format
@ -801,6 +805,8 @@ msgid ""
"Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of " "Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of "
"the following related items will be deleted:" "the following related items will be deleted:"
msgstr "" msgstr ""
"Czy chcesz skasować %(object_name)s \"%(object)s\"? Wszystkie "
"zależne obiekty zostaną skasowane:"
#: contrib/admin/templates/admin/delete_confirmation.html:26 #: contrib/admin/templates/admin/delete_confirmation.html:26
msgid "Yes, I'm sure" msgid "Yes, I'm sure"
@ -820,11 +826,10 @@ msgid "View on site"
msgstr "Pokaż na stronie" msgstr "Pokaż na stronie"
#: contrib/admin/templates/admin/change_form.html:30 #: contrib/admin/templates/admin/change_form.html:30
#, fuzzy
msgid "Please correct the error below." msgid "Please correct the error below."
msgid_plural "Please correct the errors below." msgid_plural "Please correct the errors below."
msgstr[0] "Proszę popraw poniższy błąd" msgstr[0] "Proszę popraw poniższy błąd"
msgstr[1] "Proszę popraw poniższy błąd" msgstr[1] "Proszę popraw poniższe błędy"
#: contrib/admin/templates/admin/change_form.html:48 #: contrib/admin/templates/admin/change_form.html:48
msgid "Ordering" msgid "Ordering"
@ -965,11 +970,11 @@ msgstr "Zespół %(site_name)s"
#: contrib/admin/templates/admin_doc/bookmarklets.html:3 #: contrib/admin/templates/admin_doc/bookmarklets.html:3
msgid "Bookmarklets" msgid "Bookmarklets"
msgstr "" msgstr "Zakładki"
#: contrib/admin/templates/admin_doc/bookmarklets.html:5 #: contrib/admin/templates/admin_doc/bookmarklets.html:5
msgid "Documentation bookmarklets" msgid "Documentation bookmarklets"
msgstr "" msgstr "Zakładki Dokumentacji"
#: contrib/admin/templates/admin_doc/bookmarklets.html:9 #: contrib/admin/templates/admin_doc/bookmarklets.html:9
msgid "" msgid ""
@ -1094,6 +1099,8 @@ msgid ""
"Example: 'flatpages/contact_page'. If this isn't provided, the system will " "Example: 'flatpages/contact_page'. If this isn't provided, the system will "
"use 'flatpages/default'." "use 'flatpages/default'."
msgstr "" msgstr ""
"Przykład: 'flatpages/contact_page'. Jeżeli nie podane system użyje "
"'flatpages/default'."
#: contrib/flatpages/models.py:14 #: contrib/flatpages/models.py:14
msgid "registration required" msgid "registration required"
@ -1105,11 +1112,11 @@ msgstr "Jeżeli zaznaczone - tylko zalogowani użytkownicy będą mogli zobaczy
#: contrib/flatpages/models.py:18 #: contrib/flatpages/models.py:18
msgid "flat page" msgid "flat page"
msgstr "" msgstr "strona statyczna"
#: contrib/flatpages/models.py:19 #: contrib/flatpages/models.py:19
msgid "flat pages" msgid "flat pages"
msgstr "" msgstr "strony statyczne"
#: contrib/auth/models.py:13 contrib/auth/models.py:26 #: contrib/auth/models.py:13 contrib/auth/models.py:26
msgid "name" msgid "name"
@ -1117,7 +1124,7 @@ msgstr "nazwa"
#: contrib/auth/models.py:15 #: contrib/auth/models.py:15
msgid "codename" msgid "codename"
msgstr "" msgstr "nazwa kodowa"
#: contrib/auth/models.py:17 #: contrib/auth/models.py:17
msgid "permission" msgid "permission"
@ -1161,11 +1168,11 @@ msgstr "Użyj '[algo]$[salt]$[hexdigest]'"
#: contrib/auth/models.py:60 #: contrib/auth/models.py:60
msgid "staff status" msgid "staff status"
msgstr "stan w zespole" msgstr "w zespole"
#: contrib/auth/models.py:60 #: contrib/auth/models.py:60
msgid "Designates whether the user can log into this admin site." msgid "Designates whether the user can log into this admin site."
msgstr "Oznaczy czy użytkownik może zalogować się do panelu admina." msgstr "Oznacza czy użytkownik może zalogować się do panelu admina."
#: contrib/auth/models.py:61 #: contrib/auth/models.py:61
msgid "active" msgid "active"
@ -1195,15 +1202,14 @@ msgstr ""
msgid "user permissions" msgid "user permissions"
msgstr "uprawnienia użytkownika" msgstr "uprawnienia użytkownika"
#kurwa
#: contrib/auth/models.py:70 #: contrib/auth/models.py:70
#, fuzzy
msgid "user" msgid "user"
msgstr "Użytkownik" msgstr "użytkownik"
#: contrib/auth/models.py:71 #: contrib/auth/models.py:71
#, fuzzy
msgid "users" msgid "users"
msgstr "Uzytkownicy" msgstr "ytkownicy"
#: contrib/auth/models.py:76 #: contrib/auth/models.py:76
msgid "Personal info" msgid "Personal info"
@ -1222,7 +1228,6 @@ msgid "Groups"
msgstr "Grupy" msgstr "Grupy"
#: contrib/auth/models.py:219 #: contrib/auth/models.py:219
#, fuzzy
msgid "message" msgid "message"
msgstr "wiadomość" msgstr "wiadomość"
@ -1371,7 +1376,6 @@ msgid "December"
msgstr "Grudzień" msgstr "Grudzień"
#: utils/dates.py:19 #: utils/dates.py:19
#, fuzzy
msgid "jan" msgid "jan"
msgstr "sty" msgstr "sty"
@ -1472,11 +1476,10 @@ msgstr[0] "dzień"
msgstr[1] "dni" msgstr[1] "dni"
#: utils/timesince.py:16 #: utils/timesince.py:16
#, fuzzy
msgid "hour" msgid "hour"
msgid_plural "hours" msgid_plural "hours"
msgstr[0] "godzina" msgstr[0] "godzina"
msgstr[1] "godzina" msgstr[1] "godzin"
#: utils/timesince.py:17 #: utils/timesince.py:17
msgid "minute" msgid "minute"
@ -1569,7 +1572,6 @@ msgid "Slovak"
msgstr "Słowacki" msgstr "Słowacki"
#: conf/global_settings.py:58 #: conf/global_settings.py:58
#, fuzzy
msgid "Slovenian" msgid "Slovenian"
msgstr "Słowacki" msgstr "Słowacki"
@ -1582,9 +1584,8 @@ msgid "Swedish"
msgstr "Szwedzki" msgstr "Szwedzki"
#: conf/global_settings.py:61 #: conf/global_settings.py:61
#, fuzzy
msgid "Ukrainian" msgid "Ukrainian"
msgstr "Brazylijski" msgstr "Ukraiński"
#: conf/global_settings.py:62 #: conf/global_settings.py:62
msgid "Simplified Chinese" msgid "Simplified Chinese"
@ -1715,14 +1716,14 @@ msgstr "Odnośnik %s jest nieprawidłowy."
#: core/validators.py:214 #: core/validators.py:214
msgid "Enter a valid U.S. state abbreviation." msgid "Enter a valid U.S. state abbreviation."
msgstr "Wpisz poprawny kod stanu U.S." msgstr "Wpisz poprawny kod stanu U.S.A."
#: core/validators.py:229 #: core/validators.py:229
#, fuzzy, python-format #, python-format
msgid "Watch your mouth! The word %s is not allowed here." msgid "Watch your mouth! The word %s is not allowed here."
msgid_plural "Watch your mouth! The words %s are not allowed here." msgid_plural "Watch your mouth! The words %s are not allowed here."
msgstr[0] "Nie wolno przeklinać! Słowo %s jest niedozwolone." msgstr[0] "Nie wolno przeklinać! Słowo %s jest niedozwolone."
msgstr[1] "Nie wolno przeklinać! Słowo %s jest niedozwolone." msgstr[1] "Nie wolno przeklinać! Słowa %s są niedozwolone."
#: core/validators.py:236 #: core/validators.py:236
#, python-format #, python-format
@ -1745,11 +1746,11 @@ msgstr "To pole musi być uzupełnione jeśli %(field)s jest %(value)s"
#: core/validators.py:294 #: core/validators.py:294
#, python-format #, python-format
msgid "This field must be given if %(field)s is not %(value)s" msgid "This field must be given if %(field)s is not %(value)s"
msgstr "" msgstr "To pole musi być wypełnione jeżeli %(field)s nie jest %(value)s"
#: core/validators.py:313 #: core/validators.py:313
msgid "Duplicate values are not allowed." msgid "Duplicate values are not allowed."
msgstr "" msgstr "Duplikaty są niedozwolone."
#: core/validators.py:336 #: core/validators.py:336
#, python-format #, python-format
@ -1761,20 +1762,20 @@ msgid "Please enter a valid decimal number."
msgstr "Proszę wpisać poprawną liczbę dziesiętną." msgstr "Proszę wpisać poprawną liczbę dziesiętną."
#: core/validators.py:349 #: core/validators.py:349
#, fuzzy, python-format #, python-format
msgid "Please enter a valid decimal number with at most %s total digit." msgid "Please enter a valid decimal number with at most %s total digit."
msgid_plural "" msgid_plural ""
"Please enter a valid decimal number with at most %s total digits." "Please enter a valid decimal number with at most %s total digits."
msgstr[0] "Proszę wpisać poprawną liczbę dziesiętną." msgstr[0] "Proszę wpisać poprawną liczbę dziesiętną zawierającą nie więcej niż %s cyfry."
msgstr[1] "Proszę wpisać poprawną liczbę dziesiętną." msgstr[1] "Proszę wpisać poprawną liczbę dziesiętną zawierającą nie więcej niż %s cyfr."
#: core/validators.py:352 #: core/validators.py:352
#, fuzzy, python-format #, python-format
msgid "Please enter a valid decimal number with at most %s decimal place." msgid "Please enter a valid decimal number with at most %s decimal place."
msgid_plural "" msgid_plural ""
"Please enter a valid decimal number with at most %s decimal places." "Please enter a valid decimal number with at most %s decimal places."
msgstr[0] "Proszę wpisać poprawną liczbę dziesiętną." msgstr[0] "Proszę wpisać poprawną liczbę dziesiętną z dokładnością do %s miejsca po przecinku."
msgstr[1] "Proszę wpisać poprawną liczbę dziesiętną." msgstr[1] "Proszę wpisać poprawną liczbę dziesiętną z dokładnością do %s miejsc po przecinku."
#: core/validators.py:362 #: core/validators.py:362
#, python-format #, python-format
@ -1797,13 +1798,14 @@ msgstr "To pole jest nieprawidłowe."
#: core/validators.py:426 #: core/validators.py:426
#, python-format #, python-format
msgid "Could not retrieve anything from %s." msgid "Could not retrieve anything from %s."
msgstr "Nie można otrzymać nic z %s." msgstr "Nie można nic pobrać z %s."
#: core/validators.py:429 #: core/validators.py:429
#, python-format #, python-format
msgid "" msgid ""
"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
msgstr "" msgstr ""
"URL %(url)s zwrócił niepoprawny Content-Type header '%(contenttype)s'."
#: core/validators.py:462 #: core/validators.py:462
@ -1866,17 +1868,15 @@ msgstr "To pole jest wymagane"
#: db/models/fields/__init__.py:337 #: db/models/fields/__init__.py:337
msgid "This value must be an integer." msgid "This value must be an integer."
msgstr "" msgstr "Ta wartość musi być liczbą całkowitą"
#: db/models/fields/__init__.py:369 #: db/models/fields/__init__.py:369
#, fuzzy
msgid "This value must be either True or False." msgid "This value must be either True or False."
msgstr "Wartość logiczna (True, False - prawda lub fałsz)" msgstr "Ta wartość musi być logiczna (True, False - prawda lub fałsz)."
#: db/models/fields/__init__.py:385 #: db/models/fields/__init__.py:385
#, fuzzy
msgid "This field cannot be null." msgid "This field cannot be null."
msgstr "To pole jest nieprawidłowe." msgstr "To pole nie może być puste."
#: db/models/fields/__init__.py:562 #: db/models/fields/__init__.py:562
msgid "Enter a valid filename." msgid "Enter a valid filename."
@ -1888,12 +1888,10 @@ msgid "Please enter a valid %s."
msgstr "Proszę wpisać poprawne %s." msgstr "Proszę wpisać poprawne %s."
#: db/models/fields/related.py:579 #: db/models/fields/related.py:579
#, fuzzy
msgid "Separate multiple IDs with commas." msgid "Separate multiple IDs with commas."
msgstr "Oddziel kilka pól ID przecinkami." msgstr "Oddziel kilka pól ID przecinkami."
#: db/models/fields/related.py:581 #: db/models/fields/related.py:581
#, fuzzy
msgid "" msgid ""
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one." "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgstr "" msgstr ""
@ -1909,11 +1907,11 @@ msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: forms/__init__.py:380 #: forms/__init__.py:380
#, fuzzy, python-format #, python-format
msgid "Ensure your text is less than %s character." msgid "Ensure your text is less than %s character."
msgid_plural "Ensure your text is less than %s characters." msgid_plural "Ensure your text is less than %s characters."
msgstr[0] "Upewnij się, że jest mniej niż %s znaków." msgstr[0] "Upewnij się, że tekst ma mniej niż %s znak."
msgstr[1] "Upewnij się, że jest mniej niż %s znaków." msgstr[1] "Upewnij się, że tekst ma mniej niż %s znaków."
#: forms/__init__.py:385 #: forms/__init__.py:385
msgid "Line breaks are not allowed here." msgid "Line breaks are not allowed here."

File diff suppressed because it is too large Load Diff

View File

@ -171,7 +171,6 @@ var DateTimeShortcuts = {
cal_nav_prev.className = 'calendarnav-previous'; cal_nav_prev.className = 'calendarnav-previous';
var cal_nav_next = quickElement('a', cal_nav, '>', 'href', 'javascript:DateTimeShortcuts.drawNext('+num+');'); var cal_nav_next = quickElement('a', cal_nav, '>', 'href', 'javascript:DateTimeShortcuts.drawNext('+num+');');
cal_nav_next.className = 'calendarnav-next'; cal_nav_next.className = 'calendarnav-next';
cal_box.appendChild(cal_nav);
// main box // main box
var cal_main = quickElement('div', cal_box, '', 'id', DateTimeShortcuts.calendarDivName2 + num); var cal_main = quickElement('div', cal_box, '', 'id', DateTimeShortcuts.calendarDivName2 + num);

View File

@ -161,8 +161,10 @@ class EditInlineNode(template.Node):
context.push() context.push()
if relation.field.rel.edit_inline == models.TABULAR: if relation.field.rel.edit_inline == models.TABULAR:
bound_related_object_class = TabularBoundRelatedObject bound_related_object_class = TabularBoundRelatedObject
else: elif relation.field.rel.edit_inline == models.STACKED:
bound_related_object_class = StackedBoundRelatedObject bound_related_object_class = StackedBoundRelatedObject
else:
bound_related_object_class = relation.field.rel.edit_inline
original = context.get('original', None) original = context.get('original', None)
bound_related_object = relation.bind(context['form'], original, bound_related_object_class) bound_related_object = relation.bind(context['form'], original, bound_related_object_class)
context['bound_related_object'] = bound_related_object context['bound_related_object'] = bound_related_object

View File

@ -41,7 +41,6 @@ def paginator(context, adjacent_pages=2):
page_numbers = [n for n in \ page_numbers = [n for n in \
range(context["page"] - adjacent_pages, context["page"] + adjacent_pages + 1) \ range(context["page"] - adjacent_pages, context["page"] + adjacent_pages + 1) \
if n > 0 and n <= context["pages"]] if n > 0 and n <= context["pages"]]
print page_numbers
return { return {
"hits": context["hits"], "hits": context["hits"],
"results_per_page": context["results_per_page"], "results_per_page": context["results_per_page"],

View File

@ -1,3 +1,4 @@
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django import forms, template from django import forms, template
@ -5,6 +6,8 @@ from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
def user_add_stage(request): def user_add_stage(request):
if not request.user.has_perm('auth.change_user'):
raise PermissionDenied
manipulator = UserCreationForm() manipulator = UserCreationForm()
if request.method == 'POST': if request.method == 'POST':
new_data = request.POST.copy() new_data = request.POST.copy()
@ -38,3 +41,4 @@ def user_add_stage(request):
'opts': User._meta, 'opts': User._meta,
'username_help_text': User._meta.get_field('username').help_text, 'username_help_text': User._meta.get_field('username').help_text,
}, context_instance=template.RequestContext(request)) }, context_instance=template.RequestContext(request))
user_add_stage = staff_member_required(user_add_stage)

View File

@ -757,6 +757,8 @@ class ChangeList(object):
for bit in self.query.split(): for bit in self.query.split():
or_queries = [models.Q(**{construct_search(field_name): bit}) for field_name in self.lookup_opts.admin.search_fields] or_queries = [models.Q(**{construct_search(field_name): bit}) for field_name in self.lookup_opts.admin.search_fields]
other_qs = QuerySet(self.model) other_qs = QuerySet(self.model)
if qs._select_related:
other_qs = other_qs.select_related()
other_qs = other_qs.filter(reduce(operator.or_, or_queries)) other_qs = other_qs.filter(reduce(operator.or_, or_queries))
qs = qs & other_qs qs = qs & other_qs

View File

@ -26,3 +26,11 @@ login_required.__doc__ = (
to the log-in page if necessary. to the log-in page if necessary.
""" """
) )
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.
"""
return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)

View File

@ -22,6 +22,8 @@ def authenhandler(req, **kwargs):
os.environ['DJANGO_SETTINGS_MODULE'] = settings_module os.environ['DJANGO_SETTINGS_MODULE'] = settings_module
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django import db
db.reset_queries()
# check that the username is valid # check that the username is valid
kwargs = {'username': req.user, 'is_active': True} kwargs = {'username': req.user, 'is_active': True}
@ -30,18 +32,21 @@ def authenhandler(req, **kwargs):
if superuser_only: if superuser_only:
kwargs['is_superuser'] = True kwargs['is_superuser'] = True
try: try:
user = User.objects.get(**kwargs) try:
except User.DoesNotExist: user = User.objects.get(**kwargs)
return apache.HTTP_UNAUTHORIZED except User.DoesNotExist:
return apache.HTTP_UNAUTHORIZED
# check the password and any permission given
if user.check_password(req.get_basic_auth_pw()): # check the password and any permission given
if permission_name: if user.check_password(req.get_basic_auth_pw()):
if user.has_perm(permission_name): if permission_name:
return apache.OK if user.has_perm(permission_name):
return apache.OK
else:
return apache.HTTP_UNAUTHORIZED
else: else:
return apache.HTTP_UNAUTHORIZED return apache.OK
else: else:
return apache.OK return apache.HTTP_UNAUTHORIZED
else: finally:
return apache.HTTP_UNAUTHORIZED db.connection.close()

View File

@ -1,12 +1,9 @@
class LazyUser(object): class LazyUser(object):
def __init__(self):
self._user = None
def __get__(self, request, obj_type=None): def __get__(self, request, obj_type=None):
if self._user is None: if not hasattr(request, '_cached_user'):
from django.contrib.auth import get_user from django.contrib.auth import get_user
self._user = get_user(request) request._cached_user = get_user(request)
return self._user return request._cached_user
class AuthenticationMiddleware(object): class AuthenticationMiddleware(object):
def process_request(self, request): def process_request(self, request):

View File

@ -1,5 +1,6 @@
from django import template from django import template
from django.template import loader from django.template import loader
from django.conf import settings
register = template.Library() register = template.Library()
@ -28,28 +29,28 @@ def if_has_perm(parser, token):
else: else:
nodelist_false = template.NodeList() nodelist_false = template.NodeList()
object = None object_var = None
not_flag = False not_flag = False
if tokens[1] is "not": if tokens[1] is "not":
not_flag = True not_flag = True
permission=tokens[2] permission=tokens[2]
if len(tokens)>3: if len(tokens)>3:
object=tokens[3] object_var = parser.compile_filter(tokens[3])
else: else:
permission=tokens[1] permission=tokens[1]
if len(tokens)>2: if len(tokens)>2:
object=tokens[2] object_var = parser.compile_filter(tokens[2])
if not (permission[0] == permission[-1] and permission[0] in ('"', "'")): if not (permission[0] == permission[-1] and permission[0] in ('"', "'")):
raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tokens[0] raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tokens[0]
return HasPermNode(permission[1:-1], not_flag, object, nodelist_true, nodelist_false) return HasPermNode(permission[1:-1], not_flag, object_var, nodelist_true, nodelist_false)
class HasPermNode(template.Node): class HasPermNode(template.Node):
def __init__(self, permission, not_flag, object, nodelist_true, nodelist_false): def __init__(self, permission, not_flag, object_var, nodelist_true, nodelist_false):
self.permission = permission self.permission = permission
self.not_flag = not_flag self.not_flag = not_flag
self.object_name = object self.object_var = object_var
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
def __repr__(self): def __repr__(self):
@ -70,21 +71,20 @@ class HasPermNode(template.Node):
return nodes return nodes
def render(self, context): def render(self, context):
if self.object_name: if self.object_var:
try: try:
object = template.resolve_variable(self.object_name, context) object = self.object_var.resolve(context)
except template.VariableDoesNotExist: except template.VariableDoesNotExist:
return '' object = None
else: else:
object=None object=None
try: try:
user = template.resolve_variable("user", context) user = template.resolve_variable("user", context)
except template.VariableDoesNotExist: except template.VariableDoesNotExist:
return '' return settings.TEMPLATE_STRING_IF_INVALID
bool_perm = user.has_perm(self.permission, object=object) bool_perm = user.has_perm(self.permission, object=object)
if (self.not_flag and not bool_perm) or (not self.not_flag and bool_perm): if (self.not_flag and not bool_perm) or (not self.not_flag and bool_perm):
return self.nodelist_true.render(context) return self.nodelist_true.render(context)
if (self.not_flag and bool_perm) or (not self.not_flag and not bool_perm): if (self.not_flag and bool_perm) or (not self.not_flag and not bool_perm):

View File

@ -51,15 +51,19 @@ def request(request):
class PermLookupDict(object): class PermLookupDict(object):
def __init__(self, user, module_name): def __init__(self, user, module_name):
self.user, self.module_name = user, module_name self.user, self.module_name = user, module_name
def __repr__(self): def __repr__(self):
return str(self.user.get_permission_list()) return str(self.user.get_all_permissions())
def __getitem__(self, perm_name): def __getitem__(self, perm_name):
return self.user.has_perm("%s.%s" % (self.module_name, perm_name)) return self.user.has_perm("%s.%s" % (self.module_name, perm_name))
def __nonzero__(self): def __nonzero__(self):
return self.user.has_module_perms(self.module_name) return self.user.has_module_perms(self.module_name)
class PermWrapper(object): class PermWrapper(object):
def __init__(self, user): def __init__(self, user):
self.user = user self.user = user
def __getitem__(self, module_name): def __getitem__(self, module_name):
return PermLookupDict(self.user, module_name) return PermLookupDict(self.user, module_name)

View File

@ -155,8 +155,11 @@ def populate_apache_request(http_response, mod_python_req):
for c in http_response.cookies.values(): for c in http_response.cookies.values():
mod_python_req.headers_out.add('Set-Cookie', c.output(header='')) mod_python_req.headers_out.add('Set-Cookie', c.output(header=''))
mod_python_req.status = http_response.status_code mod_python_req.status = http_response.status_code
for chunk in http_response.iterator: try:
mod_python_req.write(chunk) for chunk in http_response:
mod_python_req.write(chunk)
finally:
http_response.close()
def handler(req): def handler(req):
# mod_python hooks into this function. # mod_python hooks into this function.

View File

@ -4,6 +4,11 @@ from django.dispatch import dispatcher
from django.utils import datastructures from django.utils import datastructures
from django import http from django import http
from pprint import pformat from pprint import pformat
from shutil import copyfileobj
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
STATUS_CODE_TEXT = { STATUS_CODE_TEXT = {
@ -50,6 +55,21 @@ STATUS_CODE_TEXT = {
505: 'HTTP VERSION NOT SUPPORTED', 505: 'HTTP VERSION NOT SUPPORTED',
} }
def safe_copyfileobj(fsrc, fdst, length=16*1024, size=0):
"""
A version of shutil.copyfileobj that will not read more than 'size' bytes.
This makes it safe from clients sending more than CONTENT_LENGTH bytes of
data in the body.
"""
if not size:
return copyfileobj(fsrc, fdst, length)
while size > 0:
buf = fsrc.read(min(length, size))
if not buf:
break
fdst.write(buf)
size -= len(buf)
class WSGIRequest(http.HttpRequest): class WSGIRequest(http.HttpRequest):
def __init__(self, environ): def __init__(self, environ):
self.environ = environ self.environ = environ
@ -119,7 +139,11 @@ class WSGIRequest(http.HttpRequest):
try: try:
return self._raw_post_data return self._raw_post_data
except AttributeError: except AttributeError:
self._raw_post_data = self.environ['wsgi.input'].read(int(self.environ["CONTENT_LENGTH"])) buf = StringIO()
content_length = int(self.environ['CONTENT_LENGTH'])
safe_copyfileobj(self.environ['wsgi.input'], buf, size=content_length)
self._raw_post_data = buf.getvalue()
buf.close()
return self._raw_post_data return self._raw_post_data
GET = property(_get_get, _set_get) GET = property(_get_get, _set_get)
@ -163,4 +187,4 @@ class WSGIHandler(BaseHandler):
for c in response.cookies.values(): for c in response.cookies.values():
response_headers.append(('Set-Cookie', c.output(header=''))) response_headers.append(('Set-Cookie', c.output(header='')))
start_response(status, response_headers) start_response(status, response_headers)
return response.iterator return response

View File

@ -492,7 +492,7 @@ def syncdb(verbosity=2, interactive=True):
# to do at this point. # to do at this point.
for app in models.get_apps(): for app in models.get_apps():
dispatcher.send(signal=signals.post_syncdb, sender=app, dispatcher.send(signal=signals.post_syncdb, sender=app,
app=app, created_models=created_models, app=app, created_models=created_models,
verbosity=verbosity, interactive=interactive) verbosity=verbosity, interactive=interactive)
# Install initial data for the app (but only if this is a model we've # Install initial data for the app (but only if this is a model we've
@ -552,7 +552,7 @@ def diffsettings():
# Inspired by Postfix's "postconf -n". # Inspired by Postfix's "postconf -n".
from django.conf import settings, global_settings from django.conf import settings, global_settings
user_settings = _module_to_dict(settings) user_settings = _module_to_dict(settings._target)
default_settings = _module_to_dict(global_settings) default_settings = _module_to_dict(global_settings)
output = [] output = []
@ -903,27 +903,32 @@ def get_validation_errors(outfile, app=None):
rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name()
rel_query_name = f.related_query_name() rel_query_name = f.related_query_name()
for r in rel_opts.fields: # If rel_name is none, there is no reverse accessor.
if r.name == rel_name: # (This only occurs for symmetrical m2m relations to self).
e.add(opts, "Accessor for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) # If this is the case, there are no clashes to check for this field, as
if r.name == rel_query_name: # there are no reverse descriptors for this field.
e.add(opts, "Reverse query name for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) if rel_name is not None:
for r in rel_opts.many_to_many: for r in rel_opts.fields:
if r.name == rel_name: if r.name == rel_name:
e.add(opts, "Accessor for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) e.add(opts, "Accessor for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
if r.name == rel_query_name: if r.name == rel_query_name:
e.add(opts, "Reverse query name for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) e.add(opts, "Reverse query name for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
for r in rel_opts.get_all_related_many_to_many_objects(): for r in rel_opts.many_to_many:
if r.field is not f: if r.name == rel_name:
e.add(opts, "Accessor for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
if r.name == rel_query_name:
e.add(opts, "Reverse query name for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
for r in rel_opts.get_all_related_many_to_many_objects():
if r.field is not f:
if r.get_accessor_name() == rel_name:
e.add(opts, "Accessor for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
if r.get_accessor_name() == rel_query_name:
e.add(opts, "Reverse query name for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
for r in rel_opts.get_all_related_objects():
if r.get_accessor_name() == rel_name: if r.get_accessor_name() == rel_name:
e.add(opts, "Accessor for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) e.add(opts, "Accessor for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
if r.get_accessor_name() == rel_query_name: if r.get_accessor_name() == rel_query_name:
e.add(opts, "Reverse query name for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) e.add(opts, "Reverse query name for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
for r in rel_opts.get_all_related_objects():
if r.get_accessor_name() == rel_name:
e.add(opts, "Accessor for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
if r.get_accessor_name() == rel_query_name:
e.add(opts, "Reverse query name for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
# Check admin attribute. # Check admin attribute.
if opts.admin is not None: if opts.admin is not None:
@ -953,7 +958,8 @@ def get_validation_errors(outfile, app=None):
try: try:
f = opts.get_field(fn) f = opts.get_field(fn)
except models.FieldDoesNotExist: except models.FieldDoesNotExist:
e.add(opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn) if not hasattr(cls, fn):
e.add(opts, '"admin.list_display_links" refers to %r, which isn\'t an attribute, method or property.' % fn)
if fn not in opts.admin.list_display: if fn not in opts.admin.list_display:
e.add(opts, '"admin.list_display_links" refers to %r, which is not defined in "admin.list_display".' % fn) e.add(opts, '"admin.list_display_links" refers to %r, which is not defined in "admin.list_display".' % fn)
# list_filter # list_filter
@ -1011,10 +1017,12 @@ def get_validation_errors(outfile, app=None):
return len(e.errors) return len(e.errors)
def validate(outfile=sys.stdout): def validate(outfile=sys.stdout, silent_success=False):
"Validates all installed models." "Validates all installed models."
try: try:
num_errors = get_validation_errors(outfile) num_errors = get_validation_errors(outfile)
if silent_success and num_errors == 0:
return
outfile.write('%s error%s found.\n' % (num_errors, num_errors != 1 and 's' or '')) outfile.write('%s error%s found.\n' % (num_errors, num_errors != 1 and 's' or ''))
except ImproperlyConfigured: except ImproperlyConfigured:
outfile.write("Skipping validation because things aren't configured properly.") outfile.write("Skipping validation because things aren't configured properly.")
@ -1167,7 +1175,7 @@ def test(verbosity, app_labels):
app_list = get_apps() app_list = get_apps()
else: else:
app_list = [get_app(app_label) for app_label in app_labels] app_list = [get_app(app_label) for app_label in app_labels]
test_path = settings.TEST_RUNNER.split('.') test_path = settings.TEST_RUNNER.split('.')
# Allow for Python 2.5 relative paths # Allow for Python 2.5 relative paths
if len(test_path) > 1: if len(test_path) > 1:
@ -1176,7 +1184,7 @@ def test(verbosity, app_labels):
test_module_name = '.' test_module_name = '.'
test_module = __import__(test_module_name, [],[],test_path[-1]) test_module = __import__(test_module_name, [],[],test_path[-1])
test_runner = getattr(test_module, test_path[-1]) test_runner = getattr(test_module, test_path[-1])
test_runner(app_list, verbosity) test_runner(app_list, verbosity)
test.help_doc = 'Runs the test suite for the specified applications, or the entire site if no apps are specified' test.help_doc = 'Runs the test suite for the specified applications, or the entire site if no apps are specified'
test.args = '[--verbosity] ' + APP_ARGS test.args = '[--verbosity] ' + APP_ARGS
@ -1331,6 +1339,7 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
action_mapping[action](args[1:]) action_mapping[action](args[1:])
else: else:
from django.db import models from django.db import models
validate(silent_success=True)
try: try:
mod_list = [models.get_app(app_label) for app_label in args[1:]] mod_list = [models.get_app(app_label) for app_label in args[1:]]
except ImportError, e: except ImportError, e:

View File

@ -16,7 +16,7 @@ class Serializer(PythonSerializer):
Convert a queryset to JSON. Convert a queryset to JSON.
""" """
def end_serialization(self): def end_serialization(self):
simplejson.dump(self.objects, self.stream, cls=DateTimeAwareJSONEncoder) simplejson.dump(self.objects, self.stream, cls=DateTimeAwareJSONEncoder, **self.options)
def getvalue(self): def getvalue(self):
return self.stream.getvalue() return self.stream.getvalue()

View File

@ -74,8 +74,9 @@ def fastcgi_help(message=None):
print message print message
return False return False
def runfastcgi(argset): def runfastcgi(argset=[], **kwargs):
options = FASTCGI_OPTIONS.copy() options = FASTCGI_OPTIONS.copy()
options.update(kwargs)
for x in argset: for x in argset:
if "=" in x: if "=" in x:
k, v = x.split('=', 1) k, v = x.split('=', 1)

View File

@ -227,9 +227,8 @@ def hasNoProfanities(field_data, all_data):
catch 'motherfucker' as well. Raises a ValidationError such as: catch 'motherfucker' as well. Raises a ValidationError such as:
Watch your mouth! The words "f--k" and "s--t" are not allowed here. Watch your mouth! The words "f--k" and "s--t" are not allowed here.
""" """
bad_words = ['asshat', 'asshead', 'asshole', 'cunt', 'fuck', 'gook', 'nigger', 'shit'] # all in lower case
field_data = field_data.lower() # normalize field_data = field_data.lower() # normalize
words_seen = [w for w in bad_words if field_data.find(w) > -1] words_seen = [w for w in settings.PROFANITIES_LIST if field_data.find(w) > -1]
if words_seen: if words_seen:
from django.utils.text import get_text_list from django.utils.text import get_text_list
plural = len(words_seen) > 1 plural = len(words_seen) > 1
@ -352,10 +351,12 @@ class IsValidFloat(object):
float(data) float(data)
except ValueError: except ValueError:
raise ValidationError, gettext("Please enter a valid decimal number.") raise ValidationError, gettext("Please enter a valid decimal number.")
if len(data) > (self.max_digits + 1): # Negative floats require more space to input.
max_allowed_length = data.startswith('-') and (self.max_digits + 2) or (self.max_digits + 1)
if len(data) > max_allowed_length:
raise ValidationError, ngettext("Please enter a valid decimal number with at most %s total digit.", 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 "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) > (self.max_digits - 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)) or ('.' in data and len(data) > (self.max_digits - (self.decimal_places - len(data.split('.')[1])) + 1)):
raise ValidationError, ngettext( "Please enter a valid decimal number with a whole part of at most %s digit.", 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) "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: if '.' in data and len(data.split('.')[1]) > self.decimal_places:

View File

@ -13,9 +13,10 @@ def populate_xheaders(request, response, model, object_id):
""" """
Adds the "X-Object-Type" and "X-Object-Id" headers to the given Adds the "X-Object-Type" and "X-Object-Id" headers to the given
HttpResponse according to the given model and object_id -- but only if the HttpResponse according to the given model and object_id -- but only if the
given HttpRequest object has an IP address within the INTERNAL_IPS setting. given HttpRequest object has an IP address within the INTERNAL_IPS setting
or if the request is from a logged in staff member.
""" """
from django.conf import settings from django.conf import settings
if request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS: if request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS or (request.user.is_authenticated() and request.user.is_staff):
response['X-Object-Type'] = "%s.%s" % (model._meta.app_label, model._meta.object_name.lower()) response['X-Object-Type'] = "%s.%s" % (model._meta.app_label, model._meta.object_name.lower())
response['X-Object-Id'] = str(object_id) response['X-Object-Id'] = str(object_id)

View File

@ -36,13 +36,14 @@ def get_relations(cursor, table_name):
SELECT column_name, referenced_table_name, referenced_column_name SELECT column_name, referenced_table_name, referenced_column_name
FROM information_schema.key_column_usage FROM information_schema.key_column_usage
WHERE table_name = %s WHERE table_name = %s
AND table_schema = DATABASE()
AND referenced_table_name IS NOT NULL AND referenced_table_name IS NOT NULL
AND referenced_column_name IS NOT NULL""", [table_name]) AND referenced_column_name IS NOT NULL""", [table_name])
constraints.extend(cursor.fetchall()) constraints.extend(cursor.fetchall())
except (ProgrammingError, OperationalError): except (ProgrammingError, OperationalError):
# Fall back to "SHOW CREATE TABLE", for previous MySQL versions. # Fall back to "SHOW CREATE TABLE", for previous MySQL versions.
# Go through all constraints and save the equal matches. # Go through all constraints and save the equal matches.
cursor.execute("SHOW CREATE TABLE %s" % table_name) cursor.execute("SHOW CREATE TABLE %s" % quote_name(table_name))
for row in cursor.fetchall(): for row in cursor.fetchall():
pos = 0 pos = 0
while True: while True:

View File

@ -110,9 +110,11 @@ def dictfetchone(cursor):
def dictfetchmany(cursor, number): def dictfetchmany(cursor, number):
"Returns a certain number of rows from a cursor as a dict" "Returns a certain number of rows from a cursor as a dict"
desc = cursor.description desc = cursor.description
return [_dict_helper(desc, row) for row in cursor.fetchmany(number)] for row in cursor.fetchmany(number):
yield _dict_helper(desc, row)
def dictfetchall(cursor): def dictfetchall(cursor):
"Returns all rows from a cursor as a dict" "Returns all rows from a cursor as a dict"
desc = cursor.description desc = cursor.description
return [_dict_helper(desc, row) for row in cursor.fetchall()] for row in cursor.fetchall():
yield _dict_helper(desc, row)

View File

@ -131,6 +131,9 @@ class RelatedObject(object):
# many-to-many objects. It uses the lower-cased object_name + "_set", # many-to-many objects. It uses the lower-cased object_name + "_set",
# but this can be overridden with the "related_name" option. # but this can be overridden with the "related_name" option.
if self.field.rel.multiple: if self.field.rel.multiple:
# If this is a symmetrical m2m relation on self, there is no reverse accessor.
if getattr(self.field.rel, 'symmetrical', False) and self.model == self.parent_model:
return None
return self.field.rel.related_name or (self.opts.object_name.lower() + '_set') return self.field.rel.related_name or (self.opts.object_name.lower() + '_set')
else: else:
return self.field.rel.related_name or (self.opts.object_name.lower()) return self.field.rel.related_name or (self.opts.object_name.lower())

View File

@ -434,11 +434,11 @@ class HiddenField(FormField):
(self.get_id(), self.field_name, escape(data)) (self.get_id(), self.field_name, escape(data))
class CheckboxField(FormField): class CheckboxField(FormField):
def __init__(self, field_name, checked_by_default=False, validator_list=None): def __init__(self, field_name, checked_by_default=False, validator_list=None, is_required=False):
if validator_list is None: validator_list = [] if validator_list is None: validator_list = []
self.field_name = field_name self.field_name = field_name
self.checked_by_default = checked_by_default self.checked_by_default = checked_by_default
self.is_required = False # because the validator looks for these self.is_required = is_required
self.validator_list = validator_list[:] self.validator_list = validator_list[:]
def render(self, data): def render(self, data):
@ -639,8 +639,8 @@ class CheckboxSelectMultipleField(SelectMultipleField):
checked_html = ' checked="checked"' checked_html = ' checked="checked"'
field_name = '%s%s' % (self.field_name, value) 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 /> <label for="%s">%s</label></li>' % \
(self.get_id() + value , self.__class__.__name__, field_name, checked_html, (self.get_id() + escape(value), self.__class__.__name__, field_name, checked_html,
self.get_id() + value, choice)) self.get_id() + escape(value), choice))
output.append('</ul>') output.append('</ul>')
return '\n'.join(output) return '\n'.join(output)
@ -743,7 +743,7 @@ class FloatField(TextField):
if validator_list is None: validator_list = [] if validator_list is None: validator_list = []
self.max_digits, self.decimal_places = max_digits, decimal_places self.max_digits, self.decimal_places = max_digits, decimal_places
validator_list = [self.isValidFloat] + validator_list validator_list = [self.isValidFloat] + validator_list
TextField.__init__(self, field_name, max_digits+1, max_digits+1, is_required, validator_list) TextField.__init__(self, field_name, max_digits+2, max_digits+2, is_required, validator_list)
def isValidFloat(self, field_data, all_data): def isValidFloat(self, field_data, all_data):
v = validators.IsValidFloat(self.max_digits, self.decimal_places) v = validators.IsValidFloat(self.max_digits, self.decimal_places)
@ -952,10 +952,7 @@ class USStateField(TextField):
raise validators.CriticalValidationError, e.messages raise validators.CriticalValidationError, e.messages
def html2python(data): def html2python(data):
if data: return data.upper() # Should always be stored in upper case
return data.upper() # Should always be stored in upper case
else:
return None
html2python = staticmethod(html2python) html2python = staticmethod(html2python)
class CommaSeparatedIntegerField(TextField): class CommaSeparatedIntegerField(TextField):
@ -972,9 +969,19 @@ class CommaSeparatedIntegerField(TextField):
except validators.ValidationError, e: except validators.ValidationError, e:
raise validators.CriticalValidationError, e.messages raise validators.CriticalValidationError, e.messages
def render(self, data):
if data is None:
data = ''
elif isinstance(data, (list, tuple)):
data = ','.join(data)
return super(CommaSeparatedIntegerField, self).render(data)
class RawIdAdminField(CommaSeparatedIntegerField): class RawIdAdminField(CommaSeparatedIntegerField):
def html2python(data): def html2python(data):
return data.split(',') if data:
return data.split(',')
else:
return []
html2python = staticmethod(html2python) html2python = staticmethod(html2python)
class XMLLargeTextField(LargeTextField): class XMLLargeTextField(LargeTextField):

View File

@ -161,10 +161,10 @@ class HttpResponse(object):
if not mimetype: if not mimetype:
mimetype = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE, settings.DEFAULT_CHARSET) mimetype = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE, settings.DEFAULT_CHARSET)
if hasattr(content, '__iter__'): if hasattr(content, '__iter__'):
self._iterator = content self._container = content
self._is_string = False self._is_string = False
else: else:
self._iterator = [content] self._container = [content]
self._is_string = True self._is_string = True
self.headers = {'Content-Type': mimetype} self.headers = {'Content-Type': mimetype}
self.cookies = SimpleCookie() self.cookies = SimpleCookie()
@ -213,32 +213,37 @@ class HttpResponse(object):
self.cookies[key]['max-age'] = 0 self.cookies[key]['max-age'] = 0
def _get_content(self): def _get_content(self):
content = ''.join(self._iterator) content = ''.join(self._container)
if isinstance(content, unicode): if isinstance(content, unicode):
content = content.encode(self._charset) content = content.encode(self._charset)
return content return content
def _set_content(self, value): def _set_content(self, value):
self._iterator = [value] self._container = [value]
self._is_string = True self._is_string = True
content = property(_get_content, _set_content) content = property(_get_content, _set_content)
def _get_iterator(self): def __iter__(self):
"Output iterator. Converts data into client charset if necessary." self._iterator = self._container.__iter__()
for chunk in self._iterator: return self
if isinstance(chunk, unicode):
chunk = chunk.encode(self._charset)
yield chunk
iterator = property(_get_iterator) def next(self):
chunk = self._iterator.next()
if isinstance(chunk, unicode):
chunk = chunk.encode(self._charset)
return chunk
def close(self):
if hasattr(self._container, 'close'):
self._container.close()
# The remaining methods partially implement the file-like object interface. # The remaining methods partially implement the file-like object interface.
# See http://docs.python.org/lib/bltin-file-objects.html # See http://docs.python.org/lib/bltin-file-objects.html
def write(self, content): def write(self, content):
if not self._is_string: if not self._is_string:
raise Exception, "This %s instance is not writable" % self.__class__ raise Exception, "This %s instance is not writable" % self.__class__
self._iterator.append(content) self._container.append(content)
def flush(self): def flush(self):
pass pass
@ -246,7 +251,7 @@ class HttpResponse(object):
def tell(self): def tell(self):
if not self._is_string: if not self._is_string:
raise Exception, "This %s instance cannot tell its position" % self.__class__ raise Exception, "This %s instance cannot tell its position" % self.__class__
return sum([len(chunk) for chunk in self._iterator]) return sum([len(chunk) for chunk in self._container])
class HttpResponseRedirect(HttpResponse): class HttpResponseRedirect(HttpResponse):
def __init__(self, redirect_to): def __init__(self, redirect_to):

View File

@ -64,8 +64,9 @@ class CommonMiddleware(object):
is_internal = referer and (domain in referer) is_internal = referer and (domain in referer)
path = request.get_full_path() path = request.get_full_path()
if referer and not _is_ignorable_404(path) and (is_internal or '?' not in referer): if referer and not _is_ignorable_404(path) and (is_internal or '?' not in referer):
ua = request.META.get('HTTP_USER_AGENT','<none>')
mail_managers("Broken %slink on %s" % ((is_internal and 'INTERNAL ' or ''), domain), mail_managers("Broken %slink on %s" % ((is_internal and 'INTERNAL ' or ''), domain),
"Referrer: %s\nRequested URL: %s\n" % (referer, request.get_full_path())) "Referrer: %s\nRequested URL: %s\nUser Agent: %s\n" % (referer, request.get_full_path(), ua))
return response return response
# Use ETags, if requested. # Use ETags, if requested.

View File

@ -7,11 +7,12 @@ class XViewMiddleware(object):
""" """
def process_view(self, request, view_func, view_args, view_kwargs): def process_view(self, request, view_func, view_args, view_kwargs):
""" """
If the request method is HEAD and the IP is internal, quickly return If the request method is HEAD and either the IP is internal or the
with an x-header indicating the view function. This is used by the user is a logged-in staff member, quickly return with an x-header
documentation module to lookup the view function for an arbitrary page. indicating the view function. This is used by the documentation module
to lookup the view function for an arbitrary page.
""" """
if request.method == 'HEAD' and request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS: if request.method == 'HEAD' and (request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS or (request.user.is_authenticated() and request.user.is_staff)):
response = http.HttpResponse() response = http.HttpResponse()
response['X-View'] = "%s.%s" % (view_func.__module__, view_func.__name__) response['X-View'] = "%s.%s" % (view_func.__module__, view_func.__name__)
return response return response

View File

@ -15,7 +15,7 @@ register = Library()
def addslashes(value): def addslashes(value):
"Adds slashes - useful for passing strings to JavaScript, for example." "Adds slashes - useful for passing strings to JavaScript, for example."
return value.replace('"', '\\"').replace("'", "\\'") return value.replace('\\', '\\\\').replace('"', '\\"').replace("'", "\\'")
def capfirst(value): def capfirst(value):
"Capitalizes the first character of the value" "Capitalizes the first character of the value"

View File

@ -13,14 +13,18 @@ class CommentNode(Node):
return '' return ''
class CycleNode(Node): class CycleNode(Node):
def __init__(self, cyclevars): def __init__(self, cyclevars, variable_name=None):
self.cyclevars = cyclevars self.cyclevars = cyclevars
self.cyclevars_len = len(cyclevars) self.cyclevars_len = len(cyclevars)
self.counter = -1 self.counter = -1
self.variable_name = variable_name
def render(self, context): def render(self, context):
self.counter += 1 self.counter += 1
return self.cyclevars[self.counter % self.cyclevars_len] value = self.cyclevars[self.counter % self.cyclevars_len]
if self.variable_name:
context[self.variable_name] = value
return value
class DebugNode(Node): class DebugNode(Node):
def render(self, context): def render(self, context):
@ -125,6 +129,8 @@ class IfChangedNode(Node):
self._last_seen = None self._last_seen = None
def render(self, context): def render(self, context):
if context.has_key('forloop') and context['forloop']['first']:
self._last_seen = None
content = self.nodelist.render(context) content = self.nodelist.render(context)
if content != self._last_seen: if content != self._last_seen:
firstloop = (self._last_seen == None) firstloop = (self._last_seen == None)
@ -385,7 +391,7 @@ def cycle(parser, token):
raise TemplateSyntaxError("Second 'cycle' argument must be 'as'") raise TemplateSyntaxError("Second 'cycle' argument must be 'as'")
cyclevars = [v for v in args[1].split(",") if v] # split and kill blanks cyclevars = [v for v in args[1].split(",") if v] # split and kill blanks
name = args[3] name = args[3]
node = CycleNode(cyclevars) node = CycleNode(cyclevars, name)
if not hasattr(parser, '_namedCycleNodes'): if not hasattr(parser, '_namedCycleNodes'):
parser._namedCycleNodes = {} parser._namedCycleNodes = {}

View File

@ -38,10 +38,23 @@ def build_suite(app_module):
except ValueError: except ValueError:
# No doc tests in tests.py # No doc tests in tests.py
pass pass
except ImportError: except ImportError, e:
# No tests.py file for application # Couldn't import tests.py. Was it due to a missing file, or
pass # due to an import error in a tests.py that actually exists?
import os.path
from imp import find_module
try:
mod = find_module(TEST_MODULE, [os.path.dirname(app_module.__file__)])
except ImportError:
# 'tests' module doesn't exist. Move on.
pass
else:
# The module exists, so there must be an import error in the
# test module itself. We don't need the module; close the file
# handle returned by find_module.
mod[0].close()
raise
return suite return suite
def run_tests(module_list, verbosity=1, extra_tests=[]): def run_tests(module_list, verbosity=1, extra_tests=[]):

View File

@ -14,6 +14,9 @@ class MergeDict(object):
pass pass
raise KeyError raise KeyError
def __contains__(self, key):
return self.has_key(key)
def get(self, key, default): def get(self, key, default):
try: try:
return self[key] return self[key]

View File

@ -1,6 +1,6 @@
def curry(*args, **kwargs): def curry(_curried_func, *args, **kwargs):
def _curried(*moreargs, **morekwargs): def _curried(*moreargs, **morekwargs):
return args[0](*(args[1:]+moreargs), **dict(kwargs.items() + morekwargs.items())) return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs))
return _curried return _curried
class Promise: class Promise:

View File

@ -94,7 +94,8 @@ def compress_string(s):
return zbuf.getvalue() return zbuf.getvalue()
ustring_re = re.compile(u"([\u0080-\uffff])") ustring_re = re.compile(u"([\u0080-\uffff])")
def javascript_quote(s):
def javascript_quote(s, quote_double_quotes=False):
def fix(match): def fix(match):
return r"\u%04x" % ord(match.group(1)) return r"\u%04x" % ord(match.group(1))
@ -104,9 +105,12 @@ def javascript_quote(s):
elif type(s) != unicode: elif type(s) != unicode:
raise TypeError, s raise TypeError, s
s = s.replace('\\', '\\\\') s = s.replace('\\', '\\\\')
s = s.replace('\r', '\\r')
s = s.replace('\n', '\\n') s = s.replace('\n', '\\n')
s = s.replace('\t', '\\t') s = s.replace('\t', '\\t')
s = s.replace("'", "\\'") s = s.replace("'", "\\'")
if quote_double_quotes:
s = s.replace('"', '&quot;')
return str(ustring_re.sub(fix, s)) return str(ustring_re.sub(fix, s))
smart_split_re = re.compile('("(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'|[^\\s]+)') smart_split_re = re.compile('("(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'|[^\\s]+)')

View File

@ -82,14 +82,14 @@ Methods
``user_permissions``. ``User`` objects can access their related ``user_permissions``. ``User`` objects can access their related
objects in the same way as any other `Django model`_:: objects in the same way as any other `Django model`_::
myuser.objects.groups = [group_list] myuser.groups = [group_list]
myuser.objects.groups.add(group, group,...) myuser.groups.add(group, group,...)
myuser.objects.groups.remove(group, group,...) myuser.groups.remove(group, group,...)
myuser.objects.groups.clear() myuser.groups.clear()
myuser.objects.permissions = [permission_list] myuser.permissions = [permission_list]
myuser.objects.permissions.add(permission, permission, ...) myuser.permissions.add(permission, permission, ...)
myuser.objects.permissions.remove(permission, permission, ...] myuser.permissions.remove(permission, permission, ...]
myuser.objects.permissions.clear() myuser.permissions.clear()
In addition to those automatic API methods, ``User`` objects have the following In addition to those automatic API methods, ``User`` objects have the following
custom methods: custom methods:
@ -456,6 +456,10 @@ 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) 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.
Here's the same thing, using Python 2.4's decorator syntax:: Here's the same thing, using Python 2.4's decorator syntax::
from django.contrib.auth.decorators import user_passes_test from django.contrib.auth.decorators import user_passes_test
@ -488,6 +492,24 @@ Example in Python 2.4 syntax::
def my_view(request): def my_view(request):
# ... # ...
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::
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.
Limiting access to generic views Limiting access to generic views
-------------------------------- --------------------------------
@ -677,7 +699,7 @@ timestamps.
Messages are used by the Django admin after successful actions. For example, Messages are used by the Django admin after successful actions. For example,
``"The poll Foo was created successfully."`` is a message. ``"The poll Foo was created successfully."`` is a message.
The API is simple:: The API is simple:
* To create a new message, use * To create a new message, use
``user_obj.message_set.create(message='message_text')``. ``user_obj.message_set.create(message='message_text')``.

View File

@ -247,18 +247,23 @@ Django tarball. It's our policy to make sure all tests pass at all times.
The tests cover: The tests cover:
* Models and the database API (``tests/testapp/models``). * Models and the database API (``tests/modeltests/``).
* The cache system (``tests/otherthests/cache.py``). * The cache system (``tests/regressiontests/cache.py``).
* The ``django.utils.dateformat`` module (``tests/othertests/dateformat.py``). * The ``django.utils.dateformat`` module (``tests/regressiontests/dateformat/``).
* Database typecasts (``tests/othertests/db_typecasts.py``). * Database typecasts (``tests/regressiontests/db_typecasts/``).
* The template system (``tests/othertests/templates.py`` and * The template system (``tests/regressiontests/templates/`` and
``tests/othertests/defaultfilters.py``). ``tests/regressiontests/defaultfilters/``).
* ``QueryDict`` objects (``tests/othertests/httpwrappers.py``). * ``QueryDict`` objects (``tests/regressiontests/httpwrappers/``).
* Markup template tags (``tests/othertests/markup.py``). * Markup template tags (``tests/regressiontests/markup/``).
* The ``django.utils.timesince`` module (``tests/othertests/timesince.py``).
We appreciate any and all contributions to the test suite! 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
how to write new tests.
.. _Testing Django Applications: http://www.djangoproject.com/documentation/testing/
Running the unit tests Running the unit tests
---------------------- ----------------------
@ -268,10 +273,14 @@ To run the tests, ``cd`` to the ``tests/`` directory and type::
Yes, the unit tests need a settings module, but only for database connection Yes, the unit tests need a settings module, but only for database connection
info -- the ``DATABASE_ENGINE``, ``DATABASE_USER`` and ``DATABASE_PASSWORD``. info -- the ``DATABASE_ENGINE``, ``DATABASE_USER`` and ``DATABASE_PASSWORD``.
You will also need a ``ROOT_URLCONF`` setting (it's 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.
The unit tests will not touch your database; they create a new database, called The unit tests will not touch your existing databases; they create a new
``django_test_db``, which is deleted when the tests are finished. This means database, called ``django_test_db``, which is deleted when the tests are
your user account needs permission to execute ``CREATE DATABASE``. finished. This means your user account needs permission to execute ``CREATE
DATABASE``.
Requesting features Requesting features
=================== ===================

View File

@ -1511,7 +1511,7 @@ Many-to-many relationships
-------------------------- --------------------------
Both ends of a many-to-many relationship get automatic API access to the other Both ends of a many-to-many relationship get automatic API access to the other
end. The API works just as a "backward" one-to-many relationship. See _Backward end. The API works just as a "backward" one-to-many relationship. See Backward_
above. above.
The only difference is in the attribute naming: The model that defines the The only difference is in the attribute naming: The model that defines the

View File

@ -295,6 +295,8 @@ give you the option of creating a superuser immediately.
test test
---- ----
**New in Django development version**
Discover and run tests for all installed models. See `Testing Django applications`_ for more information. Discover and run tests for all installed models. See `Testing Django applications`_ for more information.
.. _testing django applications: ../testing/ .. _testing django applications: ../testing/
@ -348,6 +350,8 @@ options.
--noinput --noinput
--------- ---------
**New in Django development version**
Inform django-admin that the user should NOT be prompted for any input. Useful if Inform django-admin that the user should NOT be prompted for any input. Useful if
the django-admin script will be executed as an unattended, automated script. the django-admin script will be executed as an unattended, automated script.
@ -369,6 +373,8 @@ Example output::
--verbosity --verbosity
----------- -----------
**New in Django development version**
Example usage:: Example usage::
django-admin.py syncdb --verbosity=2 django-admin.py syncdb --verbosity=2

View File

@ -270,7 +270,7 @@ In your Web root directory, add this to a file named ``.htaccess`` ::
AddHandler fastcgi-script .fcgi AddHandler fastcgi-script .fcgi
RewriteEngine On RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L] RewriteRule ^(.*)$ mysite.fcgi/$1 [QSA,L]
Then, create a small script that tells Apache how to spawn your FastCGI Then, create a small script that tells Apache how to spawn your FastCGI
program. Create a file ``mysite.fcgi`` and place it in your Web directory, and program. Create a file ``mysite.fcgi`` and place it in your Web directory, and
@ -289,7 +289,7 @@ be sure to make it executable ::
os.environ['DJANGO_SETTINGS_MODULE'] = "myproject.settings" os.environ['DJANGO_SETTINGS_MODULE'] = "myproject.settings"
from django.core.servers.fastcgi import runfastcgi from django.core.servers.fastcgi import runfastcgi
runfastcgi(["method=threaded", "daemonize=false"]) runfastcgi(method="threaded", daemonize="false")
Restarting the spawned server Restarting the spawned server
----------------------------- -----------------------------

View File

@ -136,7 +136,7 @@ template::
{% endblock %} {% endblock %}
Before we get back to the problems with these naive set of views, let's go over Before we get back to the problems with these naive set of views, let's go over
some salient points of the above template:: some salient points of the above template:
* Field "widgets" are handled for you: ``{{ form.field }}`` automatically * Field "widgets" are handled for you: ``{{ form.field }}`` automatically
creates the "right" type of widget for the form, as you can see with the creates the "right" type of widget for the form, as you can see with the
@ -148,8 +148,8 @@ some salient points of the above template::
If you must use tables, use tables. If you're a semantic purist, you can If you must use tables, use tables. If you're a semantic purist, you can
probably find better HTML than in the above template. probably find better HTML than in the above template.
* To avoid name conflicts, the ``id``s of form elements take the form * To avoid name conflicts, the ``id`` values of form elements take the
"id_*fieldname*". form "id_*fieldname*".
By creating a creation form we've solved problem number 3 above, but we still By creating a creation form we've solved problem number 3 above, but we still
don't have any validation. Let's revise the validation issue by writing a new don't have any validation. Let's revise the validation issue by writing a new
@ -321,7 +321,7 @@ about editing an existing one? It's shockingly similar to creating a new one::
else: else:
errors = {} errors = {}
# This makes sure the form accurate represents the fields of the place. # This makes sure the form accurate represents the fields of the place.
new_data = place.__dict__ new_data = manipulator.flatten_data()
form = forms.FormWrapper(manipulator, new_data, errors) form = forms.FormWrapper(manipulator, new_data, errors)
return render_to_response('places/edit_form.html', {'form': form, 'place': place}) return render_to_response('places/edit_form.html', {'form': form, 'place': place})
@ -336,10 +336,10 @@ The only real differences are:
* ``ChangeManipulator.original_object`` stores the instance of the * ``ChangeManipulator.original_object`` stores the instance of the
object being edited. object being edited.
* We set ``new_data`` to the original object's ``__dict__``. This makes * We set ``new_data`` based upon ``flatten_data()`` from the manipulator.
sure the form fields contain the current values of the object. ``flatten_data()`` takes the data from the original object under
``FormWrapper`` does not modify ``new_data`` in any way, and templates manipulation, and converts it into a data dictionary that can be used
cannot, so this is perfectly safe. to populate form elements with the existing values for the object.
* The above example uses a different template, so create and edit can be * The above example uses a different template, so create and edit can be
"skinned" differently if needed, but the form chunk itself is completely "skinned" differently if needed, but the form chunk itself is completely
@ -481,6 +481,33 @@ the data being validated.
Also, because consistency in user interfaces is important, we strongly urge you Also, because consistency in user interfaces is important, we strongly urge you
to put punctuation at the end of your validation messages. to put punctuation at the end of your validation messages.
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
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
run against the field.
This feature is particularly important for models using
``models.BooleanField`` or custom manipulators using things like
``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::
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
--------------------- ---------------------

View File

@ -543,7 +543,9 @@ The default value for the field.
``editable`` ``editable``
~~~~~~~~~~~~ ~~~~~~~~~~~~
If ``False``, the field will not be editable in the admin. Default is ``True``. If ``False``, the field will not be editable in the admin or via form
processing using the object's ``AddManipulator`` or ``ChangeManipulator``
classes. Default is ``True``.
``help_text`` ``help_text``
~~~~~~~~~~~~~ ~~~~~~~~~~~~~

View File

@ -96,6 +96,21 @@ Django "ships" with a few included serializers:
.. _json: http://json.org/ .. _json: http://json.org/
.. _simplejson: http://undefined.org/python/#simplejson .. _simplejson: http://undefined.org/python/#simplejson
Notes For Specific Serialization Formats
----------------------------------------
json
~~~~
If you are 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.
For example::
json_serializer = serializers.get_serializer("json")
json_serializer.serialize(queryset, ensure_ascii=False, stream=response)
Writing custom serializers Writing custom serializers
`````````````````````````` ``````````````````````````

View File

@ -596,6 +596,12 @@ Whether to prepend the "www." subdomain to URLs that don't have it. This is
only used if ``CommonMiddleware`` is installed (see the `middleware docs`_). only used if ``CommonMiddleware`` is installed (see the `middleware docs`_).
See also ``APPEND_SLASH``. See also ``APPEND_SLASH``.
PROFANITIES_LIST
----------------
A list of profanities that will trigger a validation error when the
``hasNoProfanities`` validator is called.
ROOT_URLCONF ROOT_URLCONF
------------ ------------

View File

@ -763,17 +763,17 @@ will use the function's name as the tag name.
Shortcut for simple tags Shortcut for simple tags
~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~
Many template tags take a single argument -- a string or a template variable Many template tags take a number of arguments -- strings or a template variables
reference -- and return a string after doing some processing based solely on -- and return a string after doing some processing based solely on
the input argument and some external information. For example, the the input argument and some external information. For example, the
``current_time`` tag we wrote above is of this variety: we give it a format ``current_time`` tag we wrote above is of this variety: we give it a format
string, it returns the time as a string. string, it returns the time as a string.
To ease the creation of the types of tags, Django provides a helper function, To ease the creation of the types of tags, Django provides a helper function,
``simple_tag``. This function, which is a method of ``simple_tag``. This function, which is a method of
``django.template.Library``, takes a function that accepts one argument, wraps ``django.template.Library``, takes a function that accepts any number of
it in a ``render`` function and the other necessary bits mentioned above and arguments, wraps it in a ``render`` function and the other necessary bits
registers it with the template system. mentioned above and registers it with the template system.
Our earlier ``current_time`` function could thus be written like this:: Our earlier ``current_time`` function could thus be written like this::
@ -789,11 +789,16 @@ In Python 2.4, the decorator syntax also works::
... ...
A couple of things to note about the ``simple_tag`` helper function: A couple of things to note about the ``simple_tag`` helper function:
* Only the (single) argument is passed into our function.
* Checking for the required number of arguments, etc, has already been * Checking for the required number of arguments, etc, has already been
done by the time our function is called, so we don't need to do that. done by the time our function is called, so we don't need to do that.
* The quotes around the argument (if any) have already been stripped away, * The quotes around the argument (if any) have already been stripped away,
so we just receive a plain string. so we just receive a plain string.
* If the argument was a template variable, our function is passed the
current value of the variable, not the variable itself.
When your template tag does not need access to the current context, writing a
function to work with the input values and using the ``simple_tag`` helper is
the easiest way to create a new tag.
Inclusion tags Inclusion tags
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~

View File

@ -92,7 +92,8 @@ Writing unittests
Like doctests, Django's unit tests use a standard library module: unittest_. Like doctests, Django's unit tests use a standard library module: unittest_.
As with doctests, Django's test runner looks for any unit test cases defined As with doctests, Django's test runner looks for any unit test cases defined
in ``models.py``, or in a ``tests.py`` file in your application directory. in ``models.py``, or in a ``tests.py`` file stored in the application
directory.
An equivalent unittest test case for the above example would look like:: An equivalent unittest test case for the above example would look like::
@ -110,8 +111,9 @@ An equivalent unittest test case for the above example would look like::
self.assertEquals(self.cat.speak(), 'The cat says "meow"') self.assertEquals(self.cat.speak(), 'The cat says "meow"')
When you `run your tests`_, the test utility will find all the test cases When you `run your tests`_, the test utility will find all the test cases
(that is, subclasses of ``unittest.TestCase``) in ``tests.py``, automatically (that is, subclasses of ``unittest.TestCase``) in ``models.py`` and
build a test suite out of those test cases, and run that suite. ``tests.py``, automatically build a test suite out of those test cases,
and run that suite.
For more details about ``unittest``, see the `standard library unittest For more details about ``unittest``, see the `standard library unittest
documentation`_. documentation`_.
@ -197,10 +199,10 @@ used as test conditions.
.. _Selenium: http://www.openqa.org/selenium/ .. _Selenium: http://www.openqa.org/selenium/
The Test Client is stateful; if a cookie is returned as part of a response, The Test Client is stateful; if a cookie is returned as part of a response,
that cookie is provided as part of the next request. Expiry policies for these that cookie is provided as part of the next request issued to that Client
cookies are not followed; if you want a cookie to expire, either delete it instance. Expiry policies for these cookies are not followed; if you want
manually from ``client.cookies``, or create a new Client instance (which will a cookie to expire, either delete it manually from ``client.cookies``, or
effectively delete all cookies). create a new Client instance (which will effectively delete all cookies).
Making requests Making requests
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
@ -210,7 +212,6 @@ no arguments at time of construction. Once constructed, the following methods
can be invoked on the ``Client`` instance. can be invoked on the ``Client`` instance.
``get(path, data={})`` ``get(path, data={})``
Make a GET request on the provided ``path``. The key-value pairs in the Make a GET request on the provided ``path``. The key-value pairs in the
data dictionary will be used to create a GET data payload. For example:: data dictionary will be used to create a GET data payload. For example::
@ -222,7 +223,6 @@ can be invoked on the ``Client`` instance.
http://yoursite.com/customers/details/?name='fred'&age=7 http://yoursite.com/customers/details/?name='fred'&age=7
``post(path, data={})`` ``post(path, data={})``
Make a POST request on the provided ``path``. The key-value pairs in the Make a POST request on the provided ``path``. The key-value pairs in the
data dictionary will be used to create the POST data payload. This payload data dictionary will be used to create the POST data payload. This payload
will be transmitted with the mimetype ``multipart/form-data``. will be transmitted with the mimetype ``multipart/form-data``.
@ -243,7 +243,6 @@ can be invoked on the ``Client`` instance.
need to manually close the file after it has been provided to the POST. need to manually close the file after it has been provided to the POST.
``login(path, username, password)`` ``login(path, username, password)``
In a production site, it is likely that some views will be protected with In a production site, it is likely that some views will be protected with
the @login_required URL provided by ``django.contrib.auth``. Interacting the @login_required URL provided by ``django.contrib.auth``. Interacting
with a URL that has been login protected is a slightly complex operation, with a URL that has been login protected is a slightly complex operation,
@ -307,9 +306,12 @@ The following is a simple unit test using the Test Client::
# Every test needs a client # Every test needs a client
self.client = Client() self.client = Client()
def test_details(self): def test_details(self):
# Issue a GET request
response = self.client.get('/customer/details/') response = self.client.get('/customer/details/')
# Check that the respose is 200 OK
self.failUnlessEqual(response.status_code, 200) self.failUnlessEqual(response.status_code, 200)
# Check that the rendered context contains 5 customers
self.failUnlessEqual(len(response.context['customers']), 5) self.failUnlessEqual(len(response.context['customers']), 5)
Fixtures Fixtures

View File

@ -68,15 +68,34 @@ class SelfClashForeign(models.Model):
foreign_1 = models.ForeignKey("SelfClashForeign", related_name='id') foreign_1 = models.ForeignKey("SelfClashForeign", related_name='id')
foreign_2 = models.ForeignKey("SelfClashForeign", related_name='src_safe') foreign_2 = models.ForeignKey("SelfClashForeign", related_name='src_safe')
class ValidM2M(models.Model):
src_safe = models.CharField(maxlength=10)
validm2m = models.CharField(maxlength=10)
# M2M fields are symmetrical by default. Symmetrical M2M fields
# on self don't require a related accessor, so many potential
# clashes are avoided.
validm2m_set = models.ManyToManyField("ValidM2M")
m2m_1 = models.ManyToManyField("ValidM2M", related_name='id')
m2m_2 = models.ManyToManyField("ValidM2M", related_name='src_safe')
m2m_3 = models.ManyToManyField('self')
m2m_4 = models.ManyToManyField('self')
class SelfClashM2M(models.Model): class SelfClashM2M(models.Model):
src_safe = models.CharField(maxlength=10) src_safe = models.CharField(maxlength=10)
selfclashm2m = models.CharField(maxlength=10) selfclashm2m = models.CharField(maxlength=10)
selfclashm2m_set = models.ManyToManyField("SelfClashM2M") # Non-symmetrical M2M fields _do_ have related accessors, so
m2m_1 = models.ManyToManyField("SelfClashM2M", related_name='id') # there is potential for clashes.
m2m_2 = models.ManyToManyField("SelfClashM2M", related_name='src_safe') selfclashm2m_set = models.ManyToManyField("SelfClashM2M", symmetrical=False)
m2m_1 = models.ManyToManyField("SelfClashM2M", related_name='id', symmetrical=False)
m2m_2 = models.ManyToManyField("SelfClashM2M", related_name='src_safe', symmetrical=False)
m2m_3 = models.ManyToManyField('self', symmetrical=False)
m2m_4 = models.ManyToManyField('self', symmetrical=False)
model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "maxlength" attribute. model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "maxlength" attribute.
invalid_models.fielderrors: "floatfield": FloatFields require a "decimal_places" attribute. invalid_models.fielderrors: "floatfield": FloatFields require a "decimal_places" attribute.
@ -147,9 +166,17 @@ invalid_models.selfclashforeign: Accessor for field 'foreign_2' clashes with fie
invalid_models.selfclashforeign: Reverse query name for field 'foreign_2' clashes with field 'SelfClashForeign.src_safe'. Add a related_name argument to the definition for 'foreign_2'. invalid_models.selfclashforeign: Reverse query name for field 'foreign_2' clashes with field 'SelfClashForeign.src_safe'. Add a related_name argument to the definition for 'foreign_2'.
invalid_models.selfclashm2m: Accessor for m2m field 'selfclashm2m_set' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'selfclashm2m_set'. invalid_models.selfclashm2m: Accessor for m2m field 'selfclashm2m_set' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'selfclashm2m_set'.
invalid_models.selfclashm2m: Reverse query name for m2m field 'selfclashm2m_set' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'selfclashm2m_set'. invalid_models.selfclashm2m: Reverse query name for m2m field 'selfclashm2m_set' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'selfclashm2m_set'.
invalid_models.selfclashm2m: Accessor for m2m field 'selfclashm2m_set' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'selfclashm2m_set'.
invalid_models.selfclashm2m: Accessor for m2m field 'm2m_1' clashes with field 'SelfClashM2M.id'. Add a related_name argument to the definition for 'm2m_1'. invalid_models.selfclashm2m: Accessor for m2m field 'm2m_1' clashes with field 'SelfClashM2M.id'. Add a related_name argument to the definition for 'm2m_1'.
invalid_models.selfclashm2m: Accessor for m2m field 'm2m_2' clashes with field 'SelfClashM2M.src_safe'. Add a related_name argument to the definition for 'm2m_2'. invalid_models.selfclashm2m: Accessor for m2m field 'm2m_2' clashes with field 'SelfClashM2M.src_safe'. Add a related_name argument to the definition for 'm2m_2'.
invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_1' clashes with field 'SelfClashM2M.id'. Add a related_name argument to the definition for 'm2m_1'. invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_1' clashes with field 'SelfClashM2M.id'. Add a related_name argument to the definition for 'm2m_1'.
invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_2' clashes with field 'SelfClashM2M.src_safe'. Add a related_name argument to the definition for 'm2m_2'. invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_2' clashes with field 'SelfClashM2M.src_safe'. Add a related_name argument to the definition for 'm2m_2'.
invalid_models.selfclashm2m: Accessor for m2m field 'm2m_3' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_3'.
invalid_models.selfclashm2m: Accessor for m2m field 'm2m_3' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_3'.
invalid_models.selfclashm2m: Accessor for m2m field 'm2m_3' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_3'.
invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'.
invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'.
invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'.
invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_3' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_3'.
invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_4' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_4'.
""" """

View File

@ -15,6 +15,9 @@ r"""
>>> addslashes('"double quotes" and \'single quotes\'') >>> addslashes('"double quotes" and \'single quotes\'')
'\\"double quotes\\" and \\\'single quotes\\\'' '\\"double quotes\\" and \\\'single quotes\\\''
>>> addslashes(r'\ : backslashes, too')
'\\\\ : backslashes, too'
>>> capfirst('hello world') >>> capfirst('hello world')
'Hello world' 'Hello world'

View File

@ -187,6 +187,7 @@ class Templates(unittest.TestCase):
'cycle05': ('{% cycle %}', {}, template.TemplateSyntaxError), 'cycle05': ('{% cycle %}', {}, template.TemplateSyntaxError),
'cycle06': ('{% cycle a %}', {}, template.TemplateSyntaxError), 'cycle06': ('{% cycle a %}', {}, template.TemplateSyntaxError),
'cycle07': ('{% cycle a,b,c as foo %}{% cycle bar %}', {}, template.TemplateSyntaxError), 'cycle07': ('{% cycle a,b,c as foo %}{% cycle bar %}', {}, template.TemplateSyntaxError),
'cycle08': ('{% cycle a,b,c as foo %}{% cycle foo %}{{ foo }}{{ foo }}{% cycle foo %}{{ foo }}', {}, 'abbbcc'),
### EXCEPTIONS ############################################################ ### EXCEPTIONS ############################################################
@ -304,6 +305,10 @@ class Templates(unittest.TestCase):
'ifchanged01': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,2,3) }, '123'), 'ifchanged01': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,2,3) }, '123'),
'ifchanged02': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,3) }, '13'), 'ifchanged02': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,3) }, '13'),
'ifchanged03': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,1) }, '1'), 'ifchanged03': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,1) }, '1'),
'ifchanged04': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 2, 3), 'numx': (2, 2, 2)}, '122232'),
'ifchanged05': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (1, 2, 3)}, '1123123123'),
'ifchanged06': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (2, 2, 2)}, '1222'),
'ifchanged07': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% for y in numy %}{% ifchanged %}{{ y }}{% endifchanged %}{% endfor %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (2, 2, 2), 'numy': (3, 3, 3)}, '1233323332333'),
### IFEQUAL TAG ########################################################### ### IFEQUAL TAG ###########################################################
'ifequal01': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 2}, ""), 'ifequal01': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 2}, ""),