Merge pull request #388 from gregmuellegger/django1.6fixes

Fixes for Django 1.6
This commit is contained in:
Daniel Greenfeld 2013-12-01 15:30:24 -08:00
commit 09fcceef13
6 changed files with 62 additions and 21 deletions

View file

@ -6,6 +6,7 @@ from copy import deepcopy
from django.contrib.auth import authenticate
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
import django
import django.forms
import django.forms.models
import django.forms.extras.widgets
@ -27,7 +28,13 @@ def _copy_attributes(original, new_widget, attributes):
for attr in attributes:
original_value = getattr(original, attr)
original_value = deepcopy(original_value)
setattr(new_widget, attr, original_value)
# Don't set the attribute if it is a property. In that case we can be
# sure that the widget class is taking care of the calculation for that
# property.
old_value_on_new_widget = getattr(new_widget.__class__, attr, None)
if not isinstance(old_value_on_new_widget, property):
setattr(new_widget, attr, original_value)
def _create_widget(widget_class, copy_attributes=(), init_arguments=()):
@ -182,6 +189,33 @@ _django_field_to_floppyform_widget = {
}
def allow_floppify_widget_for_field(field):
'''
We only allow to replace a widget with the floppyform counterpart if the
original, by django determined widget is still in place. We don't want to
override custom widgets that a user specified.
'''
# There is a special case for IntegerFields (and all subclasses) that
# replaces the default TextInput with a NumberInput, if localization is
# turned off. That applies for Django 1.6 upwards.
# See the relevant source code in django:
# https://github.com/django/django/blob/1.6/django/forms/fields.py#L225
if django.VERSION >= (1, 6):
if isinstance(field, django.forms.IntegerField) and not field.localize:
if field.widget.__class__ is django.forms.NumberInput:
return True
# We can check if the widget was replaced by comparing the class of the
# specified widget with the default widget that is specified on the field
# class.
if field.widget.__class__ is field.__class__.widget:
return True
# At that point we are assuming that the user replaced the original widget
# with a custom one. So we don't allow to overwrite it.
return False
def floppify_widget(widget, field=None):
'''
Get an instance of django.forms.widgets.Widget and return a new widget
@ -203,10 +237,7 @@ def floppify_widget(widget, field=None):
create_widget = _django_field_to_floppyform_widget.get(
field.__class__)
if create_widget is not None:
# check if the default widget was replaced by a different one, in
# that case we cannot create the field specific floppyforms
# widget.
if field.widget.__class__ is field.__class__.widget:
if allow_floppify_widget_for_field(field):
return create_widget(widget)
create_widget = _django_to_floppyforms_widget.get(widget.__class__)
if create_widget is not None:

View file

@ -2,8 +2,8 @@ from django.db import models
from django.test import TestCase
from django.views.generic import View
from .. import views
from ..types import ModelAdmin2, immutable_admin_factory
from ..views import AdminView
from ..core import Admin2
@ -48,7 +48,7 @@ class ModelAdminTest(TestCase):
def setUp(self):
class MyModelAdmin(ModelAdmin2):
my_view = AdminView(r'^$', View)
my_view = views.AdminView(r'^$', views.ModelListView)
self.model_admin = MyModelAdmin

View file

@ -1,19 +1,19 @@
from django.test import TestCase
from django.views.generic import View
from ..views import AdminView
from .. import views
class AdminViewTest(TestCase):
def setUp(self):
self.admin_view = AdminView(r'^$', View, name='admin-view')
self.admin_view = views.AdminView(r'^$', views.ModelListView, name='admin-view')
def test_url(self):
self.assertEquals(self.admin_view.url, r'^$')
def test_view(self):
self.assertEquals(self.admin_view.view, View)
self.assertEquals(self.admin_view.view, views.ModelListView)
def test_name(self):
self.assertEquals(self.admin_view.name, 'admin-view')

View file

@ -4,6 +4,7 @@ from __future__ import division, absolute_import, unicode_literals
from collections import namedtuple
import logging
import os
import sys
from django.core.urlresolvers import reverse
from django.conf.urls import patterns, url
@ -210,16 +211,25 @@ class ModelAdmin2(with_metaclass(ModelAdminBase2)):
def get_urls(self):
pattern_list = []
for view in self.views:
view.model_admin = self
get_kwargs = getattr(self, "get_%s_kwargs" % view.name, None)
for admin_view in self.views:
admin_view.model_admin = self
get_kwargs = getattr(self, "get_%s_kwargs" % admin_view.name, None)
if not get_kwargs:
get_kwargs = view.get_view_kwargs
get_kwargs = admin_view.get_view_kwargs
try:
view_instance = admin_view.view.as_view(**get_kwargs())
except Exception as e:
trace = sys.exc_info()[2]
new_exception = TypeError(
'Cannot instantiate admin view "{}.{}". '
'The error that got raised was: {}'.format(
self.__class__.__name__, admin_view.name, e))
raise new_exception, None, trace
pattern_list.append(
url(
regex=view.url,
view=view.view.as_view(**get_kwargs()),
name=self.get_prefixed_view_name(view.name)
regex=admin_view.url,
view=view_instance,
name=self.get_prefixed_view_name(admin_view.name)
)
)
return patterns('', *pattern_list)

View file

@ -29,10 +29,6 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.example.settings")
sys.path.insert(0, os.path.abspath('../../'))
sys.path.insert(0, os.path.abspath('../'))
from example.example import settings
from django.core.management import setup_environ
setup_environ(settings)
# For intersphinx
ext_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "_ext"))
sys.path.append(ext_path)

View file

@ -1,3 +1,7 @@
# make sure that everything is setup for tests. Django 1.6 doesn't necessarily
# load the urls.py before the tests are run.
import example.urls
from test_apiviews import *
from test_builtin_api_resources import *
from test_permissions import *