Skip to content

Commit

Permalink
[soc2009/multidb] Merged up to trunk r11804.
Browse files Browse the repository at this point in the history
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/multidb@11805 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
alex committed Dec 9, 2009
1 parent 2e900d4 commit bee835f
Show file tree
Hide file tree
Showing 53 changed files with 2,286 additions and 76 deletions.
3 changes: 2 additions & 1 deletion AUTHORS
Expand Up @@ -60,6 +60,7 @@ answer newbie questions, and generally made Django that much better:
Ned Batchelder <http://www.nedbatchelder.com/>
batiste@dosimple.ch
Batman
Chris Beaven <http://smileychris.tactful.co.nz/>
Brian Beck <http://blog.brianbeck.com/>
Shannon -jj Behrens <http://jjinux.blogspot.com/>
Esdras Beleza <linux@esdrasbeleza.com>
Expand Down Expand Up @@ -299,6 +300,7 @@ answer newbie questions, and generally made Django that much better:
Jason McBrayer <http://www.carcosa.net/jason/>
Kevin McConnell <kevin.mcconnell@gmail.com>
mccutchen@gmail.com
Tobias McNulty <http://www.caktusgroup.com/blog>
Christian Metts
michael.mcewan@gmail.com
michal@plovarna.cz
Expand Down Expand Up @@ -391,7 +393,6 @@ answer newbie questions, and generally made Django that much better:
Jozko Skrablin <jozko.skrablin@gmail.com>
Ben Slavin <benjamin.slavin@gmail.com>
sloonz <simon.lipp@insa-lyon.fr>
SmileyChris <smileychris@gmail.com>
Warren Smith <warren@wandrsmith.net>
smurf@smurf.noris.de
Vsevolod Solovyov
Expand Down
1 change: 1 addition & 0 deletions TODO
Expand Up @@ -7,6 +7,7 @@ Required for v1.2
* Finalize the sql.Query internals
* Clean up the use of db.backend.query_class()
* Verify it still works with GeoDjango
* Modify the admin interface to support multiple databases (doh).

Optional for v1.2
~~~~~~~~~~~~~~~~~
Expand Down
2 changes: 1 addition & 1 deletion django/conf/__init__.py
Expand Up @@ -127,7 +127,7 @@ def __getattr__(self, name):
return getattr(self.default_settings, name)

def __dir__(self):
return dir(self) + dir(self.default_settings)
return self.__dict__.keys() + dir(self.default_settings)

# For Python < 2.6:
__members__ = property(lambda self: self.__dir__())
Expand Down
12 changes: 12 additions & 0 deletions django/conf/global_settings.py
Expand Up @@ -175,6 +175,7 @@
'django.core.context_processors.i18n',
'django.core.context_processors.media',
# 'django.core.context_processors.request',
'django.contrib.messages.context_processors.messages',
)

# Output to use in template system for invalid (e.g. misspelled) variables.
Expand Down Expand Up @@ -311,6 +312,7 @@
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# 'django.middleware.http.ConditionalGetMiddleware',
# 'django.middleware.gzip.GZipMiddleware',
)
Expand Down Expand Up @@ -396,6 +398,16 @@
CSRF_COOKIE_NAME = 'csrftoken'
CSRF_COOKIE_DOMAIN = None

############
# MESSAGES #
############

# Class to use as messges backend
MESSAGE_STORAGE = 'django.contrib.messages.storage.user_messages.LegacyFallbackStorage'

# Default values of MESSAGE_LEVEL and MESSAGE_TAGS are defined within
# django.contrib.messages to avoid imports in this settings file.

###########
# TESTING #
###########
Expand Down
2 changes: 2 additions & 0 deletions django/conf/project_template/settings.py
Expand Up @@ -66,6 +66,7 @@
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)

ROOT_URLCONF = '{{ project_name }}.urls'
Expand All @@ -81,4 +82,5 @@
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
)
5 changes: 3 additions & 2 deletions django/contrib/admin/options.py
Expand Up @@ -6,6 +6,7 @@
from django.contrib.admin import widgets
from django.contrib.admin import helpers
from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_ngettext, model_format_dict
from django.contrib import messages
from django.views.decorators.csrf import csrf_protect
from django.core.exceptions import PermissionDenied
from django.db import models, transaction
Expand Down Expand Up @@ -541,9 +542,9 @@ def construct_change_message(self, request, form, formsets):
def message_user(self, request, message):
"""
Send a message to the user. The default implementation
posts a message using the auth Message object.
posts a message using the django.contrib.messages backend.
"""
request.user.message_set.create(message=message)
messages.info(request, message)

def save_form(self, request, form, change):
"""
Expand Down
2 changes: 1 addition & 1 deletion django/contrib/admin/sites.py
Expand Up @@ -452,7 +452,7 @@ def root(self, request, url):
import warnings
warnings.warn(
"AdminSite.root() is deprecated; use include(admin.site.urls) instead.",
PendingDeprecationWarning
DeprecationWarning
)

#
Expand Down
3 changes: 2 additions & 1 deletion django/contrib/admin/views/template.py
Expand Up @@ -6,6 +6,7 @@
from django.conf import settings
from django.utils.importlib import import_module
from django.utils.translation import ugettext_lazy as _
from django.contrib import messages


def template_validator(request):
Expand All @@ -23,7 +24,7 @@ def template_validator(request):
form = TemplateValidatorForm(settings_modules, site_list,
data=request.POST)
if form.is_valid():
request.user.message_set.create(message='The template is valid.')
messages.info(request, 'The template is valid.')
else:
form = TemplateValidatorForm(settings_modules, site_list)
return render_to_response('admin/template_validator.html', {
Expand Down
8 changes: 5 additions & 3 deletions django/contrib/auth/admin.py
Expand Up @@ -3,6 +3,7 @@
from django.contrib import admin
from django.contrib.auth.forms import UserCreationForm, UserChangeForm, AdminPasswordChangeForm
from django.contrib.auth.models import User, Group
from django.contrib import messages
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseRedirect, Http404
from django.shortcuts import render_to_response, get_object_or_404
Expand Down Expand Up @@ -67,12 +68,13 @@ def add_view(self, request):
msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': 'user', 'obj': new_user}
self.log_addition(request, new_user)
if "_addanother" in request.POST:
request.user.message_set.create(message=msg)
messages.success(request, msg)
return HttpResponseRedirect(request.path)
elif '_popup' in request.REQUEST:
return self.response_add(request, new_user)
else:
request.user.message_set.create(message=msg + ' ' + ugettext("You may edit it again below."))
messages.success(request, msg + ' ' +
ugettext("You may edit it again below."))
return HttpResponseRedirect('../%s/' % new_user.id)
else:
form = self.add_form()
Expand Down Expand Up @@ -104,7 +106,7 @@ def user_change_password(self, request, id):
if form.is_valid():
new_user = form.save()
msg = ugettext('Password changed successfully.')
request.user.message_set.create(message=msg)
messages.success(request, msg)
return HttpResponseRedirect('..')
else:
form = self.change_password_form(user)
Expand Down
10 changes: 9 additions & 1 deletion django/contrib/auth/models.py
Expand Up @@ -288,6 +288,14 @@ def get_profile(self):
raise SiteProfileNotAvailable
return self._profile_cache

def _get_message_set(self):
import warnings
warnings.warn('The user messaging API is deprecated. Please update'
' your code to use the new messages framework.',
category=PendingDeprecationWarning)
return self._message_set
message_set = property(_get_message_set)

class Message(models.Model):
"""
The message system is a lightweight way to queue messages for given
Expand All @@ -297,7 +305,7 @@ class Message(models.Model):
actions. For example, "The poll Foo was created successfully." is a
message.
"""
user = models.ForeignKey(User)
user = models.ForeignKey(User, related_name='_message_set')
message = models.TextField(_('message'))

def __unicode__(self):
Expand Down
5 changes: 4 additions & 1 deletion django/contrib/contenttypes/generic.py
Expand Up @@ -317,10 +317,13 @@ def get_queryset(self):
from django.contrib.contenttypes.models import ContentType
if self.instance is None or self.instance.pk is None:
return self.model._default_manager.none()
return self.model._default_manager.filter(**{
qs = self.model._default_manager.filter(**{
self.ct_field.name: ContentType.objects.get_for_model(self.instance),
self.ct_fk_field.name: self.instance.pk,
})
if not qs.ordered:
qs = qs.order_by(self.model._meta.pk.name)
return qs

def save_new(self, form, commit=True):
# Avoid a circular import.
Expand Down
2 changes: 2 additions & 0 deletions django/contrib/messages/__init__.py
@@ -0,0 +1,2 @@
from api import *
from constants import *
84 changes: 84 additions & 0 deletions django/contrib/messages/api.py
@@ -0,0 +1,84 @@
from django.contrib.messages import constants
from django.utils.functional import lazy, memoize

__all__ = (
'add_message', 'get_messages',
'debug', 'info', 'success', 'warning', 'error',
)


class MessageFailure(Exception):
pass


def add_message(request, level, message, extra_tags='', fail_silently=False):
"""
Attempts to add a message to the request using the 'messages' app, falling
back to the user's message_set if MessageMiddleware hasn't been enabled.
"""
if hasattr(request, '_messages'):
return request._messages.add(level, message, extra_tags)
if hasattr(request, 'user') and request.user.is_authenticated():
return request.user.message_set.create(message=message)
if not fail_silently:
raise MessageFailure('Without the django.contrib.messages '
'middleware, messages can only be added to '
'authenticated users.')


def get_messages(request):
"""
Returns the message storage on the request if it exists, otherwise returns
user.message_set.all() as the old auth context processor did.
"""
if hasattr(request, '_messages'):
return request._messages

def get_user():
if hasattr(request, 'user'):
return request.user
else:
from django.contrib.auth.models import AnonymousUser
return AnonymousUser()

return lazy(memoize(get_user().get_and_delete_messages, {}, 0), list)()


def debug(request, message, extra_tags='', fail_silently=False):
"""
Adds a message with the ``DEBUG`` level.
"""
add_message(request, constants.DEBUG, message, extra_tags=extra_tags,
fail_silently=fail_silently)


def info(request, message, extra_tags='', fail_silently=False):
"""
Adds a message with the ``INFO`` level.
"""
add_message(request, constants.INFO, message, extra_tags=extra_tags,
fail_silently=fail_silently)


def success(request, message, extra_tags='', fail_silently=False):
"""
Adds a message with the ``SUCCESS`` level.
"""
add_message(request, constants.SUCCESS, message, extra_tags=extra_tags,
fail_silently=fail_silently)


def warning(request, message, extra_tags='', fail_silently=False):
"""
Adds a message with the ``WARNING`` level.
"""
add_message(request, constants.WARNING, message, extra_tags=extra_tags,
fail_silently=fail_silently)


def error(request, message, extra_tags='', fail_silently=False):
"""
Adds a message with the ``ERROR`` level.
"""
add_message(request, constants.ERROR, message, extra_tags=extra_tags,
fail_silently=fail_silently)
13 changes: 13 additions & 0 deletions django/contrib/messages/constants.py
@@ -0,0 +1,13 @@
DEBUG = 10
INFO = 20
SUCCESS = 25
WARNING = 30
ERROR = 40

DEFAULT_TAGS = {
DEBUG: 'debug',
INFO: 'info',
SUCCESS: 'success',
WARNING: 'warning',
ERROR: 'error',
}
8 changes: 8 additions & 0 deletions django/contrib/messages/context_processors.py
@@ -0,0 +1,8 @@
from django.contrib.messages.api import get_messages


def messages(request):
"""
Returns a lazy 'messages' context variable.
"""
return {'messages': get_messages(request)}
26 changes: 26 additions & 0 deletions django/contrib/messages/middleware.py
@@ -0,0 +1,26 @@
from django.conf import settings
from django.contrib.messages.storage import default_storage


class MessageMiddleware(object):
"""
Middleware that handles temporary messages.
"""

def process_request(self, request):
request._messages = default_storage(request)

def process_response(self, request, response):
"""
Updates the storage backend (i.e., saves the messages).
If not all messages could not be stored and ``DEBUG`` is ``True``, a
``ValueError`` is raised.
"""
# A higher middleware layer may return a request which does not contain
# messages storage, so make no assumption that it will be there.
if hasattr(request, '_messages'):
unstored_messages = request._messages.update(response)
if unstored_messages and settings.DEBUG:
raise ValueError('Not all temporary messages could be stored.')
return response
1 change: 1 addition & 0 deletions django/contrib/messages/models.py
@@ -0,0 +1 @@
# Models module required so tests are discovered.
31 changes: 31 additions & 0 deletions django/contrib/messages/storage/__init__.py
@@ -0,0 +1,31 @@
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.utils.importlib import import_module


def get_storage(import_path):
"""
Imports the message storage class described by import_path, where
import_path is the full Python path to the class.
"""
try:
dot = import_path.rindex('.')
except ValueError:
raise ImproperlyConfigured("%s isn't a Python path." % import_path)
module, classname = import_path[:dot], import_path[dot + 1:]
try:
mod = import_module(module)
except ImportError, e:
raise ImproperlyConfigured('Error importing module %s: "%s"' %
(module, e))
try:
return getattr(mod, classname)
except AttributeError:
raise ImproperlyConfigured('Module "%s" does not define a "%s" '
'class.' % (module, classname))


# Callable with the same interface as the storage classes i.e. accepts a
# 'request' object. It is wrapped in a lambda to stop 'settings' being used at
# the module level
default_storage = lambda request: get_storage(settings.MESSAGE_STORAGE)(request)

0 comments on commit bee835f

Please sign in to comment.