Ticket #9976: 9976.r17313.diff
File 9976.r17313.diff, 10.9 KB (added by , 13 years ago) |
---|
-
django/contrib/admin/options.py
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 3a0ad74..c23d4b3 100644
a b class BaseModelAdmin(object): 72 72 formfield_overrides = {} 73 73 readonly_fields = () 74 74 ordering = None 75 generic_fields = () 75 76 76 77 def __init__(self): 77 78 overrides = FORMFIELD_FOR_DBFIELD_DEFAULTS.copy() … … class BaseModelAdmin(object): 122 123 123 124 return formfield 124 125 126 # For generic foreign keys marked as generic_fields we use a special widget 127 elif db_field.name in [f.fk_field for f 128 in self.model._meta.virtual_fields 129 if f.name in self.generic_fields]: 130 for gfk in self.model._meta.virtual_fields: 131 if gfk.fk_field == db_field.name: 132 break 133 return db_field.formfield( 134 label=capfirst(gfk.name.replace('_', ' ')), 135 widget=widgets.GenericForeignKeyRawIdWidget( 136 gfk.ct_field, 137 self.admin_site._registry.keys())) 138 125 139 # If we've got overrides for the formfield defined, use 'em. **kwargs 126 140 # passed to formfield_for_dbfield override the defaults. 127 141 for klass in db_field.__class__.mro(): -
django/contrib/admin/validation.py
diff --git a/django/contrib/admin/validation.py b/django/contrib/admin/validation.py index 733f89d..dce9f63 100644
a b def validate(cls, model): 171 171 raise ImproperlyConfigured("'%s.%s' should be a boolean." 172 172 % (cls.__name__, attr)) 173 173 174 if hasattr(cls, 'generic_fields'): 175 check_isseq(cls, 'generic_fields', cls.generic_fields) 176 for i, field in enumerate(cls.generic_fields): 177 if field not in [f.name for f in model._meta.virtual_fields]: 178 raise ImproperlyConfigured( 179 "Item number %d in %s.generic_fields " 180 "is not a GenericForeignKey on %s" 181 % (i, cls.__name__, model.__name__)) 174 182 175 183 # inlines = [] 176 184 if hasattr(cls, 'inlines'): -
django/contrib/admin/widgets.py
diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index 29958b2..fc39b2f 100644
a b Form Widget classes specific to the Django admin site. 5 5 import copy 6 6 from django import forms 7 7 from django.contrib.admin.templatetags.admin_static import static 8 from django.contrib.contenttypes.models import ContentType 8 9 from django.core.urlresolvers import reverse 9 10 from django.forms.widgets import RadioFieldRenderer 10 11 from django.forms.util import flatatt … … class AdminCommaSeparatedIntegerFieldWidget(forms.TextInput): 315 316 if attrs is not None: 316 317 final_attrs.update(attrs) 317 318 super(AdminCommaSeparatedIntegerFieldWidget, self).__init__(attrs=final_attrs) 319 320 class GenericForeignKeyRawIdWidget(ForeignKeyRawIdWidget): 321 def __init__(self, ct_field, cts=[], attrs=None): 322 self.ct_field = ct_field 323 self.cts = cts 324 forms.TextInput.__init__(self, attrs) 325 326 def render(self, name, value, attrs=None): 327 if attrs is None: 328 attrs = {} 329 related_url = '../../../' 330 params = self.url_parameters() 331 if params: 332 url = '?' + '&'.join(['%s=%s' % (k, v) for k, v in params.iteritems()]) 333 else: 334 url = '' 335 if 'class' not in attrs: 336 attrs['class'] = 'vForeignKeyRawIdAdminField' 337 output = [ 338 forms.TextInput.render(self, name, value, attrs), 339 "<a href=\"%(related)s%(url)s\" class=\"related-lookup\" " 340 "id=\"lookup_id_%(name)s\" onclick=\"return " 341 "showGenericRelatedObjectLookupPopup(document.getElementById(" 342 "'id_%(ct_field)s'), this, '%(related)s%(url)s');\"> " 343 % {'related': related_url, 'url': url, 'name': name, 344 'ct_field': self.ct_field}, 345 "<img src=\"%s\" width=\"16\" height=\"16\" alt=\"%s\" /></a>" 346 % (static('admin/img/selector-search.gif'), _('Lookup'))] 347 if value: 348 output.append(self.label_for_value(value)) 349 350 content_types = """ 351 <script type="text/javascript"> 352 var content_types = new Array(); 353 %s 354 </script>""" % ('\n'.join(["content_types[%s] = '%s/%s/';" 355 % (ContentType.objects.get_for_model(ct).id, 356 ct._meta.app_label, 357 ct._meta.object_name.lower()) 358 for ct in self.cts])) 359 return mark_safe(u''.join(output) + content_types) 360 361 def url_parameters(self): 362 return {} -
tests/regressiontests/admin_widgets/models.py
diff --git a/tests/regressiontests/admin_widgets/models.py b/tests/regressiontests/admin_widgets/models.py index c4489e0..8e16641 100644
a b 1 1 from django.db import models 2 2 from django.contrib.auth.models import User 3 3 from django.contrib.contenttypes import generic 4 from django.contrib.contenttypes.models import ContentType 4 5 5 6 class MyFileField(models.FileField): 6 7 pass … … class Advisor(models.Model): 99 100 """ 100 101 name = models.CharField(max_length=20) 101 102 companies = models.ManyToManyField(Company) 103 104 class Image(models.Model): 105 image = models.ImageField(upload_to='images') 106 description = models.CharField(max_length=200) 107 108 content_type = models.ForeignKey(ContentType, related_name='admin_widgets_image_set') 109 object_id = models.PositiveIntegerField() 110 object = generic.GenericForeignKey('content_type', 'object_id') 111 112 def __unicode__(self): 113 return u"%s - %s" % (self.image.name, self.description[:100]) 114 No newline at end of file -
tests/regressiontests/admin_widgets/tests.py
diff --git a/tests/regressiontests/admin_widgets/tests.py b/tests/regressiontests/admin_widgets/tests.py index e28df32..96e607c 100644
a b from django.conf import settings 8 8 from django.contrib import admin 9 9 from django.contrib.admin import widgets 10 10 from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase 11 from django.contrib.admin.widgets import GenericForeignKeyRawIdWidget 12 from django.contrib.contenttypes.models import ContentType 11 13 from django.core.files.storage import default_storage 12 14 from django.core.files.uploadedfile import SimpleUploadedFile 13 15 from django.db.models import DateField … … class AdminForeignKeyWidgetChangeList(DjangoTestCase): 150 152 self.assertTrue('%s/auth/user/add/' % self.admin_root in response.content) 151 153 152 154 155 class AdminGenericForeignKeyRawIdWidget(DjangoTestCase): 156 fixtures = ["admin-widgets-users.xml"] 157 admin_root = '/widget_admin' 158 159 def test_gfk_raw_id_field(self): 160 self.assertEqual( 161 GenericForeignKeyRawIdWidget(models.Image._meta.virtual_fields[0].ct_field).render('test', '', {}), 162 """<input type="text" name="test" class="vForeignKeyRawIdAdminField" /><a href="../../../" class="related-lookup" id="lookup_id_test" onclick="return showGenericRelatedObjectLookupPopup(document.getElementById('id_content_type'), this, '../../../');"> <img src="/static/admin/img/selector-search.gif" width="16" height="16" alt="Lookup" /></a> 163 <script type="text/javascript"> 164 var content_types = new Array(); 165 166 </script>""" 167 ) 168 169 cts = [ct.model_class() for ct in ContentType.objects.filter(pk__lt=3)] 170 self.assertEqual( 171 GenericForeignKeyRawIdWidget(models.Image._meta.virtual_fields[0].ct_field, cts).render('test', '', {}), 172 """<input type="text" name="test" class="vForeignKeyRawIdAdminField" /><a href="../../../" class="related-lookup" id="lookup_id_test" onclick="return showGenericRelatedObjectLookupPopup(document.getElementById('id_content_type'), this, '../../../');"> <img src="/static/admin/img/selector-search.gif" width="16" height="16" alt="Lookup" /></a> 173 <script type="text/javascript"> 174 var content_types = new Array(); 175 content_types[1] = '%s/%s/'; 176 content_types[2] = '%s/%s/'; 177 </script>""" % (cts[0]._meta.app_label, cts[0]._meta.object_name.lower(), 178 cts[1]._meta.app_label, cts[1]._meta.object_name.lower(),) 179 ) 180 153 181 class AdminForeignKeyRawIdWidget(DjangoTestCase): 154 182 fixtures = ["admin-widgets-users.xml"] 155 183 admin_root = '/widget_admin' -
tests/regressiontests/modeladmin/models.py
diff --git a/tests/regressiontests/modeladmin/models.py b/tests/regressiontests/modeladmin/models.py index 33202fa..a9129ec 100644
a b 1 1 # coding: utf-8 2 2 from django.contrib.auth.models import User 3 from django.contrib.contenttypes import generic 4 from django.contrib.contenttypes.models import ContentType 3 5 from django.db import models 4 6 5 7 … … class ValidationTestModel(models.Model): 40 42 41 43 class ValidationTestInlineModel(models.Model): 42 44 parent = models.ForeignKey(ValidationTestModel) 45 46 class Image(models.Model): 47 name = models.CharField(max_length=100) 48 description = models.TextField() 49 50 content_type = models.ForeignKey(ContentType, related_name='modeladmin_image_set') 51 object_id = models.PositiveIntegerField() 52 object = generic.GenericForeignKey('content_type', 'object_id') -
tests/regressiontests/modeladmin/tests.py
diff --git a/tests/regressiontests/modeladmin/tests.py b/tests/regressiontests/modeladmin/tests.py index 9b60945..1f65580 100644
a b from django.forms.widgets import Select 17 17 from django.test import TestCase 18 18 from django.utils import unittest 19 19 20 from .models import Band, Concert, ValidationTestModel, ValidationTestInlineModel 20 from .models import (Band, Concert, Image, ValidationTestModel, 21 ValidationTestInlineModel) 21 22 22 23 23 24 class MockRequest(object): … … class ValidationTests(unittest.TestCase): 1494 1495 inlines = [ValidationTestInline] 1495 1496 1496 1497 validate(ValidationTestModelAdmin, ValidationTestModel) 1498 1499 def test_generic_fields_validation(self): 1500 class GenericModelAdmin(ModelAdmin): 1501 generic_fields = None 1502 1503 self.assertRaisesRegexp( 1504 ImproperlyConfigured, 1505 "'GenericModelAdmin.generic_fields' must be a list or tuple.", 1506 validate, 1507 GenericModelAdmin, 1508 Image 1509 ) 1510 1511 class GenericModelAdmin(ModelAdmin): 1512 generic_fields = ["abc"] 1513 1514 self.assertRaisesRegexp( 1515 ImproperlyConfigured, 1516 "Item number 0 in GenericModelAdmin.generic_fields is not a GenericForeignKey on Image", 1517 validate, 1518 GenericModelAdmin, 1519 Image 1520 ) 1521 1522 class GenericModelAdmin(ModelAdmin): 1523 generic_fields = ["object"] 1524 1525 validate(GenericModelAdmin, Image)