python/django/wagtail/puput/hallo/non-responsive_images_under_Bootstrap3.rant - python

I am part editor and part developer and not utterly advanced at either career. But I am carrying out only a small-scale project. I'm thinking that in the blog that I recently added to my Django site (as yet only on the development server), with Wagtail and Puput, I might want to upload, say, two ~50KB images per week for five years, after which I'll be doing something else. There will never be a huge number of readers or a need for vast storage. Those being the circumstances, I specifically want to know if what I'm doing to overcome the problems that I encountered with uploaded images not resizing to small screens in the Puput blog, non-responsive design, looks feasible. Or, did I make some stupid mistake and, say, just use the Puput/Wagtail editor incorrectly?
When you click into the "body" textbox in the Puput editor to insert an image, it's quite simple. You just browse for your file, give the image a name, and select whether you want full-width or aligned on the left or right. And upon doing that your image will be uploaded into your previously established "media" folder and the database will simply be updated to contain the location of your image in the "media" folder. The <img> tag in your text body will be given an ID attribute which is a link to the database entry.
Two troubling things then happen: (1) when you go into the browser's Responsive Design Mode the image is bigger than the small screen, no responsiveness; and, you actually don't now have an image stored in your media folder, you have three--- the original is in a subdirectory called "original_images" and there are two images in an "images" subdirectory. The two additional images may not have exactly the same pixel dimensions as the original, depending on your choice of full-width or not, the aspect ratio of the images perhaps, etc.
So this is rather intolerable, unless of course you can tell me what mistake I may have made. Otherwise, here's what I have done to get past this, and again, my question is would this work out in practice or do you have a better idea. I found this post on github, and in particular the comment by jerel concerning an insert_editor_js and wagtail_hooks.py hook. This overcomes the richtext limitations of standard hallo and permits opening a second editor window in which you can see and enter HTML.
But Wagtail has this Whitelister class that only permits certain attributes to be used with certain HTML tags. So the Wagtail people also have a hook for changing that, which is explained here. Here's my version of the wagtail_hooks.py file:
from wagtail.wagtailcore import hooks
from wagtail.wagtailcore.whitelist import attribute_rule, check_url, allow_without_attributes
from django.utils.html import format_html
# This one is from the esteemable jerel.
#hooks.register('insert_editor_js')
def enable_source():
return format_html(
"""
<script>
registerHalloPlugin('hallohtml');
</script>
"""
)
# This is modified from the Wagtail docs example.
#hooks.register('construct_whitelister_element_rules')
def whitelister_element_rules():
return {
'blockquote': allow_without_attributes,
'a': attribute_rule({'href': check_url, 'target': True}),
'img': attribute_rule({'src': True, 'width': True, 'height': True, 'alt': True, 'style': True}),
'p': attribute_rule({'style': True, 'class': True}),
}
Note especially that for the img tag I have put 'src': True in place of 'src': check_url, which is the default (check_url is a function that would reject a data URI, as I discuss below). Other changes important to me are the inclusion of 'target': True for the a tag and also the 'style': True additions.
Puput natively uses Bootstrap3 which is "mobile first", or some such rallying cry. So to bring about responsiveness for images with Bootstap3 in Puput I had to do what I have had to do before, which is, in the img tag, to either set the attribute width="100%" or to do it with style="width:100%;" (which I could do thanks only to the hallohtml plugin).
So now, here comes the problem: I found that that only works if you remove the extra attributes that Puput or Wagtail gives to the img tag (otherwise your changes will be deleted). Here's what the img tag looks like straight from the Puput editor: <img data-embedtype="image" data-id="9" data-format="fullwidth" data-alt="junk" class="richtext-image full-width" src="/home/mike/myproject/public_html/djangoprojectdir/public/media/images/imagename.width-800.png" alt="junk" height="1115" width="596">.
So if I throw away height and change width to 100% that doesn't work unless I also remove data-format, etc. If I do all of that, I have responsive design... but, the database is no longer involved. I have thereby instead just manually linked the image file to the img tag.
So my solution to bring about responsive-design behavior kills the database linkage between pages and image files. I must say, I don't miss the absurd presence of three images in the media folder for every one that I upload. And I don't much like having to guard and backup without failure, for years, not only a database but also a folder of many images.
So the second thing that I tried--- it too seems to work--- is the use of data URIs with Base64, which I read about here. It seems feasible because I won't be using many dense images. I made use of the hallohtml editor to cut and paste the Base64 encoding of the image to src in the img tag. It's not utterly unwieldy.
So again, the question is, do I have to do something like this (and is what I propose reasonable)... or, am I somehow just in the dark concerning how I should upload images or configure Puput and Wagtail for responsive design (I followed all of their instructions and everything else works)?

The root of the issue is that you need a good way of applying the style width: 100% to all rich text images. Ideally you'd do that with a global CSS rule, which would avoid the need to hand-edit the HTML of the body field.
Puput doesn't seem to provide an "official" way to customise the base templates at present, although there are a few pointers here: https://github.com/APSL/puput/issues/63. The following steps should hopefully do the trick:
Create a blog app inside your project (run ./manage.py startapp blog, and add 'blog' to the INSTALLED_APPS list in your settings making sure it's above puput) - or if your project already has a suitable app, follow the remaining steps with that app name in place of blog;
Create a blog/templates/puput/ directory
Create a file blog/templates/puput/base.html containing:
{% extends "puput/base.html" %}
{% block content %}
<style>
img.full-width {
width: 100%;
}
</style>
{{ block.super }}
{% endblock %}

Related

In Django, how can I load images based on screen size?

Apologies for not having any specific broken code here. I already know that what I would try won't work from a different question here, and I have a vague idea of something that might work but is likely not the best way to do it.
I'm building a website for a photographer, so it's important that I'm loading the best looking photos that the user is capable of seeing. The starting file size for the images is a few MB, but the model uses Pillow to save down-scaled copies. There are times when I want a full-screen image at high resolution, but I want to serve a smaller image if the user is on mobile, for example.
What I would have done was load the images from CSS background-image with media queries, but I understand that I can't use template tags in CSS.
My next guess would be to build two separate versions of each template and have the views render a different template based on the user-agent of the request, but that strikes me as probably not a great solution to put that much trust in the request headers, and the functionality could break as easily as a new browser release. There's a better way, right?
Why not CSS? - In this case, the images are dynamic content. The photographer doesn't know web development and I'm not going to update the site for him every time he adds or removes images or blog posts, etc, so the site is a lite CMS. He can freely add or remove images from galleries, etc. The django view/template then find and serve the images from the query set. Instead of referring to specific images and their specific smaller versions, I'm asking the server to serve whatever images currently belong to a specific queryset in the database, and serve either the smaller or larger versions of the images, and to do so with the explicit goal of not having the user download resolution that they can't see.

detect image errors django template

I pull in image links from several sources so I have a mix images that render and then have problems rendering.
I have many images that return with http error 400, 403 etc.
Am I able to detect this in the django template so that I can render something more suitable than a broken image?
Something like:
{% if ia.image.url %}
<img src="{{media_url}}{{ia.image.url}}" alt="#" class="trimimg1" />
{% else %}
<img src="{% static 'common/app/images/news-default.jpg' %}" alt="#" class="trimimg1" />
{% endif %}
You are able to detect broken links in the django template or also before in the view. However, depending on the type of project you are doing, I would not recommend this - at least not without caching.
Let's talk about the theory first and then about a possible alternative solution:
If you only are using images that you are hosting yourself, serving the images to your clients should be no problem as long as the files on your server exist. You can easily check that by retrieving the path of the image and checking if the file exists (provided, that you may access the file and did not separate completely the media server, then you have to handle this as if it is external hosting).
If I read your question carefully, you seem to link to images hosted on external servers though. It is possible to handle a few but probably not all problems with those images on the server side. Either you do this while storing the image URL already, or you do a periodical check in the background. If you really want to check every time you are sending the image URL to the user, you might create a heavy load on the server just for checking. In this case, I recommend to rely heavily on caching and to cache the return value of the method for checking the availability of the URL for a certain time.
That being said, you could do the following in your template:
In theory, you could create your own custom filter "urlexists" (See https://docs.djangoproject.com/en/1.11/howto/custom-template-tags/ ). This filter would retrieve the URL you want to check. It would try to retrieve the file from the remote server (Download just the headers, see https://stackoverflow.com/a/16778473/1331407 on how to do that) and return True, if the URL exists and False otherwise.
Usage:
{% if ia.image.url|urlexists %}
<img src="{{media_url}}{{ia.image.url}}" alt="#" class="trimimg1" />
{% else %}
<img src="{% static 'common/app/images/news-default.jpg' %}" alt="#" class="trimimg1" />
{% endif %}
As I said, it is a solution but I do not recommend this.
Alternative solution
I would rather recommend to handle the HTTP error on the client side using JavaScript. That script can be as easy as an and a JavaScript function that then replaces the image src with a placeholder image that you provide.
Examples on how to do that are provided here: Detecting an image 404 in javascript
You could even do one better: If you want to know about the inaccessible image, you could modify the URL of the placeholder image to a view that retrieves the image URL and logs it somewhere in your database so that you can remove the URL from your image database later. The view would always just return the placeholder image.
Why do I recommend handling this error on the client side?
Simple answer: Server load and access rights. Checking all URLs constantly will create a huge server load and traffic, both of which you might not want to handle all the time. In addition, your server might not be allowed to access certain images that you would filter out - or vice versa. Some servers allow you only to access their images after you loaded a page containing those images beforehand (I learned that trying to scrape movie posters from websites for my personal BluRay library index). An image that your server might have scraped from somewhere and that you are able to access might thus not be accessible for your clients webbrowser. Thus he might still see broken images. If you check the availability on your clients browser, he will never see the broken image, since his or her browser is always replacing those with a placeholder. If you include my suggestion above, you would even crowdsource image availability checking, reducing server load on your and foreign servers.

Gallery in Photologue can have only one Photo

after I put the photologue on the server, I have no issue with uploading photos.
the issue is when I am creating a Gallery from the admin site, I can choose only one photo to be attached to the Gallery. even if I selected many photos, one of them will be linked to the Gallery only.
The only way to add photos to a gallery is by adding them manually to photologue_gallery_photos table in the database :(
anyone kows how to solve it?
I had exactly the same problem. I suspected some problem with django-sortedm2m package. To associate photo to gallery, it was using SortedManyToMany() from sortedm2m package. For some reason, the admin widget associated with this package did not function well. (I tried Firefox, Chrome and safari browser).
I actually did not care for the order of photos getting uploaded to Gallery, so I simply replaced that function call with Django's ManyToManyField(). Also, I noticed that SortedManyToMany('Photo') was called with constant string Photo. Instead it should be called with SortedManyToMany(Photo) to identify Photo class. Although it did not resolve my problem entirely. So I used default ManyToMany field and it is showing all the photos from Gallery.
I guess your problem is solved by now, but just in case.. I had the same problem. Looking around in the logs, I found it was caused by me not having consolidated the static files from sortedm2m with the rest of my static files (hence the widget was not working properly).
Make sure sortedm2m is in INSTALLED_APPS in addition to photologue; merely duplicating any sortedm2m templates alone will not suffice.
Installation & configuration — django-photologue 3.6 documentation

Google App Engine(Python) - site fragments - composite view

Is there a way to build three or four parts of a site (three or four html templates) and then render some of them or all of them together in GAE python? I know I can load and render one specific html django template but I want to build templates for different parts of the site in different files and then compose them together depending on the situation.
A good example would be that I want pretty much the same menu, header, footer in most of my web application pages but I want to switch a specific part of the content.
So I would like to have one file and template that deals with lets say classes and another that deals with students, so the general look of the site (main.html) stays the same but the way I display and handle the information about students or classes is completely different. I basically want to plant a bunch of page specific html into a generic template.
Thanks for any help on this. :)
I am not sure what is the correct technical term for what I'm looking for(I tried searching). => I think they call it composite view or site fragments in the Zend framework.
You should use template inheritance in Django. Have a look at this tutorial for a start.
EDIT The official Django Book section on Template Inheritance also demonstrates how different 'fragments' e.g. a footer, or a nav bar, may be stored in different template files and brought together via inclusion and inheritance.
This site shows how one template can inherit from another, as when a site section template extends a basic layout template, with the code, for example,
{% extends "base.html" %}
It also shows how using template inclusion one may, for example, add different pieces to a larger template like pieces in a puzzle. For example, a navigation fragment may be added to a layout file with the phrase
{% include "nav.html" %}
As noted in the comments by #Nick Johnson: extends is more compact and can make the use of multiple file fragments unnecessary. Only include as last resort, if extends fails you.
EDIT See also my answer to a question on "How to cut large HTML file into multiple HTML files"

Including Flash content inline in a custom Weblog?

I'm trying to think of a way to place Flash content into a blog post so that it appears inline between paragraphs. I'm writing a custom weblog application in Django (still learning) and I'll be using SWFObject for the embedding.
The blog is for me only so the back-end isn't too fancy. I'm simply using Django's built in admin interface. No TinyMCE rich text editor (like Wordpress), rather I've implemented Markdown.
I'd like to add Flash content into the body of a post, between paragraphs, in a way that is not coupled to any third party script. Meaning, I would prefer not to include javascript within the body of the blog post as it introduces a dependency on SWFObject. For example, I could quite easily add the following to an entry via the back-end to embed a SWF inline:
Paragraph one...
<script type="text/javascript">
swfobject.embedSWF("/path/to/flash.swf", "myContent", "200", "200", "9.0.0");
</script>
<div id="myContent"></div>
Paragraph two...
As you can see this is quite wordy and a lot to remember but it also refers to SWFObject directly. This WILL work, however I would prefer to write it in a "cleaner" more abstract way. What I was thinking of doing is creating my own parser which would translate a custom string into the above just before rendering a template.
[#SWF swf="/path/to/flash.swf" w="200" h="200" ver="9.0.0"]
I'm wondering if anyone has encountered this issue. I'd love to know how you solved it.
You might want to look into OEmbed, specifically the django-oembed project.

Categories

Resources