⬆️ ⬇️

We finish the admin with a chainsaw. Part I - Thumbnails

I'll put in my five kopecks about how cool and flexible the Django admin panel is. Many stubbornly do not want to understand that this is not a toy, but a completely production-quality application, which is just silly not to use if there is such an opportunity.



And the point here is not at all that the developers are so well done that they have provided so many customization possibilities to cover all the needs of users - this is certainly not the case. Nevertheless, at the disposal of the developer there is always another powerful means of customizing any web application at all. This tool is Javascript. The developers of Django, perfectly aware of this, provide us with all the means to connect custom JS / CSS, which, in fact, in general, removes any restrictions on what we want to blind from our admin panel.



Of course, there is nothing in it and most experienced developers do this, I will only try to describe a couple of life-style recipes, on the basis of which you can, having connected a little imagination, solve almost any issues related to customizing Django admin panel. More specifically, we’ll do what we’ll do with the actual thumbnails for our ImageFields, connect TinyMCE, and teach it to insert images using Django-admin itself as a file manager to select images.



So suppose that we want to take the usual flatpages and supplement them with the ability to create pages using a WYSIWYG editor, including uploading and inserting images (what are the pages without images?)

')

To begin with, we will create a simple FlatPicture model and teach it to make thumbnails. To do this, use the library PIL (there is nowhere more standard). Using it, creating thumbnails is not easy, but very simple. We will put all the logic of working with thumbnails in a separate file (yes, all 10 stupid simple lines)



  # utils.py

 import os
 from PIL import Image

 def get_thumbnail_url (image_url, size = 150):
     thumbs_part = 'thumbs_' + str (size)
     image_url_parts = image_url.rsplit ('/', 1)
     return image_url_parts [0] + '/' + thumbs_part + '/' + image_url_parts [1]

 def get_thumbnail_path (image_path, size = 150):
     thumbs_dir = 'thumbs_' + str (size)
     dirname, filename = os.path.split (image_path)
     dirname = os.path.join (dirname, thumbs_dir)
     if not os.path.exists (dirname):
         os.mkdir (dirname, 0755)
     return os.path.join (dirname, filename)

 def create_thumbnail (image_path, size = 150):
     thumb_path = get_thumbnail_path (image_path, size)
     delete_thumbnail (image_path, size)
     img = Image.open (image_path)
     img.thumbnail ((size, size), Image.ANTIALIAS)
     img.save (thumb_path)

 def delete_thumbnail (image_path, size = 150):
     thumb_path = get_thumbnail_path (image_path, size)
     if os.path.exists (thumb_path):
         os.remove (thumb_path) 




These functions will be very useful to us in order to tie the thumbnails to our model:



  from django.db.models.signals import post_save, pre_delete
 from utils import *

 class FlatPicture (models.Model):
     picture = models. ImageField (upload_to = 'uploads / flatpictures', max_length = 250)
     description = models.CharField (max_length = 250, blank = True)

     def get_thumbnail_html (self):
         html = '<a class="image-picker" href="%s"> <img src = "% s" alt = "% s" /> </a>'
         return html% (self.picture.url, get_thumbnail_url (self.picture.url), self.description)
     get_thumbnail_html.short_description = _ ('thumbnail')
     get_thumbnail_html.allow_tags = True

 def post_save_handler (sender, ** kwargs):
     create_thumbnail (kwargs ['instance']. picture.path)
 post_save.connect (post_save_handler, sender = FlatPicture)

 def pre_delete_handler (sender, ** kwargs):
     delete_thumbnail (kwargs ['instance']. picture.path)
 pre_delete.connect (pre_delete_handler, sender = FlatPicture) 




This is how cheap and angry we now automatically create and delete thumbnails of the size we need. Although you only need to take a look at the editing form and the list of pictures, as it becomes obvious that something is clearly not enough ...







... Of course, both in the list and on the form, I would like to see the thumbnail of the current image, and not guess what its name is. Thus, we smoothly approach the topic of this post. No, we do not need to redefine a dozen templates and write new widgets. Javascript comes to the rescue.



For clarity, I use jQuery, I hook it up (along with TinyMCE) again stupid simple - by redefining the 'admin / base_site.html' template. It is quite convenient to connect these libraries once “globally”, if they are used throughout your admin panel:



  {% extends "admin / base.html"%}
 {% load i18n%}

 {% block title%} {{title}} |  Admin example.com {% endblock%}

 {% block branding%}
 <h1 id = "site-name"> example.com admin panel </ h1>
 {% endblock%}

 {% block nav-global%} {% endblock%}

 {% block extrastyle%}
 <script type = "text / javascript" src = "/ media / lib / jquery-1.3.2.min.js"> </ script>
 <script type = "text / javascript" src = "/ media / lib / tiny_mce / jquery.tinymce.js"> </ script>
 <script type = "text / javascript" src = "/ media / js / admin / base.js"> </ script>
 {% endblock%} 




With the task of displaying the thumbnail in the list, the 'get_thumbnail_html' method will help us to cope, which we have already prudently added to the model. And in order to display the thumb on the form, we will need the following JS, which can later be connected to any form for which we need the following functionality:



  $ (). ready (function () {
   $ ('a [target = _blank]'). each (function () {
       if ($ (this) .html (). indexOf ('uploads /') == 0) {
           var path = $ (this) .attr ('href');
           path = path.substring (0, path.lastIndexOf ('/'))
                   + '/ thumbs_150'
                   + path.substring (path.lastIndexOf ('/'));
           $ (this) .parent (). after ('<a style = "margin-left: 10em" href = "'
                   + $ (this) .attr ('href') + '"target =" _ blank "> <img src ="'
                   + path + '"alt =" image "/> </a>');
       }
   });
 }); 




Now, with a slight movement of the hand, we add both of these elements to 'admin.py' ...



  class FlatPictureAdmin (admin.ModelAdmin):
     class Media:
         js = ['js / admin / display_thumbs.js']
     list_display = ['get_thumbnail_html', '__unicode__', 'description']
     list_display_links = ['__unicode__']
 admin.site.register (FlatPicture, FlatPictureAdmin) 




... and admire the result:







That's all for now. In the next series, how to make TinyMCE use this list page as a picture file manager.

Source: https://habr.com/ru/post/78256/



All Articles