Hi Simon,

Thanks for the pointer, but I don't think that helps.

The fields are already declared using the existing fields / readonly_fields
attributes on the ExampleAdmin class - and this is what get_fields /
get_readonly_fields return. The system check fails because the fields
declared don't exist on the ExampleAdmin class nor on the model. Here's the
relevant lines from contrib/admin/checks.py:

    def _check_readonly_fields_item(self, cls, model, field_name, label):
        if callable(field_name):
            return []
        elif hasattr(cls, field_name):
            return []
        elif hasattr(model, field_name):
            return []
        else:
            try:
                model._meta.get_field(field_name)
            except FieldDoesNotExist:
                return [
                    checks.Error(
                        "The value of '%s' is not a callable, an attribute
of '%s', or an attribute of '%s.%s'." % (
                            label, cls.__name__, model._meta.app_label,
model._meta.object_name
                        ),
                        hint=None,
                        obj=cls,
                        id='admin.E035',
                    )
                ]
            else:
                return []

If the thumbnail fields were defined as methods on the ExampleAdmin, all
would be fine e.g.:

class ExampleAdmin(models.ModelAdmin):
   fields = ['image', 'image_thumbnail']

   def image_thumbnail(self, obj):
       return "<img src="%s"/>" % obj.image.url

That's fine, but if there's lots of image fields (with a variety of names)
spread over several ModelAdmin classes, then you end up with a lot of
duplicated code. The normal solution then is to refactor the code. And
that's where I get stuck - I can't see (short of metaclass programming!)
how to inject the methods into the class such that the system check
succeeds.

I therefore suspect that the check is actually borked, and it should be
checking hasattr(instance, field_name) rather than hasattr(cls, field_name)

So I see three possibilities, in order of probability:

   1. I'm being dumb, and there's an easy way to dynamically create
   attributes on a ModelAdmin that passes system checks
   2. The system check is incorrect, and should allow dynamically created
   attributes on ModelAdmin when validating fields
   3. Metaclass programming is really the right way to do this


Malcolm

On 9 September 2015 at 02:23, Simon Charette <charett...@gmail.com> wrote:

> Hi Malcom!
>
> I would suggest you have a look at the ModelAdmin.get_fields()
> <https://docs.djangoproject.com/en/1.8/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_fields>
> method to append your thumbnail read-only field names.
>
> As documented
> <https://docs.djangoproject.com/en/1.8/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fields>,
> just make sure you also override ModelAdmin.get_readonly_fields()
> <https://docs.djangoproject.com/en/1.8/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_readonly_fields>
> to return them as well.
>
> Cheers,
> Simon
>
> Le mardi 8 septembre 2015 13:31:47 UTC-4, Malcolm Box a écrit :
>>
>> Hi,
>>
>> I'm trying to add a dynamic method to a ModelAdmin so that I can have
>> automatically generated thumbnail fields for any image by simply adding
>> '<fieldname>_thumbnail' to the field definitions - which saves a lot of
>> code when there's a load of admin classes with image fields that need
>> thumbnails.
>>
>> e.g.
>>
>> class ThumbnailMixin(object):
>>     def getattr(self, name):
>>          if name.endswith('_thumbnail'):
>>               # ... generate appropriate thumbnail method and return
>>               return thumbnail_function
>>          else:
>>              raise AttributeError
>>
>> class ExampleAdmin(models.ModelAdmin, ThumbnailMixin):
>>      fields = ['image_thumbnail', 'image', ...]
>>
>> This worked fine in Django 1.6/1.7, but it's now failing in 1.8 with a
>> SystemCheckError (admin.E035 / admin.E108). If I silence the error, the
>> admin actually works fine, but that feels icky.
>>
>> The check fails because it checks for the field being on the ExampleAdmin
>> class, not on an instance - whereas the admin always uses an instance, so
>> it works.
>>
>> What's the "right" way to do this in the 1.8 world - I've considered a
>> custom metaclass, but that feels like overkill for a simple task like this.
>> Should this even work, and if so is it a bug in the check framework?
>>
>> Cheers,
>>
>> Malcolm
>>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "Django users" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/django-users/lsDP5oUWOsw/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> django-users+unsubscr...@googlegroups.com.
> To post to this group, send email to django-users@googlegroups.com.
> Visit this group at http://groups.google.com/group/django-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/05249551-899b-4a64-b416-216c9f81d950%40googlegroups.com
> <https://groups.google.com/d/msgid/django-users/05249551-899b-4a64-b416-216c9f81d950%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>
> For more options, visit https://groups.google.com/d/optout.
>



-- 
Malcolm Box
CTO & Co-Founder, Tellybug  http://tellybug.com
malc...@tellybug.com   +44 7766 990123    @malcolmbox

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/CAF3R4sWpmtdTQvjSrUasp57iMMVF56uFgYuhAzx_RTQioPGTnQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to