Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The property thumbnail is not defined on <ThroughTable> - manytomany inline #138

Closed
allofthesepeople opened this issue Jun 20, 2012 · 5 comments

Comments

@allofthesepeople
Copy link

Hi, not sure if this is a bug, a problem with my code, or if it's just not a workable case.

I'm trying to get image thumbnails to appear in the admin beside a manytomany inline using a through table (which adds additional info). It’s giving me an Exception The property thumbnail is not defined on PostImage. on /imagekit/admin.py in __call__, line 31.

I’ve looked at both issue #46 & #53 and think this should work?

class ImageInline(admin.TabularInline):
    model           = Post.images.through
    raw_id_fields   = ('image',)
    admin_thumbnail = AdminThumbnail(image_field = 'thumbnail')
    readonly_fields = ('admin_thumbnail',)
    fields          = ('admin_thumbnail','image')

class PostAdmin(admin.ModelAdmin):
    inlines = [ImageInline]

If I change the image_field to the actual model (Image) I can return the image object title, similar happens if I change to Image.thumbnail but never the image…

@matthewwithanm
Copy link
Owner

All AdminThumbnail is going to do is look up the property you specify ("thumbnail") on the host model (Post.images.through, which I assume is PostImage) and show that in the admin. Apparently, PostImage doesn't define a thumbnail property; Image does.

As it stands currently, there's no way to tell AdminThumbnail to get the image from another model, but maybe we could add this in the future. Perhaps something like this:

class ImageInline(admin.TabularInline):
    model = Post.images.through
    admin_thumbnail = AdminThumbnail(image_field='image.thumbnail')

(I'm assuming here that "image" is the name of the fk property on PostImage that points to Image.)

@allofthesepeople
Copy link
Author

Thanks for the quick reply Matthew! You’re right, the fk is image, and I didn't think this case would be possible.

I’ve had a play about and image.thumbnail also doesn’t work, though will keep trying & will pass back any possible solutions.

@matthewwithanm
Copy link
Owner

Sorry, I know that "image.thumbnail" doesn't work. I was saying that perhaps we could add that.

Currently, this can't be done with AdminThumbnail. (Well, you can create an ugly hack—like adding a "thumbnail" getter on the PostImage that proxies to the Image—but you could also just write your own method on the admin.)

Hope that helps clarify.

allofthesepeople added a commit to allofthesepeople/django-imagekit that referenced this issue Jun 20, 2012
Accepts `image_fk` in order to allow thumbnail to be displayed within inline forms.
@allofthesepeople
Copy link
Author

Cheers Matthew, sent through a pull request with two simple hacks: one tests for a dot in the image_field string, the other accepts a further image_fk argument.

Option 1

Test for dot notation

admin.py

class AdminThumbnail(object):
...
    def __call__(self, obj):

        if self.image_field.find('.') == -1:
             thumbnail = getattr(obj, self.image_field, None)
        else:
             thumbnail = getattr(getattr(obj, self.image_field.split('.')[0]), self.image_field.split('.')[1], None)
...

Option 2

Pass additional argument

admin.py

class AdminThumbnail(object):
    def __init__(self, image_field, template=None, image_fk=None):
        self.image_fk = image_fk
...
    def __call__(self, obj):
        if self.image_fk == None:
            thumbnail = getattr(obj, self.image_field, None)
        else:
            thumbnail = getattr(getattr(obj, self.image_fk), self.image_field, None)
...

example_app/admin.py example

Where Post has a ManytoMany with a Image model, ImageInline provides the details.

class ImageInline(admin.TabularInline):
    model = Post.images.through
    raw_id_fields = ("image",)
    admin_thumbnail = AdminThumbnail(image_field = "thumbnail", image_fk="image")
    readonly_fields = ('admin_thumbnail',)
    fields = ('admin_thumbnail','image')

Personally, the second seems a little easier to follow, but I’m fairly new to python can’t vouch for the coding standard.

@matthewwithanm
Copy link
Owner

Hey @roj27. Sorry I didn't get back to you on this for so long. 548fb65 should take care of it for you. It allows you to pass a callable as the image_field argument. The callable will be passed the model instance, so you can do something like this:

admin_thumbnail = AdminThumbnail(image_field=lambda o: o.image.thumbnail)

Or, of course, you can use a real function:

def get_thumbnail(model):
    return model.image.thumbnail

class ImageInline(admin.TabularInline):
    model = Post.images.through
    admin_thumbnail = AdminThumbnail(image_field=get_thumbnail)

The reason I like this approach is that it allows you to access objects that are related more distantly than by just a foreign key.

We can still add the dotted-path syntax in the future as a shortcut, but the implementation would have to support distant relationships as well—in other words, strings with more than one dot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants