Now although the blog functions are mostly realized, but the interface is still relatively simple, especially the home page of the article list is almost all text, read more fatigue. Therefore, a title image for each title is not only beautiful, but also allows users to quickly understand the content of the article. In fact, most social networking sites do the same, after all, human nature is lazy, can look at pictures rather than words.

We’ve covered uploading and displaying images in the uploading user profile picture section. The implementation of the title image is similar, except that this chapter takes a step further and zooms in the image to make the page look clean and efficient.

The preparatory work

Like user avatars, the title image is an “asset” of each blog post, so you need to modify the model and create a new field:

article/models.py

class ArticlePost(models.Model):.# Article title graph
    avatar = models.ImageField(upload_to='article/%Y%m%d/', blank=True)...Copy the code

Note that %Y%m%d in the upload address is formatted as the date. For example, if the upload date is February 26, 2019, the title image will be uploaded to the media/ Article /20190226 directory.

Remember data migration.

The title diagram is usually set up when a new article is created, and the new article is uploaded to the database via a form. So the next step is to modify the published form class:

article/forms.py

...
class ArticlePostForm(forms.ModelForm):
    class Meta:. fields = ('title'.'body'.'tags'.'avatar')

Copy the code

Added avatar field, nothing new.

The next step is to modify the view. Since the POST form contains the image file, bind request.FILES to the form class as well, otherwise the image will not save properly:

article/views.py

...
def article_create(request):
    if request.method == "POST":
        Increased the request # FILES
        article_post_form = ArticlePostForm(request.POST, request.FILES)
        
        ...
Copy the code

Good, we’re almost done, now we’re going to do the image processing.

Processing images

Before you write the code, think about what you need to do:

  • Title images do not require too much quality, so you need to reduce the size of the image to improve the speed of page loading.
  • Secondly, it is necessary to standardize the length and width of the picture. I prefer to set the width of the image to be the same so that the title is neat.

The next question is, where should the code go? It seems that you can manipulate images in a Model, form, or View. Here I’m going to write the code into the Model so that whenever you upload images anywhere (including in the background!) , the image will be processed.

Once you think about it, you have to act. Remember the Pillow library, which we installed a long time ago, now it’s time to use it:

article/models.py

...

Remember to import!
from PIL import Image

class ArticlePost(models.Model):.# Code written earlier
    avatar = models.ImageField(upload_to='article/%Y%m%d/', blank=True)
    
    # Process images while saving
    def save(self, *args, **kwargs):
        Call the original save() function
        article = super(ArticlePost, self).save(*args, **kwargs)

        # Fixed width zoom image size
        if self.avatar and not kwargs.get('update_fields'):
            image = Image.open(self.avatar)
            (x, y) = image.size
            new_x = 400
            new_y = int(new_x * (y / x))
            resized_image = image.resize((new_x, new_y), Image.ANTIALIAS)
            resized_image.save(self.avatar.path)

        return article
    
...
Copy the code

** doesn’t have a lot of code, but it has a lot of details that deserve careful scrutiny. ** no hurry, line by line:

  • Save () is a built-in model method that is called every time a Model instance is saved. Rewrite it here and “plug in” the logic for processing images.

  • Super (ArticlePost, self).save(*args, **kwargs) calls the original save() method of the parent class, which saves the field data in the Model to the database. Because the image processing is based on the saved image, this sentence must be executed before the image processing, otherwise you will get an error that the original image will not be found.

  • There are two conditions for an if statement:

    • Post title images are not required. Self. avatar removes posts that do not have title images, and these posts do not require images.

    • A little confusing is this not kwargs.get(‘update_fields’). Remember that save(update_fields=[‘total_views’]) was called in the article_detail() view to count views? Yes, save() is called to exclude the number of statistical views, so that the title graph is not processed every time the user enters the article details page, which affects performance.

      This judgment method is simple, but it results in a tight coupling between the model and the view. Readers can explore more elegant methods in practice, such as setting a parameter to determine which view calls save().

  • Then the Pillow processes the image: Open the original image, get the resolution, set the width of the new image to 400 and scale down the height, and then cover the original image with the new image. Image.ANTIALIAS Smooth filtering is used for zooming.

  • As a final step, the parent class save() returns the result intact.

Perfect!

Templates and Tests

The rest of the job is easier.

Modify the post template so that the form can upload images:

templates/article/create.html

...

<! Remember to add encType! -->
<form . enctype="multipart/form-data">.<! -- Article title map -->
    <div class="form-group">
        <label for="avatar">Headline figure</label>
        <input type="file" class="form-control-file" name="avatar" id="avatar">
    </div>.</form>.Copy the code

Then modify the article list template to show the title diagram.

For aesthetic purposes, the overall structure of the list loop has been slightly altered:

templates/article/list.html

...

<! -- List loop -->
<div class="row mt-2">
    {% for article in articles %}
        <! -- Title image -->
        {% if article.avatar %}
            <div class="col-3">
                <img src="{{ article.avatar.url }}" 
                     alt="avatar" 
                     style="max-width:100%; border-radius: 20px"
                >
            </div>
        {% endif %}

        <div class="col">
            <! - section - >.<! - label - >. .<hr style="width: 100%;"/>
    {% endfor %}
</div>.Copy the code

Then there’s the fun part of testing.

Start the server and open the page of publication:

Select a few images with different resolutions for the title image,

Post a few articles and return to the articles list page:

It looks good.

Take a look at the actual images saved in the Media directory:

Do save to the desired directory, and the bottom left corner shows the width of the image is 400.

Mopping up

Functionality has been implemented, but there is still cleaning up to be done:

  • You need to verify the uploaded image, such as whether the uploaded file is a picture and whether the resolution meets requirements. While this verification isn’t particularly important in personal blog projects, it’s not so important in other projects: Who knows what weird stuff people are Posting?

  • Editing and deleting articles also involves dealing with uploaded images. You can also apply zooming resolution techniques to your avatar, such as cropping it to a square.

    Note: Deleting the Avatar entry from the database simply disconnects the spreadsheet from the image, which is actually still in its original location. To delete the image completely, you still have to code the operating system files.

I’ll leave it to the reader to figure out how to implement these features.

The wheel

Although this article is self-written (Pillow is technically a wheel), as you might have guessed, there is a more intelligent wheel: Django-ImageKit. This library can be directly inherited from the Model field, for example:

article/models.py

# introduction imagekit
from imagekit.models import ProcessedImageField
from imagekit.processors import ResizeToFit

class ArticlePost(models.Model):. avatar = ProcessedImageField( upload_to='article/%Y%m%d',
        processors=[ResizeToFit(width=400)],
        format='JPEG',
        options={'quality': 100},)Copy the code

Fields define the upload location, processing rules, storage format, and image quality, so you don’t need to write any image processing code.

See the official introduction for more usage.

conclusion

In this chapter you learned how to upload and manipulate the title image of your post so that the front page of your blog has a nice look.

It should be pointed out that the servers used by personal blogs are usually not performing well. It is fine to store small images such as thumbnails of articles, but don’t store large image files, otherwise users will be stuck waiting for a few minutes to open your images.

Therefore, it is recommended that you put large size pictures and videos into professional cloud object storage service providers, such as Qiuniuyun and Youpaiyun, etc. It will not cost much money when your storage capacity is very small (less than 10G).


  • If you have any questions please leave a message on Doucet’s personal website and I will reply as soon as possible.
  • Or Email me a private message: [email protected]
  • Project code: Django_blog_tutorial