Ticket #9976: 9976.r17313.diff

File 9976.r17313.diff, 10.9 KB (added by prestontimmons, 4 years ago)

Updated patch to r17313

  • 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): 
    7272    formfield_overrides = {}
    7373    readonly_fields = ()
    7474    ordering = None
     75    generic_fields = ()
    7576
    7677    def __init__(self):
    7778        overrides = FORMFIELD_FOR_DBFIELD_DEFAULTS.copy()
    class BaseModelAdmin(object): 
    122123
    123124            return formfield
    124125
     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
    125139        # If we've got overrides for the formfield defined, use 'em. **kwargs
    126140        # passed to formfield_for_dbfield override the defaults.
    127141        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): 
    171171            raise ImproperlyConfigured("'%s.%s' should be a boolean."
    172172                    % (cls.__name__, attr))
    173173
     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__))
    174182
    175183    # inlines = []
    176184    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. 
    55import copy
    66from django import forms
    77from django.contrib.admin.templatetags.admin_static import static
     8from django.contrib.contenttypes.models import ContentType
    89from django.core.urlresolvers import reverse
    910from django.forms.widgets import RadioFieldRenderer
    1011from django.forms.util import flatatt
    class AdminCommaSeparatedIntegerFieldWidget(forms.TextInput): 
    315316        if attrs is not None:
    316317            final_attrs.update(attrs)
    317318        super(AdminCommaSeparatedIntegerFieldWidget, self).__init__(attrs=final_attrs)
     319
     320class 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">
     352var 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  
    11from django.db import models
    22from django.contrib.auth.models import User
    3 
     3from django.contrib.contenttypes import generic
     4from django.contrib.contenttypes.models import ContentType
    45
    56class MyFileField(models.FileField):
    67    pass
    class Advisor(models.Model): 
    99100    """
    100101    name = models.CharField(max_length=20)
    101102    companies = models.ManyToManyField(Company)
     103
     104class 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 
    88from django.contrib import admin
    99from django.contrib.admin import widgets
    1010from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
     11from django.contrib.admin.widgets import GenericForeignKeyRawIdWidget
     12from django.contrib.contenttypes.models import ContentType
    1113from django.core.files.storage import default_storage
    1214from django.core.files.uploadedfile import SimpleUploadedFile
    1315from django.db.models import DateField
    class AdminForeignKeyWidgetChangeList(DjangoTestCase): 
    150152        self.assertTrue('%s/auth/user/add/' % self.admin_root in response.content)
    151153
    152154
     155class 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">
     164var 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">
     174var content_types = new Array();
     175content_types[1] = '%s/%s/';
     176content_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
    153181class AdminForeignKeyRawIdWidget(DjangoTestCase):
    154182    fixtures = ["admin-widgets-users.xml"]
    155183    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  
    11# coding: utf-8
    22from django.contrib.auth.models import User
     3from django.contrib.contenttypes import generic
     4from django.contrib.contenttypes.models import ContentType
    35from django.db import models
    46
    57
    class ValidationTestModel(models.Model): 
    4042
    4143class ValidationTestInlineModel(models.Model):
    4244    parent = models.ForeignKey(ValidationTestModel)
     45
     46class 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 
    1717from django.test import TestCase
    1818from django.utils import unittest
    1919
    20 from .models import Band, Concert, ValidationTestModel, ValidationTestInlineModel
     20from .models import (Band, Concert, Image, ValidationTestModel,
     21    ValidationTestInlineModel)
    2122
    2223
    2324class MockRequest(object):
    class ValidationTests(unittest.TestCase): 
    14941495            inlines = [ValidationTestInline]
    14951496
    14961497        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)
Back to Top