1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

[soc2009/multidb] Merged up to trunk r11810. There are many conflicts in this merge, these will be resolved in a subsequent commit.

git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/multidb@11812 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Alex Gaynor 2009-12-12 02:10:28 +00:00
parent 353e079792
commit c88113683d
34 changed files with 1239 additions and 233 deletions

View File

@ -131,9 +131,12 @@ DATABASE_HOST = '' # Set to empty string for localhost. Not used wit
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
DATABASE_OPTIONS = {} # Set to empty dictionary for default.
<<<<<<< HEAD:django/conf/global_settings.py
DATABASES = {
}
=======
>>>>>>> master:django/conf/global_settings.py
# The email backend to use. For possible shortcuts see django.core.mail.
# The default is to use the SMTP backend.
# Third-party backends can be specified by providing a Python path

View File

@ -5,7 +5,11 @@ msgid ""
msgstr ""
"Project-Id-Version: Django\n"
"Report-Msgid-Bugs-To: \n"
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
"POT-Creation-Date: 2009-10-25 20:56+0100\n"
=======
"POT-Creation-Date: 2009-12-11 10:11+0100\n"
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
"PO-Revision-Date: 2008-02-25 15:53+0100\n"
"Last-Translator: Jarek Zgoda <jarek.zgoda@gmail.com>\n"
"MIME-Version: 1.0\n"
@ -223,7 +227,11 @@ msgstr "chiński tradycyjny"
msgid "Successfully deleted %(count)d %(items)s."
msgstr "Usunięto %(count)d %(items)s."
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/actions.py:67 contrib/admin/options.py:1027
=======
#: contrib/admin/actions.py:67 contrib/admin/options.py:1034
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
msgid "Are you sure?"
msgstr "Jesteś pewien?"
@ -310,87 +318,132 @@ msgstr "log"
msgid "log entries"
msgstr "logi"
#: contrib/admin/options.py:133 contrib/admin/options.py:147
#: contrib/admin/options.py:135 contrib/admin/options.py:149
msgid "None"
msgstr "brak"
#: contrib/admin/options.py:519
#: contrib/admin/options.py:522
#, python-format
msgid "Changed %s."
msgstr "Zmieniono %s"
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/options.py:519 contrib/admin/options.py:529
=======
#: contrib/admin/options.py:522 contrib/admin/options.py:532
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/comments/templates/comments/preview.html:16 forms/models.py:384
#: forms/models.py:596
msgid "and"
msgstr "i"
#: contrib/admin/options.py:524
#: contrib/admin/options.py:527
#, python-format
msgid "Added %(name)s \"%(object)s\"."
msgstr "Dodano %(name)s \"%(object)s\"."
#: contrib/admin/options.py:528
#: contrib/admin/options.py:531
#, python-format
msgid "Changed %(list)s for %(name)s \"%(object)s\"."
msgstr "Zmieniono %(list)s w %(name)s \"%(object)s\"."
#: contrib/admin/options.py:533
#: contrib/admin/options.py:536
#, python-format
msgid "Deleted %(name)s \"%(object)s\"."
msgstr "Usunięto %(name)s \"%(object)s\"."
#: contrib/admin/options.py:537
#: contrib/admin/options.py:540
msgid "No fields changed."
msgstr "Żadne pole nie zmienione."
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/options.py:599 contrib/auth/admin.py:67
=======
#: contrib/admin/options.py:602 contrib/auth/admin.py:68
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#, python-format
msgid "The %(name)s \"%(obj)s\" was added successfully."
msgstr "%(name)s \"%(obj)s\" dodany pomyślnie."
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/options.py:603 contrib/admin/options.py:636
#: contrib/auth/admin.py:75
msgid "You may edit it again below."
msgstr "Możesz ponownie edytować wpis poniżej."
#: contrib/admin/options.py:613 contrib/admin/options.py:646
=======
#: contrib/admin/options.py:606 contrib/admin/options.py:639
#: contrib/auth/admin.py:77
msgid "You may edit it again below."
msgstr "Możesz ponownie edytować wpis poniżej."
#: contrib/admin/options.py:616 contrib/admin/options.py:649
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#, python-format
msgid "You may add another %s below."
msgstr "Możesz dodać nowy wpis %s poniżej."
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/options.py:634
=======
#: contrib/admin/options.py:637
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#, python-format
msgid "The %(name)s \"%(obj)s\" was changed successfully."
msgstr "%(name)s \"%(obj)s\" zostało pomyślnie zmienione."
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/options.py:642
=======
#: contrib/admin/options.py:645
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#, python-format
msgid ""
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
msgstr ""
"%(name)s \"%(obj)s\" dodane pomyślnie. Możesz edytować ponownie wpis poniżej."
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/options.py:773
=======
#: contrib/admin/options.py:778
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#, python-format
msgid "Add %s"
msgstr "Dodaj %s"
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/options.py:804 contrib/admin/options.py:1005
=======
#: contrib/admin/options.py:810 contrib/admin/options.py:1012
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#, python-format
msgid "%(name)s object with primary key %(key)r does not exist."
msgstr "Obiekt %(name)s o kluczu głównym %(key)r nie istnieje."
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/options.py:861
=======
#: contrib/admin/options.py:867
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#, python-format
msgid "Change %s"
msgstr "Zmień %s"
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/options.py:905
msgid "Database error"
msgstr "Błąd bazy danych"
#: contrib/admin/options.py:941
=======
#: contrib/admin/options.py:911
msgid "Database error"
msgstr "Błąd bazy danych"
#: contrib/admin/options.py:947
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#, python-format
msgid "%(count)s %(name)s was changed successfully."
msgid_plural "%(count)s %(name)s were changed successfully."
@ -398,17 +451,29 @@ msgstr[0] "%(count)s %(name)s został pomyślnie zmieniony."
msgstr[1] "%(count)s %(name)s zostały pomyślnie zmienione."
msgstr[2] "%(count)s %(name)s zostało pomyślnie zmienionych."
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/options.py:1020
=======
#: contrib/admin/options.py:1027
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#, python-format
msgid "The %(name)s \"%(obj)s\" was deleted successfully."
msgstr "%(name)s \"%(obj)s\" usunięty pomyślnie."
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/options.py:1057
=======
#: contrib/admin/options.py:1064
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#, python-format
msgid "Change history: %s"
msgstr "Historia zmian: %s"
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/sites.py:21 contrib/admin/views/decorators.py:14
=======
#: contrib/admin/sites.py:22 contrib/admin/views/decorators.py:14
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/auth/forms.py:80
msgid ""
"Please enter a correct username and password. Note that both fields are case-"
@ -417,11 +482,19 @@ msgstr ""
"Proszę wpisać poprawną nazwę użytkownika i hasło. Uwaga: wielkość liter ma "
"znaczenie."
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/sites.py:288 contrib/admin/views/decorators.py:40
msgid "Please log in again, because your session has expired."
msgstr "Twoja sesja wygasła, zaloguj się ponownie."
#: contrib/admin/sites.py:295 contrib/admin/views/decorators.py:47
=======
#: contrib/admin/sites.py:292 contrib/admin/views/decorators.py:40
msgid "Please log in again, because your session has expired."
msgstr "Twoja sesja wygasła, zaloguj się ponownie."
#: contrib/admin/sites.py:299 contrib/admin/views/decorators.py:47
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
msgid ""
"Looks like your browser isn't configured to accept cookies. Please enable "
"cookies, reload this page, and try again."
@ -429,27 +502,47 @@ msgstr ""
"Twoja przeglądarka nie chce akceptować ciasteczek. Zmień jej ustawienia i "
"spróbuj ponownie."
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/sites.py:311 contrib/admin/sites.py:317
=======
#: contrib/admin/sites.py:315 contrib/admin/sites.py:321
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/views/decorators.py:66
msgid "Usernames cannot contain the '@' character."
msgstr "Nazwy użytkowników nie mogą zawierać znaku '@'."
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/sites.py:314 contrib/admin/views/decorators.py:62
=======
#: contrib/admin/sites.py:318 contrib/admin/views/decorators.py:62
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#, python-format
msgid "Your e-mail address is not your username. Try '%s' instead."
msgstr "Podany adres e-mail nie jest Twoją nazwą użytkownika. Spróbuj '%s'."
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/sites.py:370
msgid "Site administration"
msgstr "Administracja stroną"
#: contrib/admin/sites.py:384 contrib/admin/templates/admin/login.html:26
=======
#: contrib/admin/sites.py:374
msgid "Site administration"
msgstr "Administracja stroną"
#: contrib/admin/sites.py:388 contrib/admin/templates/admin/login.html:26
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/templates/registration/password_reset_complete.html:14
#: contrib/admin/views/decorators.py:20
msgid "Log in"
msgstr "Zaloguj się"
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/sites.py:429
=======
#: contrib/admin/sites.py:433
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#, python-format
msgid "%s administration"
msgstr "%s - administracja"
@ -670,8 +763,13 @@ msgid ""
"Are you sure you want to delete the selected %(object_name)s objects? All of "
"the following objects and their related items will be deleted:"
msgstr ""
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
"Czy chcesz skasować wybrane %(object_name)s? Następujące obiekty i zależne od "
"nich zostaną skasowane:"
=======
"Czy chcesz skasować wybrane %(object_name)s? Następujące obiekty i zależne "
"od nich zostaną skasowane:"
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/admin/templates/admin/filter.html:2
#, python-format
@ -977,7 +1075,7 @@ msgstr "Adres e-mail:"
msgid "Reset my password"
msgstr "Zresetuj moje hasło"
#: contrib/admin/templatetags/admin_list.py:299
#: contrib/admin/templatetags/admin_list.py:304
msgid "All dates"
msgstr "Wszystkie daty"
@ -991,11 +1089,11 @@ msgstr "Zaznacz %s"
msgid "Select %s to change"
msgstr "Zaznacz %s aby zmienić"
#: contrib/admin/views/template.py:37 contrib/sites/models.py:38
#: contrib/admin/views/template.py:38 contrib/sites/models.py:38
msgid "site"
msgstr "strona"
#: contrib/admin/views/template.py:39
#: contrib/admin/views/template.py:40
msgid "template"
msgstr "szablon"
@ -1209,37 +1307,37 @@ msgstr "Edytuj ten obiekt (nowe okno)"
msgid "As above, but opens the admin page in a new window."
msgstr "Jak wyżej, tyle że otwiera nowe okno."
#: contrib/auth/admin.py:21
#: contrib/auth/admin.py:22
msgid "Personal info"
msgstr "Dane osobowe"
#: contrib/auth/admin.py:22
#: contrib/auth/admin.py:23
msgid "Permissions"
msgstr "Uprawnienia"
#: contrib/auth/admin.py:23
#: contrib/auth/admin.py:24
msgid "Important dates"
msgstr "Ważne daty"
#: contrib/auth/admin.py:24
#: contrib/auth/admin.py:25
msgid "Groups"
msgstr "Grupy"
#: contrib/auth/admin.py:80
#: contrib/auth/admin.py:82
msgid "Add user"
msgstr "Dodaj użytkownika"
#: contrib/auth/admin.py:106
#: contrib/auth/admin.py:108
msgid "Password changed successfully."
msgstr "Hasło zostało zmienione pomyślnie."
#: contrib/auth/admin.py:112
#: contrib/auth/admin.py:114
#, python-format
msgid "Change password: %s"
msgstr "Zmień hasło: %s"
#: contrib/auth/forms.py:15 contrib/auth/forms.py:48
#: contrib/auth/models.py:128
#: contrib/auth/models.py:129
msgid ""
"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
"digits and underscores)."
@ -1329,31 +1427,31 @@ msgstr "uprawnienia"
msgid "group"
msgstr "grupa"
#: contrib/auth/models.py:91 contrib/auth/models.py:138
#: contrib/auth/models.py:91 contrib/auth/models.py:139
msgid "groups"
msgstr "grupy"
#: contrib/auth/models.py:128
#: contrib/auth/models.py:129
msgid "username"
msgstr "użytkownik"
#: contrib/auth/models.py:129
#: contrib/auth/models.py:130
msgid "first name"
msgstr "imię"
#: contrib/auth/models.py:130
#: contrib/auth/models.py:131
msgid "last name"
msgstr "nazwisko"
#: contrib/auth/models.py:131
#: contrib/auth/models.py:132
msgid "e-mail address"
msgstr "adres e-mail"
#: contrib/auth/models.py:132
#: contrib/auth/models.py:133
msgid "password"
msgstr "hasło"
#: contrib/auth/models.py:132
#: contrib/auth/models.py:133
msgid ""
"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
"password form</a>."
@ -1361,19 +1459,19 @@ msgstr ""
"Użyj '[algo]$[salt]$[hexdigest]' lub <a href=\"password/\">formularza zmiany "
"hasła</a>."
#: contrib/auth/models.py:133
#: contrib/auth/models.py:134
msgid "staff status"
msgstr "w zespole"
#: contrib/auth/models.py:133
#: contrib/auth/models.py:134
msgid "Designates whether the user can log into this admin site."
msgstr "Oznacza czy użytkownik może zalogować się do panelu admina."
#: contrib/auth/models.py:134
#: contrib/auth/models.py:135
msgid "active"
msgstr "aktywny"
#: contrib/auth/models.py:134
#: contrib/auth/models.py:135
msgid ""
"Designates whether this user should be treated as active. Unselect this "
"instead of deleting accounts."
@ -1381,11 +1479,11 @@ msgstr ""
"Oznacza czy użytkownika należy uważać za aktywnego. Odznacz to, zamiast "
"usuwać konta."
#: contrib/auth/models.py:135
#: contrib/auth/models.py:136
msgid "superuser status"
msgstr "status administratora"
#: contrib/auth/models.py:135
#: contrib/auth/models.py:136
msgid ""
"Designates that this user has all permissions without explicitly assigning "
"them."
@ -1393,15 +1491,15 @@ msgstr ""
"Oznacza, że ten użytkownik ma wszystkie uprawnienia bez jawnego "
"przypisywania ich."
#: contrib/auth/models.py:136
#: contrib/auth/models.py:137
msgid "last login"
msgstr "ostatnio zalogowany"
#: contrib/auth/models.py:137
#: contrib/auth/models.py:138
msgid "date joined"
msgstr "data przyłączenia"
#: contrib/auth/models.py:139
#: contrib/auth/models.py:140
msgid ""
"In addition to the permissions manually assigned, this user will also get "
"all permissions granted to each group he/she is in."
@ -1409,24 +1507,28 @@ msgstr ""
"Oprócz uprawnień przypisanych bezpośrednio użytkownikowi otrzyma on "
"uprawnienia grup, do których należy."
#: contrib/auth/models.py:140
#: contrib/auth/models.py:141
msgid "user permissions"
msgstr "uprawnienia użytkownika"
#: contrib/auth/models.py:144 contrib/comments/models.py:50
#: contrib/auth/models.py:145 contrib/comments/models.py:50
#: contrib/comments/models.py:168
msgid "user"
msgstr "użytkownik"
#: contrib/auth/models.py:145
#: contrib/auth/models.py:146
msgid "users"
msgstr "użytkownicy"
#: contrib/auth/models.py:301
#: contrib/auth/models.py:334
msgid "message"
msgstr "wiadomość"
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: contrib/auth/views.py:58
=======
#: contrib/auth/views.py:60
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
msgid "Logged out"
msgstr "Wylogowany"
@ -1774,7 +1876,7 @@ msgstr "strona statyczna"
msgid "flat pages"
msgstr "strony statyczne"
#: contrib/formtools/wizard.py:130
#: contrib/formtools/wizard.py:132
msgid ""
"We apologize, but your form has expired. Please continue filling out the "
"form from this page."
@ -3811,6 +3913,10 @@ msgstr "Prowincja Północno-Zachodnia"
msgid "Western Cape"
msgstr "Prowincja Przylądkowa Zachodnia"
#: contrib/messages/tests/base.py:97
msgid "lazy message"
msgstr "testowa wiadomość z opóźnioną ewaluacją"
#: contrib/redirects/models.py:7
msgid "redirect from"
msgstr "przekieruj z"
@ -3919,14 +4025,22 @@ msgstr ""
msgid "Enter a valid time in HH:MM[:ss[.uuuuuu]] format."
msgstr "Proszę wpisać poprawną godzinę w formacie HH:MM[:ss[.uuuuuu]]."
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: db/models/fields/related.py:816
=======
#: db/models/fields/related.py:869
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
msgid ""
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgstr ""
"Przytrzymaj wciśnięty klawisz \"Ctrl\" lub \"Command\" na Mac'u aby "
"zaznaczyć więcej niż jeden wybór."
<<<<<<< HEAD:django/conf/locale/pl/LC_MESSAGES/django.po
#: db/models/fields/related.py:894
=======
#: db/models/fields/related.py:930
>>>>>>> master:django/conf/locale/pl/LC_MESSAGES/django.po
#, python-format
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
msgid_plural ""
@ -4427,17 +4541,17 @@ msgstr "Y-m"
msgid "MONTH_DAY_FORMAT"
msgstr "m-d"
#: views/generic/create_update.py:114
#: views/generic/create_update.py:115
#, python-format
msgid "The %(verbose_name)s was created successfully."
msgstr "%(verbose_name)s zostało pomyślnie utworzone."
#: views/generic/create_update.py:156
#: views/generic/create_update.py:158
#, python-format
msgid "The %(verbose_name)s was updated successfully."
msgstr "%(verbose_name)s zostało pomyślnie zmienione."
#: views/generic/create_update.py:198
#: views/generic/create_update.py:201
#, python-format
msgid "The %(verbose_name)s was deleted."
msgstr "%(verbose_name)s zostało usunięte."

View File

@ -1059,7 +1059,7 @@ class ModelAdmin(BaseModelAdmin):
content_type__id__exact = ContentType.objects.get_for_model(model).id
).select_related().order_by('action_time')
# If no history was found, see whether this object even exists.
obj = get_object_or_404(model, pk=object_id)
obj = get_object_or_404(model, pk=unquote(object_id))
context = {
'title': _('Change history: %s') % force_unicode(obj),
'action_list': action_list,

View File

@ -1,4 +1,5 @@
import datetime
from warnings import warn
from django.core.exceptions import ImproperlyConfigured
from django.utils.importlib import import_module
@ -19,6 +20,12 @@ def load_backend(path):
cls = getattr(mod, attr)
except AttributeError:
raise ImproperlyConfigured, 'Module "%s" does not define a "%s" authentication backend' % (module, attr)
try:
getattr(cls, 'supports_object_permissions')
except AttributeError:
warn("Authentication backends without a `supports_object_permissions` attribute are deprecated. Please define it in %s." % cls,
PendingDeprecationWarning)
cls.supports_object_permissions = False
return cls()
def get_backends():

View File

@ -11,6 +11,8 @@ class ModelBackend(object):
"""
Authenticates against django.contrib.auth.models.User.
"""
supports_object_permissions = False
# TODO: Model, login attribute name and password attribute name should be
# configurable.
def authenticate(self, username=None, password=None):

View File

@ -121,7 +121,8 @@ class UserManager(models.Manager):
return ''.join([choice(allowed_chars) for i in range(length)])
class User(models.Model):
"""Users within the Django authentication system are represented by this model.
"""
Users within the Django authentication system are represented by this model.
Username and password are required. Other fields are optional.
"""
@ -151,11 +152,16 @@ class User(models.Model):
return "/users/%s/" % urllib.quote(smart_str(self.username))
def is_anonymous(self):
"Always returns False. This is a way of comparing User objects to anonymous users."
"""
Always returns False. This is a way of comparing User objects to
anonymous users.
"""
return False
def is_authenticated(self):
"""Always return True. This is a way to tell if the user has been authenticated in templates.
"""
Always return True. This is a way to tell if the user has been
authenticated in templates.
"""
return True
@ -194,30 +200,41 @@ class User(models.Model):
def has_usable_password(self):
return self.password != UNUSABLE_PASSWORD
def get_group_permissions(self):
def get_group_permissions(self, obj=None):
"""
Returns a list of permission strings that this user has through
his/her groups. This method queries all available auth backends.
If an object is passed in, only permissions matching this object
are returned.
"""
permissions = set()
for backend in auth.get_backends():
if hasattr(backend, "get_group_permissions"):
permissions.update(backend.get_group_permissions(self))
if obj is not None and backend.supports_object_permissions:
group_permissions = backend.get_group_permissions(self, obj)
else:
group_permissions = backend.get_group_permissions(self)
permissions.update(group_permissions)
return permissions
def get_all_permissions(self):
def get_all_permissions(self, obj=None):
permissions = set()
for backend in auth.get_backends():
if hasattr(backend, "get_all_permissions"):
permissions.update(backend.get_all_permissions(self))
if obj is not None and backend.supports_object_permissions:
all_permissions = backend.get_all_permissions(self, obj)
else:
all_permissions = backend.get_all_permissions(self)
permissions.update(all_permissions)
return permissions
def has_perm(self, perm):
def has_perm(self, perm, obj=None):
"""
Returns True if the user has the specified permission. This method
queries all available auth backends, but returns immediately if any
backend returns True. Thus, a user who has permission from a single
auth backend is assumed to have permission in general.
auth backend is assumed to have permission in general. If an object
is provided, permissions for this specific object are checked.
"""
# Inactive users have no permissions.
if not self.is_active:
@ -230,14 +247,22 @@ class User(models.Model):
# Otherwise we need to check the backends.
for backend in auth.get_backends():
if hasattr(backend, "has_perm"):
if backend.has_perm(self, perm):
return True
if obj is not None and backend.supports_object_permissions:
if backend.has_perm(self, perm, obj):
return True
else:
if backend.has_perm(self, perm):
return True
return False
def has_perms(self, perm_list):
"""Returns True if the user has each of the specified permissions."""
def has_perms(self, perm_list, obj=None):
"""
Returns True if the user has each of the specified permissions.
If object is passed, it checks if the user has all required perms
for this object.
"""
for perm in perm_list:
if not self.has_perm(perm):
if not self.has_perm(perm, obj):
return False
return True
@ -358,10 +383,10 @@ class AnonymousUser(object):
return self._user_permissions
user_permissions = property(_get_user_permissions)
def has_perm(self, perm):
def has_perm(self, perm, obj=None):
return False
def has_perms(self, perm_list):
def has_perms(self, perm_list, obj=None):
return False
def has_module_perms(self, module):

View File

@ -4,6 +4,7 @@ from django.contrib.auth.tests.views \
from django.contrib.auth.tests.forms import FORM_TESTS
from django.contrib.auth.tests.remote_user \
import RemoteUserTest, RemoteUserNoCreateTest, RemoteUserCustomTest
from django.contrib.auth.tests.auth_backends import BackendTest, RowlevelBackendTest
from django.contrib.auth.tests.tokens import TOKEN_GENERATOR_TESTS
# The password for the fixture data users is 'password'

View File

@ -0,0 +1,149 @@
from django.conf import settings
from django.contrib.auth.models import User, Group, Permission, AnonymousUser
from django.contrib.contenttypes.models import ContentType
from django.test import TestCase
class BackendTest(TestCase):
backend = 'django.contrib.auth.backends.ModelBackend'
def setUp(self):
self.curr_auth = settings.AUTHENTICATION_BACKENDS
settings.AUTHENTICATION_BACKENDS = (self.backend,)
User.objects.create_user('test', 'test@example.com', 'test')
def tearDown(self):
settings.AUTHENTICATION_BACKENDS = self.curr_auth
def test_has_perm(self):
user = User.objects.get(username='test')
self.assertEqual(user.has_perm('auth.test'), False)
user.is_staff = True
user.save()
self.assertEqual(user.has_perm('auth.test'), False)
user.is_superuser = True
user.save()
self.assertEqual(user.has_perm('auth.test'), True)
user.is_staff = False
user.is_superuser = False
user.save()
self.assertEqual(user.has_perm('auth.test'), False)
def test_custom_perms(self):
user = User.objects.get(username='test')
content_type=ContentType.objects.get_for_model(Group)
perm = Permission.objects.create(name='test', content_type=content_type, codename='test')
user.user_permissions.add(perm)
user.save()
# reloading user to purge the _perm_cache
user = User.objects.get(username='test')
self.assertEqual(user.get_all_permissions() == set([u'auth.test']), True)
self.assertEqual(user.get_group_permissions(), set([]))
self.assertEqual(user.has_module_perms('Group'), False)
self.assertEqual(user.has_module_perms('auth'), True)
perm = Permission.objects.create(name='test2', content_type=content_type, codename='test2')
user.user_permissions.add(perm)
user.save()
perm = Permission.objects.create(name='test3', content_type=content_type, codename='test3')
user.user_permissions.add(perm)
user.save()
user = User.objects.get(username='test')
self.assertEqual(user.get_all_permissions(), set([u'auth.test2', u'auth.test', u'auth.test3']))
self.assertEqual(user.has_perm('test'), False)
self.assertEqual(user.has_perm('auth.test'), True)
self.assertEqual(user.has_perms(['auth.test2', 'auth.test3']), True)
perm = Permission.objects.create(name='test_group', content_type=content_type, codename='test_group')
group = Group.objects.create(name='test_group')
group.permissions.add(perm)
group.save()
user.groups.add(group)
user = User.objects.get(username='test')
exp = set([u'auth.test2', u'auth.test', u'auth.test3', u'auth.test_group'])
self.assertEqual(user.get_all_permissions(), exp)
self.assertEqual(user.get_group_permissions(), set([u'auth.test_group']))
self.assertEqual(user.has_perms(['auth.test3', 'auth.test_group']), True)
user = AnonymousUser()
self.assertEqual(user.has_perm('test'), False)
self.assertEqual(user.has_perms(['auth.test2', 'auth.test3']), False)
class TestObj(object):
pass
class SimpleRowlevelBackend(object):
supports_object_permissions = True
def has_perm(self, user, perm, obj=None):
if not obj:
return # We only support row level perms
if isinstance(obj, TestObj):
if user.username == 'test2':
return True
elif isinstance(user, AnonymousUser) and perm == 'anon':
return True
return False
def get_all_permissions(self, user, obj=None):
if not obj:
return [] # We only support row level perms
if not isinstance(obj, TestObj):
return ['none']
if user.username == 'test2':
return ['simple', 'advanced']
else:
return ['simple']
def get_group_permissions(self, user, obj=None):
if not obj:
return # We only support row level perms
if not isinstance(obj, TestObj):
return ['none']
if 'test_group' in [group.name for group in user.groups.all()]:
return ['group_perm']
else:
return ['none']
class RowlevelBackendTest(TestCase):
backend = 'django.contrib.auth.tests.auth_backends.SimpleRowlevelBackend'
def setUp(self):
self.curr_auth = settings.AUTHENTICATION_BACKENDS
settings.AUTHENTICATION_BACKENDS = self.curr_auth + (self.backend,)
self.user1 = User.objects.create_user('test', 'test@example.com', 'test')
self.user2 = User.objects.create_user('test2', 'test2@example.com', 'test')
self.user3 = AnonymousUser()
self.user4 = User.objects.create_user('test4', 'test4@example.com', 'test')
def tearDown(self):
settings.AUTHENTICATION_BACKENDS = self.curr_auth
def test_has_perm(self):
self.assertEqual(self.user1.has_perm('perm', TestObj()), False)
self.assertEqual(self.user2.has_perm('perm', TestObj()), True)
self.assertEqual(self.user2.has_perm('perm'), False)
self.assertEqual(self.user2.has_perms(['simple', 'advanced'], TestObj()), True)
self.assertEqual(self.user3.has_perm('perm', TestObj()), False)
self.assertEqual(self.user3.has_perm('anon', TestObj()), False)
self.assertEqual(self.user3.has_perms(['simple', 'advanced'], TestObj()), False)
def test_get_all_permissions(self):
self.assertEqual(self.user1.get_all_permissions(TestObj()), set(['simple']))
self.assertEqual(self.user2.get_all_permissions(TestObj()), set(['simple', 'advanced']))
self.assertEqual(self.user2.get_all_permissions(), set([]))
def test_get_group_permissions(self):
content_type=ContentType.objects.get_for_model(Group)
group = Group.objects.create(name='test_group')
self.user4.groups.add(group)
self.assertEqual(self.user4.get_group_permissions(TestObj()), set(['group_perm']))

View File

@ -279,11 +279,19 @@ class RelatedGeoModelTest(unittest.TestCase):
def test14_collect(self):
"Testing the `collect` GeoQuerySet method and `Collect` aggregate."
# Reference query:
<<<<<<< HEAD:django/contrib/gis/tests/relatedapp/tests.py
# SELECT AsText(ST_Collect("relatedapp_location"."point")) FROM "relatedapp_city" LEFT OUTER JOIN
# "relatedapp_location" ON ("relatedapp_city"."location_id" = "relatedapp_location"."id")
# WHERE "relatedapp_city"."state" = 'TX';
ref_geom = fromstr('MULTIPOINT(-97.516111 33.058333,-96.801611 32.782057,-95.363151 29.763374,-96.801611 32.782057)')
=======
# SELECT AsText(ST_Collect("relatedapp_location"."point")) FROM "relatedapp_city" LEFT OUTER JOIN
# "relatedapp_location" ON ("relatedapp_city"."location_id" = "relatedapp_location"."id")
# WHERE "relatedapp_city"."state" = 'TX';
ref_geom = fromstr('MULTIPOINT(-97.516111 33.058333,-96.801611 32.782057,-95.363151 29.763374,-96.801611 32.782057)')
>>>>>>> master:django/contrib/gis/tests/relatedapp/tests.py
c1 = City.objects.filter(state='TX').collect(field_name='location__point')
c2 = City.objects.filter(state='TX').aggregate(Collect('location__point'))['location__point__collect']
@ -292,7 +300,10 @@ class RelatedGeoModelTest(unittest.TestCase):
# consolidate -- that's why 4 points in MultiPoint.
self.assertEqual(4, len(coll))
self.assertEqual(ref_geom, coll)
<<<<<<< HEAD:django/contrib/gis/tests/relatedapp/tests.py
=======
>>>>>>> master:django/contrib/gis/tests/relatedapp/tests.py
# TODO: Related tests for KML, GML, and distance lookups.

View File

@ -82,9 +82,14 @@ class Command(BaseCommand):
model_list = get_models(app)
for model in model_list:
<<<<<<< HEAD:django/core/management/commands/dumpdata.py
# Don't serialize proxy models, or models that haven't been synchronized
if not model._meta.proxy and model._meta.db_table in tables:
objects.extend(model._default_manager.using(using).all())
=======
if not model._meta.proxy:
objects.extend(model._default_manager.all())
>>>>>>> master:django/core/management/commands/dumpdata.py
try:
return serializers.serialize(format, objects, indent=indent)

View File

@ -357,7 +357,11 @@ class DatabaseWrapper(BaseDatabaseWrapper):
cursor = None
if not self._valid_connection():
conn_string = convert_unicode(self._connect_string())
<<<<<<< HEAD:django/db/backends/oracle/base.py
self.connection = Database.connect(conn_string, **self.settings_dict['OPTIONS'])
=======
self.connection = Database.connect(conn_string, **self.settings_dict['DATABASE_OPTIONS'])
>>>>>>> master:django/db/backends/oracle/base.py
cursor = FormatStylePlaceholderCursor(self.connection)
# Set oracle date to ansi date format. This only needs to execute
# once when we create a new connection. We also set the Territory

View File

@ -230,6 +230,7 @@ class ModelBase(type):
signals.class_prepared.send(sender=cls)
<<<<<<< HEAD:django/db/models/base.py
class ModelState(object):
"""
A class for storing instance state
@ -237,6 +238,8 @@ class ModelState(object):
def __init__(self, db=None):
self.db = db
=======
>>>>>>> master:django/db/models/base.py
class Model(object):
__metaclass__ = ModelBase
_deferred = False
@ -488,7 +491,11 @@ class Model(object):
if pk_set:
# Determine whether a record with the primary key already exists.
if (force_update or (not force_insert and
<<<<<<< HEAD:django/db/models/base.py
manager.using(using).filter(pk=pk_val).exists())):
=======
manager.filter(pk=pk_val).exists())):
>>>>>>> master:django/db/models/base.py
# It does already exist, so do an UPDATE.
if force_update or non_pks:
values = [(f, None, (raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks]
@ -527,7 +534,10 @@ class Model(object):
# Store the database on which the object was saved
self._state.db = using
<<<<<<< HEAD:django/db/models/base.py
# Signal that the save is complete
=======
>>>>>>> master:django/db/models/base.py
if origin and not meta.auto_created:
signals.post_save.send(sender=origin, instance=self,
created=(not record_exists), raw=raw)

View File

@ -474,7 +474,11 @@ def create_many_related_manager(superclass, rel=False):
if not rel.through._meta.auto_created:
opts = through._meta
raise AttributeError, "Cannot use create() on a ManyToManyField which specifies an intermediary model. Use %s.%s's Manager instead." % (opts.app_label, opts.object_name)
<<<<<<< HEAD:django/db/models/fields/related.py
new_obj = super(ManyRelatedManager, self).using(self.instance._state.db).create(**kwargs)
=======
new_obj = super(ManyRelatedManager, self).create(**kwargs)
>>>>>>> master:django/db/models/fields/related.py
self.add(new_obj)
return new_obj
create.alters_data = True
@ -501,15 +505,22 @@ def create_many_related_manager(superclass, rel=False):
new_ids = set()
for obj in objs:
if isinstance(obj, self.model):
<<<<<<< HEAD:django/db/models/fields/related.py
if obj._state.db != self.instance._state.db:
raise ValueError('Cannot add "%r": instance is on database "%s", value is is on database "%s"' %
(obj, self.instance._state.db, obj._state.db))
=======
>>>>>>> master:django/db/models/fields/related.py
new_ids.add(obj.pk)
elif isinstance(obj, Model):
raise TypeError, "'%s' instance expected" % self.model._meta.object_name
else:
new_ids.add(obj)
<<<<<<< HEAD:django/db/models/fields/related.py
vals = self.through._default_manager.using(self.instance._state.db).values_list(target_field_name, flat=True)
=======
vals = self.through._default_manager.values_list(target_field_name, flat=True)
>>>>>>> master:django/db/models/fields/related.py
vals = vals.filter(**{
source_field_name: self._pk_val,
'%s__in' % target_field_name: new_ids,
@ -518,7 +529,11 @@ def create_many_related_manager(superclass, rel=False):
# Add the ones that aren't there already
for obj_id in (new_ids - vals):
<<<<<<< HEAD:django/db/models/fields/related.py
self.through._default_manager.using(self.instance._state.db).create(**{
=======
self.through._default_manager.create(**{
>>>>>>> master:django/db/models/fields/related.py
'%s_id' % source_field_name: self._pk_val,
'%s_id' % target_field_name: obj_id,
})
@ -538,14 +553,22 @@ def create_many_related_manager(superclass, rel=False):
else:
old_ids.add(obj)
# Remove the specified objects from the join table
<<<<<<< HEAD:django/db/models/fields/related.py
self.through._default_manager.using(self.instance._state.db).filter(**{
=======
self.through._default_manager.filter(**{
>>>>>>> master:django/db/models/fields/related.py
source_field_name: self._pk_val,
'%s__in' % target_field_name: old_ids
}).delete()
def _clear_items(self, source_field_name):
# source_col_name: the PK colname in join_table for the source object
<<<<<<< HEAD:django/db/models/fields/related.py
self.through._default_manager.using(self.instance._state.db).filter(**{
=======
self.through._default_manager.filter(**{
>>>>>>> master:django/db/models/fields/related.py
source_field_name: self._pk_val
}).delete()

View File

@ -172,9 +172,12 @@ class Manager(object):
def only(self, *args, **kwargs):
return self.get_query_set().only(*args, **kwargs)
<<<<<<< HEAD:django/db/models/manager.py
def using(self, *args, **kwargs):
return self.get_query_set().using(*args, **kwargs)
=======
>>>>>>> master:django/db/models/manager.py
def exists(self, *args, **kwargs):
return self.get_query_set().exists(*args, **kwargs)

View File

@ -3,8 +3,12 @@ The main QuerySet implementation. This provides the public API for the ORM.
"""
from copy import deepcopy
<<<<<<< HEAD:django/db/models/query.py
from django.db import connections, transaction, IntegrityError, DEFAULT_DB_ALIAS
=======
from django.db import connection, transaction, IntegrityError
>>>>>>> master:django/db/models/query.py
from django.db.models.aggregates import Aggregate
from django.db.models.fields import DateField
from django.db.models.query_utils import Q, select_related_descend, CollectedObjects, CyclicDependency, deferred_class_factory
@ -476,7 +480,11 @@ class QuerySet(object):
def exists(self):
if self._result_cache is None:
<<<<<<< HEAD:django/db/models/query.py
return self.query.has_results(using=self.db)
=======
return self.query.has_results()
>>>>>>> master:django/db/models/query.py
return bool(self._result_cache)
##################################################

View File

@ -22,8 +22,12 @@ from django.db.models.sql.expressions import SQLEvaluator
from django.db.models.sql.where import WhereNode, Constraint, EverythingNode, AND, OR
from django.core.exceptions import FieldError
<<<<<<< HEAD:django/db/models/sql/query.py
__all__ = ['Query']
=======
__all__ = ['Query', 'BaseQuery']
>>>>>>> master:django/db/models/sql/query.py
class Query(object):
"""
@ -337,7 +341,11 @@ class Query(object):
return number
<<<<<<< HEAD:django/db/models/sql/query.py
def has_results(self, using):
=======
def has_results(self):
>>>>>>> master:django/db/models/sql/query.py
q = self.clone()
q.add_extra({'a': 1}, None, None, None, None, None)
q.add_fields(())
@ -345,8 +353,104 @@ class Query(object):
q.set_aggregate_mask(())
q.clear_ordering()
q.set_limits(high=1)
<<<<<<< HEAD:django/db/models/sql/query.py
compiler = q.get_compiler(using=using)
return bool(compiler.execute_sql(SINGLE))
=======
return bool(q.execute_sql(SINGLE))
def as_sql(self, with_limits=True, with_col_aliases=False):
"""
Creates the SQL for this query. Returns the SQL string and list of
parameters.
If 'with_limits' is False, any limit/offset information is not included
in the query.
"""
self.pre_sql_setup()
out_cols = self.get_columns(with_col_aliases)
ordering, ordering_group_by = self.get_ordering()
# This must come after 'select' and 'ordering' -- see docstring of
# get_from_clause() for details.
from_, f_params = self.get_from_clause()
qn = self.quote_name_unless_alias
where, w_params = self.where.as_sql(qn=qn)
having, h_params = self.having.as_sql(qn=qn)
params = []
for val in self.extra_select.itervalues():
params.extend(val[1])
result = ['SELECT']
if self.distinct:
result.append('DISTINCT')
result.append(', '.join(out_cols + self.ordering_aliases))
result.append('FROM')
result.extend(from_)
params.extend(f_params)
if where:
result.append('WHERE %s' % where)
params.extend(w_params)
if self.extra_where:
if not where:
result.append('WHERE')
else:
result.append('AND')
result.append(' AND '.join(self.extra_where))
grouping, gb_params = self.get_grouping()
if grouping:
if ordering:
# If the backend can't group by PK (i.e., any database
# other than MySQL), then any fields mentioned in the
# ordering clause needs to be in the group by clause.
if not self.connection.features.allows_group_by_pk:
for col, col_params in ordering_group_by:
if col not in grouping:
grouping.append(str(col))
gb_params.extend(col_params)
else:
ordering = self.connection.ops.force_no_ordering()
result.append('GROUP BY %s' % ', '.join(grouping))
params.extend(gb_params)
if having:
result.append('HAVING %s' % having)
params.extend(h_params)
if ordering:
result.append('ORDER BY %s' % ', '.join(ordering))
if with_limits:
if self.high_mark is not None:
result.append('LIMIT %d' % (self.high_mark - self.low_mark))
if self.low_mark:
if self.high_mark is None:
val = self.connection.ops.no_limit_value()
if val:
result.append('LIMIT %d' % val)
result.append('OFFSET %d' % self.low_mark)
params.extend(self.extra_params)
return ' '.join(result), tuple(params)
def as_nested_sql(self):
"""
Perform the same functionality as the as_sql() method, returning an
SQL string and parameters. However, the alias prefixes are bumped
beforehand (in a copy -- the current query isn't changed) and any
ordering is removed.
Used when nesting this query inside another.
"""
obj = self.clone()
obj.clear_ordering(True)
obj.bump_prefix()
return obj.as_sql()
>>>>>>> master:django/db/models/sql/query.py
def combine(self, rhs, connector):
"""

View File

@ -471,8 +471,12 @@ class BaseModelFormSet(BaseFormSet):
pk_key = "%s-%s" % (self.add_prefix(i), self.model._meta.pk.name)
pk = self.data[pk_key]
pk_field = self.model._meta.pk
<<<<<<< HEAD:django/forms/models.py
pk = pk_field.get_db_prep_lookup('exact', pk,
connection=connections[self.get_queryset().db])
=======
pk = pk_field.get_db_prep_lookup('exact', pk)
>>>>>>> master:django/forms/models.py
if isinstance(pk, list):
pk = pk[0]
kwargs['instance'] = self._existing_object(pk)

View File

@ -11,6 +11,7 @@ except NameError:
from django.template import Node, NodeList, Template, Context, Variable
from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END
from django.template import get_library, Library, InvalidTemplateLibrary
from django.template.smartif import IfParser, Literal
from django.conf import settings
from django.utils.encoding import smart_str, smart_unicode
from django.utils.itercompat import groupby
@ -227,10 +228,9 @@ class IfEqualNode(Node):
return self.nodelist_false.render(context)
class IfNode(Node):
def __init__(self, bool_exprs, nodelist_true, nodelist_false, link_type):
self.bool_exprs = bool_exprs
def __init__(self, var, nodelist_true, nodelist_false=None):
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
self.link_type = link_type
self.var = var
def __repr__(self):
return "<If node>"
@ -250,28 +250,10 @@ class IfNode(Node):
return nodes
def render(self, context):
if self.link_type == IfNode.LinkTypes.or_:
for ifnot, bool_expr in self.bool_exprs:
try:
value = bool_expr.resolve(context, True)
except VariableDoesNotExist:
value = None
if (value and not ifnot) or (ifnot and not value):
return self.nodelist_true.render(context)
return self.nodelist_false.render(context)
else:
for ifnot, bool_expr in self.bool_exprs:
try:
value = bool_expr.resolve(context, True)
except VariableDoesNotExist:
value = None
if not ((value and not ifnot) or (ifnot and not value)):
return self.nodelist_false.render(context)
if self.var.eval(context):
return self.nodelist_true.render(context)
class LinkTypes:
and_ = 0,
or_ = 1
else:
return self.nodelist_false.render(context)
class RegroupNode(Node):
def __init__(self, target, expression, var_name):
@ -761,6 +743,27 @@ def ifnotequal(parser, token):
return do_ifequal(parser, token, True)
ifnotequal = register.tag(ifnotequal)
class TemplateLiteral(Literal):
def __init__(self, value, text):
self.value = value
self.text = text # for better error messages
def display(self):
return self.text
def eval(self, context):
return self.value.resolve(context, ignore_failures=True)
class TemplateIfParser(IfParser):
error_class = TemplateSyntaxError
def __init__(self, parser, *args, **kwargs):
self.template_parser = parser
return super(TemplateIfParser, self).__init__(*args, **kwargs)
def create_var(self, value):
return TemplateLiteral(self.template_parser.compile_filter(value), value)
#@register.tag(name="if")
def do_if(parser, token):
"""
@ -805,47 +808,21 @@ def do_if(parser, token):
There are some athletes and absolutely no coaches.
{% endif %}
``if`` tags do not allow ``and`` and ``or`` clauses with the same tag,
because the order of logic would be ambigous. For example, this is
invalid::
Comparison operators are also available, and the use of filters is also
allowed, for example:
{% if athlete_list and coach_list or cheerleader_list %}
{% if articles|length >= 5 %}...{% endif %}
If you need to combine ``and`` and ``or`` to do advanced logic, just use
nested if tags. For example::
Arguments and operators _must_ have a space between them, so
``{% if 1>2 %}`` is not a valid if tag.
{% if athlete_list %}
{% if coach_list or cheerleader_list %}
We have athletes, and either coaches or cheerleaders!
{% endif %}
{% endif %}
All supported operators are: ``or``, ``and``, ``in``, ``==`` (or ``=``),
``!=``, ``>``, ``>=``, ``<`` and ``<=``.
Operator precedence follows Python.
"""
bits = token.contents.split()
del bits[0]
if not bits:
raise TemplateSyntaxError("'if' statement requires at least one argument")
# Bits now looks something like this: ['a', 'or', 'not', 'b', 'or', 'c.d']
bitstr = ' '.join(bits)
boolpairs = bitstr.split(' and ')
boolvars = []
if len(boolpairs) == 1:
link_type = IfNode.LinkTypes.or_
boolpairs = bitstr.split(' or ')
else:
link_type = IfNode.LinkTypes.and_
if ' or ' in bitstr:
raise TemplateSyntaxError, "'if' tags can't mix 'and' and 'or'"
for boolpair in boolpairs:
if ' ' in boolpair:
try:
not_, boolvar = boolpair.split()
except ValueError:
raise TemplateSyntaxError, "'if' statement improperly formatted"
if not_ != 'not':
raise TemplateSyntaxError, "Expected 'not' in if statement"
boolvars.append((True, parser.compile_filter(boolvar)))
else:
boolvars.append((False, parser.compile_filter(boolpair)))
bits = token.split_contents()[1:]
var = TemplateIfParser(parser, bits).parse()
nodelist_true = parser.parse(('else', 'endif'))
token = parser.next_token()
if token.contents == 'else':
@ -853,7 +830,7 @@ def do_if(parser, token):
parser.delete_first_token()
else:
nodelist_false = NodeList()
return IfNode(boolvars, nodelist_true, nodelist_false, link_type)
return IfNode(var, nodelist_true, nodelist_false)
do_if = register.tag("if", do_if)
#@register.tag

192
django/template/smartif.py Normal file
View File

@ -0,0 +1,192 @@
"""
Parser and utilities for the smart 'if' tag
"""
import operator
# Using a simple top down parser, as described here:
# http://effbot.org/zone/simple-top-down-parsing.htm.
# 'led' = left denotation
# 'nud' = null denotation
# 'bp' = binding power (left = lbp, right = rbp)
class TokenBase(object):
"""
Base class for operators and literals, mainly for debugging and for throwing
syntax errors.
"""
id = None # node/token type name
value = None # used by literals
first = second = None # used by tree nodes
def nud(self, parser):
# Null denotation - called in prefix context
raise parser.error_class(
"Not expecting '%s' in this position in if tag." % self.id
)
def led(self, left, parser):
# Left denotation - called in infix context
raise parser.error_class(
"Not expecting '%s' as infix operator in if tag." % self.id
)
def display(self):
"""
Returns what to display in error messages for this node
"""
return self.id
def __repr__(self):
out = [str(x) for x in [self.id, self.first, self.second] if x is not None]
return "(" + " ".join(out) + ")"
def infix(bp, func):
"""
Creates an infix operator, given a binding power and a function that
evaluates the node
"""
class Operator(TokenBase):
lbp = bp
def led(self, left, parser):
self.first = left
self.second = parser.expression(bp)
return self
def eval(self, context):
try:
return func(self.first.eval(context), self.second.eval(context))
except Exception:
# Templates shouldn't throw exceptions when rendering. We are
# most likely to get exceptions for things like {% if foo in bar
# %} where 'bar' does not support 'in', so default to False
return False
return Operator
def prefix(bp, func):
"""
Creates a prefix operator, given a binding power and a function that
evaluates the node.
"""
class Operator(TokenBase):
lbp = bp
def nud(self, parser):
self.first = parser.expression(bp)
self.second = None
return self
def eval(self, context):
try:
return func(self.first.eval(context))
except Exception:
return False
return Operator
# Operator precedence follows Python.
# NB - we can get slightly more accurate syntax error messages by not using the
# same object for '==' and '='.
OPERATORS = {
'or': infix(6, lambda x, y: x or y),
'and': infix(7, lambda x, y: x and y),
'not': prefix(8, operator.not_),
'in': infix(9, lambda x, y: x in y),
'=': infix(10, operator.eq),
'==': infix(10, operator.eq),
'!=': infix(10, operator.ne),
'>': infix(10, operator.gt),
'>=': infix(10, operator.ge),
'<': infix(10, operator.lt),
'<=': infix(10, operator.le),
}
# Assign 'id' to each:
for key, op in OPERATORS.items():
op.id = key
class Literal(TokenBase):
"""
A basic self-resolvable object similar to a Django template variable.
"""
# IfParser uses Literal in create_var, but TemplateIfParser overrides
# create_var so that a proper implementation that actually resolves
# variables, filters etc is used.
id = "literal"
lbp = 0
def __init__(self, value):
self.value = value
def display(self):
return repr(self.value)
def nud(self, parser):
return self
def eval(self, context):
return self.value
def __repr__(self):
return "(%s %r)" % (self.id, self.value)
class EndToken(TokenBase):
lbp = 0
def nud(self, parser):
raise parser.error_class("Unexpected end of expression in if tag.")
EndToken = EndToken()
class IfParser(object):
error_class = ValueError
def __init__(self, tokens):
self.tokens = map(self.translate_tokens, tokens)
self.pos = 0
self.current_token = self.next()
def translate_tokens(self, token):
try:
op = OPERATORS[token]
except (KeyError, TypeError):
return self.create_var(token)
else:
return op()
def next(self):
if self.pos >= len(self.tokens):
return EndToken
else:
retval = self.tokens[self.pos]
self.pos += 1
return retval
def parse(self):
retval = self.expression()
# Check that we have exhausted all the tokens
if self.current_token is not EndToken:
raise self.error_class("Unused '%s' at end of if expression." %
self.current_token.display())
return retval
def expression(self, rbp=0):
t = self.current_token
self.current_token = self.next()
left = t.nud(self)
while rbp < self.current_token.lbp:
t = self.current_token
self.current_token = self.next()
left = t.led(left, self)
return left
def create_var(self, value):
return Literal(value)

View File

@ -13,6 +13,13 @@ their deprecation, as per the :ref:`Django deprecation policy
hooking up admin URLs. This has been deprecated since the 1.1
release.
<<<<<<< HEAD:docs/internals/deprecation.txt
=======
* Authentication backends need to define the boolean attribute
``supports_object_permissions``. The old backend style is deprecated
since the 1.2 release.
>>>>>>> master:docs/internals/deprecation.txt
* 1.4
* ``CsrfResponseMiddleware``. This has been deprecated since the 1.2
release, in favour of the template tag method for inserting the CSRF
@ -26,6 +33,7 @@ their deprecation, as per the :ref:`Django deprecation policy
class in favor of a generic E-mail backend API.
* The many to many SQL generation functions on the database backends
<<<<<<< HEAD:docs/internals/deprecation.txt
will be removed.
* The ability to use the ``DATABASE_*`` family of top-level settings to
@ -39,6 +47,9 @@ their deprecation, as per the :ref:`Django deprecation policy
``get_db_prep_lookup`` methods on Field were modified in 1.2 to support
multiple databases. In 1.4, the support functions that allow methods
with the old prototype to continue working will be removed.
=======
will be removed. These have been deprecated since the 1.2 release.
>>>>>>> master:docs/internals/deprecation.txt
* The ``Message`` model (in ``django.contrib.auth``), its related
manager in the ``User`` model (``user.message_set``), and the
@ -48,6 +59,13 @@ their deprecation, as per the :ref:`Django deprecation policy
:ref:`messages framework <ref-contrib-messages>` should be used
instead.
<<<<<<< HEAD:docs/internals/deprecation.txt
=======
* Authentication backends need to support the ``obj`` parameter for
permission checking. The ``supports_object_permissions`` variable
is not checked any longer and can be removed.
>>>>>>> master:docs/internals/deprecation.txt
* 2.0
* ``django.views.defaults.shortcut()``. This function has been moved
to ``django.contrib.contenttypes.views.shortcut()`` as part of the

View File

@ -257,7 +257,10 @@ Here's a sample configuration which uses a MySQL option file::
}
}
<<<<<<< HEAD:docs/ref/databases.txt
=======
>>>>>>> master:docs/ref/databases.txt
# my.cnf
[client]
database = NAME

View File

@ -210,6 +210,24 @@ records to dump. If you're using a :ref:`custom manager <custom-managers>` as
the default manager and it filters some of the available records, not all of the
objects will be dumped.
<<<<<<< HEAD:docs/ref/django-admin.txt
=======
.. django-admin-option:: --exclude
.. versionadded:: 1.0
Exclude a specific application from the applications whose contents is
output. For example, to specifically exclude the `auth` application from
the output, you would call::
django-admin.py dumpdata --exclude=auth
If you want to exclude multiple applications, use multiple ``--exclude``
directives::
django-admin.py dumpdata --exclude=auth --exclude=contenttypes
>>>>>>> master:docs/ref/django-admin.txt
.. django-admin-option:: --format <fmt>
By default, ``dumpdata`` will format its output in JSON, but you can use the
@ -221,11 +239,14 @@ are listed in :ref:`serialization-formats`.
By default, ``dumpdata`` will output all data on a single line. This isn't
easy for humans to read, so you can use the ``--indent`` option to
pretty-print the output with a number of indentation spaces.
<<<<<<< HEAD:docs/ref/django-admin.txt
.. versionadded:: 1.0
The :djadminopt:`--exclude` option may be provided to prevent specific
applications from being dumped.
=======
>>>>>>> master:docs/ref/django-admin.txt
.. versionadded:: 1.1
@ -252,12 +273,15 @@ fixture will be re-installed.
The :djadminopt:`--noinput` option may be provided to suppress all user
prompts.
<<<<<<< HEAD:docs/ref/django-admin.txt
.. versionadded:: 1.2
The :djadminopt:`--database` option may be used to specify the database
to flush.
=======
>>>>>>> master:docs/ref/django-admin.txt
inspectdb
---------
@ -487,6 +511,7 @@ reset <appname appname ...>
---------------------------
.. django-admin:: reset
<<<<<<< HEAD:docs/ref/django-admin.txt
Executes the equivalent of ``sqlreset`` for the given app name(s).
@ -497,6 +522,13 @@ prompts.
The :djadminopt:`--database` option can be used to specify the alias
of the database to reset.
=======
Executes the equivalent of ``sqlreset`` for the given app name(s).
The :djadminopt:`--noinput` option may be provided to suppress all user
prompts.
>>>>>>> master:docs/ref/django-admin.txt
runfcgi [options]
-----------------
@ -680,11 +712,14 @@ sqlflush
Prints the SQL statements that would be executed for the :djadmin:`flush`
command.
<<<<<<< HEAD:docs/ref/django-admin.txt
.. versionadded:: 1.2
The :djadminopt:`--database` option can be used to specify the database for
which to print the SQL.
=======
>>>>>>> master:docs/ref/django-admin.txt
sqlindexes <appname appname ...>
--------------------------------
@ -784,6 +819,7 @@ with an appropriate extension (e.g. ``json`` or ``xml``). See the
documentation for ``loaddata`` for details on the specification of fixture
data files.
<<<<<<< HEAD:docs/ref/django-admin.txt
--noinput
~~~~~~~~~
The :djadminopt:`--noinput` option may be provided to suppress all user
@ -793,15 +829,27 @@ prompts.
The :djadminopt:`--database` option can be used to specify the database to
synchronize.
=======
The :djadminopt:`--noinput` option may be provided to suppress all user
prompts.
test <app or test identifier>
-----------------------------
.. django-admin:: test
>>>>>>> master:docs/ref/django-admin.txt
test <app or test identifier>
-----------------------------
<<<<<<< HEAD:docs/ref/django-admin.txt
.. django-admin:: test
Runs tests for all installed models. See :ref:`topics-testing` for more
information.
=======
>>>>>>> master:docs/ref/django-admin.txt
testserver <fixture fixture ...>
--------------------------------
@ -935,6 +983,7 @@ Common options
The following options are not available on every commands, but they are
common to a number of commands.
<<<<<<< HEAD:docs/ref/django-admin.txt
.. django-admin-option:: --database
.. versionadded:: 1.2
@ -959,6 +1008,8 @@ directives::
django-admin.py dumpdata --exclude=auth --exclude=contenttypes
=======
>>>>>>> master:docs/ref/django-admin.txt
.. django-admin-option:: --locale
Use the ``--locale`` or ``-l`` option to specify the locale to process.

View File

@ -145,6 +145,54 @@ The default number of seconds to cache a page when the caching middleware or
``cache_page()`` decorator is used.
.. setting:: CSRF_COOKIE_NAME
<<<<<<< HEAD:docs/ref/settings.txt
=======
CSRF_COOKIE_NAME
----------------
.. versionadded:: 1.2
Default: ``'csrftoken'``
The name of the cookie to use for the CSRF authentication token. This can be whatever you
want. See :ref:`ref-contrib-csrf`.
.. setting:: CSRF_COOKIE_DOMAIN
CSRF_COOKIE_DOMAIN
------------------
.. versionadded:: 1.2
Default: ``None``
The domain to be used when setting the CSRF cookie. This can be useful for
allowing cross-subdomain requests to be exluded from the normal cross site
request forgery protection. It should be set to a string such as
``".lawrence.com"`` to allow a POST request from a form on one subdomain to be
accepted by accepted by a view served from another subdomain.
.. setting:: CSRF_FAILURE_VIEW
CSRF_FAILURE_VIEW
-----------------
.. versionadded:: 1.2
Default: ``'django.views.csrf.csrf_failure'``
A dotted path to the view function to be used when an incoming request
is rejected by the CSRF protection. The function should have this signature::
def csrf_failure(request, reason="")
where ``reason`` is a short message (intended for developers or logging, not for
end users) indicating the reason the request was rejected. See
:ref:`ref-contrib-csrf`.
.. setting:: DATABASE_ENGINE
>>>>>>> master:docs/ref/settings.txt
CSRF_COOKIE_NAME
----------------

View File

@ -313,6 +313,9 @@ displayed by the ``{{ athlete_list|length }}`` variable.
As you can see, the ``if`` tag can take an optional ``{% else %}`` clause that
will be displayed if the test fails.
Boolean operators
^^^^^^^^^^^^^^^^^
``if`` tags may use ``and``, ``or`` or ``not`` to test a number of variables or
to negate a given variable::
@ -338,24 +341,153 @@ to negate a given variable::
There are some athletes and absolutely no coaches.
{% endif %}
``if`` tags don't allow ``and`` and ``or`` clauses within the same tag, because
the order of logic would be ambiguous. For example, this is invalid::
.. versionchanged:: 1.2
Use of both ``and`` and ``or`` clauses within the same tag is allowed, with
``and`` having higher precedence than ``or`` e.g.::
{% if athlete_list and coach_list or cheerleader_list %}
If you need to combine ``and`` and ``or`` to do advanced logic, just use nested
``if`` tags. For example::
will be interpreted like:
{% if athlete_list %}
{% if coach_list or cheerleader_list %}
We have athletes, and either coaches or cheerleaders!
{% endif %}
.. code-block:: python
if (athlete_list and coach_list) or cheerleader_list
Use of actual brackets in the ``if`` tag is invalid syntax. If you need them to
indicate precedence, you should use nested ``if`` tags.
.. versionadded:: 1.2
``if`` tags may also use the operators ``==``, ``!=``, ``<``, ``>``,
``<=``, ``>=`` and ``in`` which work as follows:
``==`` operator
^^^^^^^^^^^^^^^
Equality. Example::
{% if somevar == "x" %}
This appears if variable somevar equals the string "x"
{% endif %}
Multiple uses of the same logical operator are fine, as long as you use the
same operator. For example, this is valid::
``!=`` operator
^^^^^^^^^^^^^^^
Inequality. Example::
{% if somevar != "x" %}
This appears if variable somevar does not equal the string "x",
or if somevar is not found in the context
{% endif %}
``<`` operator
^^^^^^^^^^^^^^
Less than. Example::
{% if somevar < 100 %}
This appears if variable somevar is less than 100.
{% endif %}
``>`` operator
^^^^^^^^^^^^^^
Greater than. Example::
{% if somevar > 0 %}
This appears if variable somevar is greater than 0.
{% endif %}
``<=`` operator
^^^^^^^^^^^^^^^
Less than or equal to. Example::
{% if somevar <= 100 %}
This appears if variable somevar is less than 100 or equal to 100.
{% endif %}
``>=`` operator
^^^^^^^^^^^^^^^
Greater than or equal to. Example::
{% if somevar >= 1 %}
This appears if variable somevar is greater than 1 or equal to 1.
{% endif %}
``in`` operator
^^^^^^^^^^^^^^^
Contained within. This operator is supported by many Python containers to test
whether the given value is in the container. The following are some examples of
how ``x in y`` will be interpreted::
{% if "bc" in "abcdef" %}
This appears since "bc" is a substring of "abcdef"
{% endif %}
{% if "hello" in greetings %}
If greetings is a list or set, one element of which is the string
"hello", this will appear.
{% endif %}
{% if user in users %}
If users is a QuerySet, this will appear if user is an
instance that belongs to the QuerySet.
{% endif %}
The comparison operators cannot be 'chained' like in Python or in mathematical
notation. For example, instead of using::
{% if a > b > c %} (WRONG)
you should use::
{% if a > b and b > c %}
Filters
^^^^^^^
You can also use filters in the ``if`` expression. For example::
{% if messages|length >= 100 %}
You have lots of messages today!
{% endif %}
Complex expressions
^^^^^^^^^^^^^^^^^^^
All of the above can be combined to form complex expressions. For such
expressions, it can be important to know how the operators are grouped when the
expression is evaluated - that is, the precedence rules. The precedence of the
operators, from lowest to highest, is as follows:
* ``or``
* ``and``
* ``not``
* ``in``
* ``==``, ``!=``, ``<``, ``>``,``<=``, ``>=``
(This follows Python exactly). So, for example, the following complex if tag:
{% if a == b or c == d and e %}
...will be interpreted as:
.. code-block:: python
(a == b) or ((c == d) and e)
If you need different precedence, you will need to use nested if tags. Sometimes
that is better for clarity anyway, for the sake of those who do not know the
precedence rules.
{% if athlete_list or coach_list or parent_list or teacher_list %}
.. templatetag:: ifchanged
@ -427,6 +559,9 @@ You cannot check for equality with Python objects such as ``True`` or
``False``. If you need to test if something is true or false, use the ``if``
tag instead.
.. versionadded:: 1.2
An alternative to the ``ifequal`` tag is to use the :ttag:`if` tag and the ``==`` operator.
.. templatetag:: ifnotequal
ifnotequal
@ -434,6 +569,9 @@ ifnotequal
Just like ``ifequal``, except it tests that the two arguments are not equal.
.. versionadded:: 1.2
An alternative to the ``ifnotequal`` tag is to use the :ttag:`if` tag and the ``!=`` operator.
.. templatetag:: include
include

View File

@ -42,6 +42,18 @@ changes that developers must be aware of:
* All of the CSRF has moved from contrib to core (with backwards compatible
imports in the old locations, which are deprecated).
<<<<<<< HEAD:docs/releases/1.2.txt
=======
:ttag:`if` tag changes
----------------------
Due to new features in the :ttag:`if` template tag, it no longer accepts 'and',
'or' and 'not' as valid **variable** names. Previously that worked in some
cases even though these strings were normally treated as keywords. Now, the
keyword status is always enforced, and template code like ``{% if not %}`` or
``{% if and %}`` will throw a TemplateSyntaxError.
>>>>>>> master:docs/releases/1.2.txt
``LazyObject``
--------------
@ -67,6 +79,7 @@ changes:
__members__ = property(lambda self: self.__dir__())
<<<<<<< HEAD:docs/releases/1.2.txt
Specifying databases
--------------------
@ -208,6 +221,8 @@ connection, you should be able to upgrade by renaming
database specific conversions, then you will need to provide an
implementation ``get_db_prep_*`` that uses the ``connection``
argument to resolve database-specific values.
=======
>>>>>>> master:docs/releases/1.2.txt
.. _deprecated-features-1.2:
@ -338,6 +353,7 @@ replaces the deprecated user message API and allows you to temporarily store
messages in one request and retrieve them for display in a subsequent request
(usually the next one).
<<<<<<< HEAD:docs/releases/1.2.txt
Support for multiple databases
------------------------------
@ -346,3 +362,38 @@ Django 1.2 adds the ability to use :ref:`more than one database
issued at a specific database with the `using()` method on
querysets; individual objects can be saved to a specific database
by providing a ``using`` argument when you save the instance.
=======
'Smart' if tag
--------------
The :ttag:`if` tag has been upgraded to be much more powerful. First, support
for comparison operators has been added. No longer will you have to type:
.. code-block:: html+django
{% ifnotequal a b %}
...
{% endifnotequal %}
...as you can now do:
.. code-block:: html+django
{% if a != b %}
...
{% endif %}
The operators supported are ``==``, ``!=``, ``<``, ``>``, ``<=``, ``>=`` and
``in``, all of which work like the Python operators, in addition to ``and``,
``or`` and ``not`` which were already supported.
Also, filters may now be used in the ``if`` expression. For example:
.. code-block:: html+django
<div
{% if user.email|lower == message.recipient|lower %}
class="highlight"
{% endif %}
>{{ message }}</div>
>>>>>>> master:docs/releases/1.2.txt

View File

@ -202,28 +202,51 @@ Methods
:meth:`~django.contrib.auth.models.User.set_unusable_password()` has
been called for this user.
.. method:: models.User.get_group_permissions()
.. method:: models.User.get_group_permissions(obj=None)
Returns a list of permission strings that the user has, through his/her
groups.
.. method:: models.User.get_all_permissions()
.. versionadded:: 1.2
If ``obj`` is passed in, only returns the group permissions for
this specific object.
.. method:: models.User.get_all_permissions(obj=None)
Returns a list of permission strings that the user has, both through
group and user permissions.
.. method:: models.User.has_perm(perm)
.. versionadded:: 1.2
If ``obj`` is passed in, only returns the permissions for this
specific object.
.. method:: models.User.has_perm(perm, obj=None)
Returns ``True`` if the user has the specified permission, where perm is
in the format ``"<app label>.<permission codename>"``.
If the user is inactive, this method will always return ``False``.
.. method:: models.User.has_perms(perm_list)
.. versionadded:: 1.2
If ``obj`` is passed in, this method won't check for a permission for
the model, but for this specific object.
.. method:: models.User.has_perms(perm_list, obj=None)
Returns ``True`` if the user has each of the specified permissions,
where each perm is in the format
``"<app label>.<permission codename>"``. If the user is inactive,
this method will always return ``False``.
<<<<<<< HEAD:docs/topics/auth.txt
=======
.. versionadded:: 1.2
If ``obj`` is passed in, this method won't check for permissions for
the model, but for the specific object.
>>>>>>> master:docs/topics/auth.txt
.. method:: models.User.has_module_perms(package_name)
@ -1521,3 +1544,24 @@ A full authorization implementation can be found in
the ``auth_permission`` table most of the time.
.. _django/contrib/auth/backends.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/backends.py
Handling object permissions
---------------------------
Django's permission framework has a foundation for object permissions, though
there is no implementation for it in the core. That means that checking for
object permissions will always return ``False`` or an empty list (depending on
the check performed).
To enable object permissions in your own
:ref:`authentication backend <ref-authentication-backends>` you'll just have
to allow passing an ``obj`` parameter to the permission methods and set the
``supports_objects_permissions`` class attribute to ``True``.
A nonexistent ``supports_objects_permissions`` will raise a hidden
``PendingDeprecationWarning`` if used in Django 1.2. In Django 1.3, this
warning will be upgraded to a ``DeprecationWarning``, which will be displayed
loudly. Additionally ``supports_objects_permissions`` will be set to ``False``.
Django 1.4 will assume that every backend supports object permissions and
won't check for the existence of ``supports_objects_permissions``, which
means not supporting ``obj`` as a parameter will raise a ``TypeError``.

View File

@ -187,8 +187,8 @@ tags:
<li>{{ athlete.name }}</li>
{% endfor %}
</ul>
:ttag:`if` and :ttag:`else`
:ttag:`if` and ``else``
Evaluates a variable, and if that variable is "true" the contents of the
block are displayed::
@ -200,20 +200,15 @@ tags:
In the above, if ``athlete_list`` is not empty, the number of athletes
will be displayed by the ``{{ athlete_list|length }}`` variable.
:ttag:`ifequal` and :ttag:`ifnotequal`
Display some contents if two arguments are or are not equal. For example::
{% ifequal athlete.name coach.name %}
...
{% endifequal %}
You can also use filters and various operators in the ``if`` tag::
Or::
{% if athlete_list|length > 1 %}
Team: {% for athlete in athlete_list %} ... {% endfor %}
{% else %}
Athlete: {{ athlete_list.0.name }}
{% endif %}
{% ifnotequal athlete.name "Joe" %}
...
{% endifnotequal %}
:ttag:`block` and :ttag:`extends`
Set up `template inheritance`_ (see below), a powerful way
of cutting down on "boilerplate" in templates.

View File

@ -610,6 +610,12 @@ class AdminViewStringPrimaryKeyTest(TestCase):
def tearDown(self):
self.client.logout()
def test_get_history_view(self):
"Retrieving the history for the object using urlencoded form of primary key should work"
response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/%s/history/' % quote(self.pk))
self.assertContains(response, escape(self.pk))
self.failUnlessEqual(response.status_code, 200)
def test_get_change_view(self):
"Retrieving the object using urlencoded form of primary key should work"
response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/%s/' % quote(self.pk))

View File

@ -1,78 +0,0 @@
try:
set
except NameError:
from sets import Set as set # Python 2.3 fallback
__test__ = {'API_TESTS': """
>>> from django.contrib.auth.models import User, Group, Permission, AnonymousUser
>>> from django.contrib.contenttypes.models import ContentType
# No Permissions assigned yet, should return False except for superuser
>>> user = User.objects.create_user('test', 'test@example.com', 'test')
>>> user.has_perm("auth.test")
False
>>> user.is_staff=True
>>> user.save()
>>> user.has_perm("auth.test")
False
>>> user.is_superuser=True
>>> user.save()
>>> user.has_perm("auth.test")
True
>>> user.is_staff = False
>>> user.is_superuser = False
>>> user.save()
>>> user.has_perm("auth.test")
False
>>> content_type=ContentType.objects.get_for_model(Group)
>>> perm = Permission.objects.create(name="test", content_type=content_type, codename="test")
>>> user.user_permissions.add(perm)
>>> user.save()
# reloading user to purge the _perm_cache
>>> user = User.objects.get(username="test")
>>> user.get_all_permissions() == set([u'auth.test'])
True
>>> user.get_group_permissions() == set([])
True
>>> user.has_module_perms("Group")
False
>>> user.has_module_perms("auth")
True
>>> perm = Permission.objects.create(name="test2", content_type=content_type, codename="test2")
>>> user.user_permissions.add(perm)
>>> user.save()
>>> perm = Permission.objects.create(name="test3", content_type=content_type, codename="test3")
>>> user.user_permissions.add(perm)
>>> user.save()
>>> user = User.objects.get(username="test")
>>> user.get_all_permissions() == set([u'auth.test2', u'auth.test', u'auth.test3'])
True
>>> user.has_perm('test')
False
>>> user.has_perm('auth.test')
True
>>> user.has_perms(['auth.test2', 'auth.test3'])
True
>>> perm = Permission.objects.create(name="test_group", content_type=content_type, codename="test_group")
>>> group = Group.objects.create(name='test_group')
>>> group.permissions.add(perm)
>>> group.save()
>>> user.groups.add(group)
>>> user = User.objects.get(username="test")
>>> exp = set([u'auth.test2', u'auth.test', u'auth.test3', u'auth.test_group'])
>>> user.get_all_permissions() == exp
True
>>> user.get_group_permissions() == set([u'auth.test_group'])
True
>>> user.has_perms(['auth.test3', 'auth.test_group'])
True
>>> user = AnonymousUser()
>>> user.has_perm('test')
False
>>> user.has_perms(['auth.test2', 'auth.test3'])
False
"""}

View File

@ -1,7 +1,11 @@
# -*- coding: utf-8 -*-
# Unit and doctests for specific database backends.
import unittest
<<<<<<< HEAD:tests/regressiontests/backends/tests.py
from django.db import backend, connection, DEFAULT_DB_ALIAS
=======
from django.db import backend, connection
>>>>>>> master:tests/regressiontests/backends/tests.py
from django.db.backends.signals import connection_created
from django.conf import settings
@ -10,7 +14,11 @@ class Callproc(unittest.TestCase):
def test_dbms_session(self):
# If the backend is Oracle, test that we can call a standard
# stored procedure through our cursor wrapper.
<<<<<<< HEAD:tests/regressiontests/backends/tests.py
if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == 'django.db.backends.oracle':
=======
if settings.DATABASE_ENGINE == 'oracle':
>>>>>>> master:tests/regressiontests/backends/tests.py
convert_unicode = backend.convert_unicode
cursor = connection.cursor()
cursor.callproc(convert_unicode('DBMS_SESSION.SET_IDENTIFIER'),
@ -24,7 +32,11 @@ class LongString(unittest.TestCase):
def test_long_string(self):
# If the backend is Oracle, test that we can save a text longer
# than 4000 chars and read it properly
<<<<<<< HEAD:tests/regressiontests/backends/tests.py
if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == 'django.db.backends.oracle':
=======
if settings.DATABASE_ENGINE == 'oracle':
>>>>>>> master:tests/regressiontests/backends/tests.py
c = connection.cursor()
c.execute('CREATE TABLE ltext ("TEXT" NCLOB)')
long_str = ''.join([unicode(x) for x in xrange(4000)])

View File

@ -0,0 +1,46 @@
import unittest
from django.template.smartif import IfParser, Literal
class SmartIfTests(unittest.TestCase):
def assertCalcEqual(self, expected, tokens):
self.assertEqual(expected, IfParser(tokens).parse().eval({}))
# We only test things here that are difficult to test elsewhere
# Many other tests are found in the main tests for builtin template tags
# Test parsing via the printed parse tree
def test_not(self):
var = IfParser(["not", False]).parse()
self.assertEqual("(not (literal False))", repr(var))
self.assert_(var.eval({}))
self.assertFalse(IfParser(["not", True]).parse().eval({}))
def test_or(self):
var = IfParser([True, "or", False]).parse()
self.assertEqual("(or (literal True) (literal False))", repr(var))
self.assert_(var.eval({}))
def test_in(self):
list_ = [1,2,3]
self.assertCalcEqual(True, [1, 'in', list_])
self.assertCalcEqual(False, [1, 'in', None])
self.assertCalcEqual(False, [None, 'in', list_])
def test_precedence(self):
# (False and False) or True == True <- we want this one, like Python
# False and (False or True) == False
self.assertCalcEqual(True, [False, 'and', False, 'or', True])
# True or (False and False) == True <- we want this one, like Python
# (True or False) and False == False
self.assertCalcEqual(True, [True, 'or', False, 'and', False])
# (1 or 1) == 2 -> False
# 1 or (1 == 2) -> True <- we want this one
self.assertCalcEqual(True, [1, 'or', 1, '==', 2])
self.assertCalcEqual(True, [True, '==', True, 'or', True, '==', False])
self.assertEqual("(or (and (== (literal 1) (literal 2)) (literal 3)) (literal 4))",
repr(IfParser([1, '==', 2, 'and', 3, 'or', 4]).parse()))

View File

@ -24,6 +24,7 @@ from context import context_tests
from custom import custom_filters
from parser import filter_parsing, variable_parsing
from unicode import unicode_tests
from smartif import *
try:
from loaders import *
@ -534,6 +535,27 @@ class Templates(unittest.TestCase):
'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"),
'if-tag03': ("{% if foo %}yes{% else %}no{% endif %}", {}, "no"),
# Filters
'if-tag-filter01': ("{% if foo|length == 5 %}yes{% else %}no{% endif %}", {'foo': 'abcde'}, "yes"),
'if-tag-filter02': ("{% if foo|upper == 'ABC' %}yes{% else %}no{% endif %}", {}, "no"),
# Equality
'if-tag-eq01': ("{% if foo == bar %}yes{% else %}no{% endif %}", {}, "yes"),
'if-tag-eq02': ("{% if foo == bar %}yes{% else %}no{% endif %}", {'foo': 1}, "no"),
'if-tag-eq03': ("{% if foo == bar %}yes{% else %}no{% endif %}", {'foo': 1, 'bar': 1}, "yes"),
'if-tag-eq04': ("{% if foo == bar %}yes{% else %}no{% endif %}", {'foo': 1, 'bar': 2}, "no"),
'if-tag-eq05': ("{% if foo == '' %}yes{% else %}no{% endif %}", {}, "no"),
# Comparison
'if-tag-gt-01': ("{% if 2 > 1 %}yes{% else %}no{% endif %}", {}, "yes"),
'if-tag-gt-02': ("{% if 1 > 1 %}yes{% else %}no{% endif %}", {}, "no"),
'if-tag-gte-01': ("{% if 1 >= 1 %}yes{% else %}no{% endif %}", {}, "yes"),
'if-tag-gte-02': ("{% if 1 >= 2 %}yes{% else %}no{% endif %}", {}, "no"),
'if-tag-lt-01': ("{% if 1 < 2 %}yes{% else %}no{% endif %}", {}, "yes"),
'if-tag-lt-02': ("{% if 1 < 1 %}yes{% else %}no{% endif %}", {}, "no"),
'if-tag-lte-01': ("{% if 1 <= 1 %}yes{% else %}no{% endif %}", {}, "yes"),
'if-tag-lte-02': ("{% if 2 <= 1 %}yes{% else %}no{% endif %}", {}, "no"),
# AND
'if-tag-and01': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
'if-tag-and02': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
@ -554,14 +576,13 @@ class Templates(unittest.TestCase):
'if-tag-or07': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True}, 'yes'),
'if-tag-or08': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': True}, 'yes'),
# TODO: multiple ORs
# multiple ORs
'if-tag-or09': ("{% if foo or bar or baz %}yes{% else %}no{% endif %}", {'baz': True}, 'yes'),
# NOT
'if-tag-not01': ("{% if not foo %}no{% else %}yes{% endif %}", {'foo': True}, 'yes'),
'if-tag-not02': ("{% if not %}yes{% else %}no{% endif %}", {'foo': True}, 'no'),
'if-tag-not03': ("{% if not %}yes{% else %}no{% endif %}", {'not': True}, 'yes'),
'if-tag-not04': ("{% if not not %}no{% else %}yes{% endif %}", {'not': True}, 'yes'),
'if-tag-not05': ("{% if not not %}no{% else %}yes{% endif %}", {}, 'no'),
'if-tag-not02': ("{% if not not foo %}no{% else %}yes{% endif %}", {'foo': True}, 'no'),
# not03 to not05 removed, now TemplateSyntaxErrors
'if-tag-not06': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {}, 'no'),
'if-tag-not07': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
@ -599,12 +620,21 @@ class Templates(unittest.TestCase):
'if-tag-not34': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
'if-tag-not35': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),
# AND and OR raises a TemplateSyntaxError
'if-tag-error01': ("{% if foo or bar and baz %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, template.TemplateSyntaxError),
# Various syntax errors
'if-tag-error01': ("{% if %}yes{% endif %}", {}, template.TemplateSyntaxError),
'if-tag-error02': ("{% if foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
'if-tag-error03': ("{% if foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
'if-tag-error04': ("{% if not foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
'if-tag-error05': ("{% if not foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
'if-tag-error06': ("{% if abc def %}yes{% endif %}", {}, template.TemplateSyntaxError),
'if-tag-error07': ("{% if not %}yes{% endif %}", {}, template.TemplateSyntaxError),
'if-tag-error08': ("{% if and %}yes{% endif %}", {}, template.TemplateSyntaxError),
'if-tag-error09': ("{% if or %}yes{% endif %}", {}, template.TemplateSyntaxError),
'if-tag-error10': ("{% if == %}yes{% endif %}", {}, template.TemplateSyntaxError),
'if-tag-error11': ("{% if 1 == %}yes{% endif %}", {}, template.TemplateSyntaxError),
'if-tag-error12': ("{% if a not b %}yes{% endif %}", {}, template.TemplateSyntaxError),
# Additional, more precise parsing tests are in SmartIfTests
### IFCHANGED TAG #########################################################
'ifchanged01': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', {'num': (1,2,3)}, '123'),