The dream-seeker characters

The sample code covered in this article has been synchronously updated to the HelloGithub-Team repository

We finished writing the django blog front page view. We wanted the front page to show a list of published blog posts, but it complained: Not published yet! As it says, we haven’t posted anything yet. In this section, we’ll use Django’s built-in Admin background to post our blog posts.

Example Create the admin background administrator account

To access the Django Admin background, you first need to create a super administrator account. We already created a background account in Djangomigrationoperation database, but if you didn’t follow the previous steps, go to the project root directory and run the pipenv run python manage.py createsuperuser command to create one:

> pipenv run python manage.py createsuperuser User name (leave blank to use)'yangxg'): admin email address: [email protected] Password: Password (again): Superuser created successfully.Copy the code

Note:

When you enter a password on the command line, the characters may not be displayed. Do not assume that the keyboard is broken, just enter the password in the normal way.

Register the model in the admin background

To register a few of our own models in the background so that Django Admin knows they exist, it’s as simple as adding the following code to blog\admin.py:

blog/admin.py

from django.contrib import admin
from .models import Post, Category, Tag

admin.site.register(Post)
admin.site.register(Category)
admin.site.register(Tag)
Copy the code

Run development server, visit http://127.0.0.1:8000/admin/, have entered into the django admin backend login page, enter the newly created the password for the administrator account can log on to the backstage.

Now you can see the three models we just registered. Click on the Add button next to Posts and you will see the page for adding Posts, which means adding blog Posts. Then type in some content for the test in the relevant area, and click Save when you’re finished. You can also add a few more articles to see how they look. Note that each article must have a category, and you can select an existing category when adding articles. If you don’t already have a Category in your database, click the + button next to the Category to add a Category.

You might want to add images to the content of your post, but currently you can’t. You’ll see how to insert images into articles in the support Markdown syntax section.

Visit http://127.0.0.1:8000/ home page to see a list of articles you have added, and here is a rendering of my environment:

Customizing admin Background

Using the Admin background, we found the following experience-related issues:

  • Admin background itself of the page elements is already Chinese, but our own blog application, and Post, Category, Tag in the page is displayed in English, and when publishing articles, form fields label is also in English.
  • On the Post list page behind Admin, we only see the title of the article, but we want it to show more detailed information, such as author, post date, modification date, etc.
  • When adding articles, all data should be filled in manually. However, some data should be generated automatically. For example, post time created_time and change time modified_time should be generated automatically when a post is created or modified, not manually. At the same time, our blog is a single blog system, the publisher must be the article author, this should also be automatically set as admin background login account.

While Django’s Admin application is available out of the box, it also offers a wealth of customizations, which is what makes Django attractive. Here, we’ll customize each one as needed.

Chinese blog application

First of all, let’s look at the places that need to be sinicized. Each section of the admin homepage represents an APP. For example, the BLOG section represents the BLOG application, and the default display of the section title is the application name. The application section contains all the models of the application that have been registered in the admin background. We registered Post, Category and Tag before, so these three models are displayed, and the displayed name is the name of the model. As shown below:

The second is the newly added form of the POST page. The label of each Field is converted from the Field name defined in the POST class. For example, if the title Field is defined in the POST model, the label of the corresponding form is the title.

The first is the title of the BLOG section, BLOG. A section represents an application. Obviously, this title is translated from the name of the application.

from django.apps import AppConfig


class BlogConfig(AppConfig):
    name = 'blog'
Copy the code

This is the code generated automatically when we run StartApp to create the blog application. You can see that there is a BlogConfig class that inherits from the AppConfig class, which, by its name, is related to application configuration. We can configure some features of the application by setting the values of some properties in this class. For example, name is used to define the name of the app. It should be the same as the name of the app. Do not change it. To change the app display name in admin background, add verbose_name property.

class BlogConfig(AppConfig):
    name = 'blog'
    verbose_name = 'blog'
Copy the code

In addition, we registered the app in Settings as “blog”. Now we have done some configuration for the app in BlogConfig class, so we should register this class:

INSTALLED_APPS = [
    'django.contrib.admin'.'blog.apps.BlogConfig'.Sign up for the blog app
]
Copy the code

When you log in to the background again, you can see that the title of the BLOG section is displayed as BLOG.

The next step is to make the model registered under the application appear in Chinese. Since the application is configured in apps.py, the configuration related to the model should find the corresponding Model. Some features of the configured Model are defined in the model inner class Meta. For example, for the Post model, it should be displayed as Chinese in the admin background, as follows:

class Post(models.Model):. author = models.ForeignKey(User, on_delete=models.CASCADE)class Meta:
        verbose_name = 'articles'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.title
Copy the code

Verbose_name specifies the name of the model that will appear on admin. Verbose_name_plural specifies the plural form of multiple articles that will appear on admin. In English, if there are multiple Posts, it will be displayed as Posts, which means plural. In Chinese, there is no plural representation, so it is defined as verbose_name.

You can also set Tag and Category:

class Category(models.Model):
    name = models.CharField(max_length=100)
    
    class Meta:
        verbose_name = 'classification'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Tag(models.Model):
    name = models.CharField(max_length=100)
    
    class Meta:
        verbose_name = 'tags'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name
Copy the code

You can see the effect of the Chinese version in admin.

Then change the label of the POST form. The label is converted from the Field name defined in the model, so change it in the Field.

class Post(models.Model):
    title = models.CharField('title', max_length=70)
    body = models.TextField(The 'body')
    created_time = models.DateTimeField('Creation time')
    modified_time = models.DateTimeField('Modification time')
    excerpt = models.CharField('the', max_length=200, blank=True)
    category = models.ForeignKey(Category, verbose_name='classification', on_delete=models.CASCADE)
    tags = models.ManyToManyField(Tag, verbose_name='tags', blank=True)
    author = models.ForeignKey(User, verbose_name='the writer', on_delete=models.CASCADE)
Copy the code

As you can see, we pass each Field a positional argument whose value is the name the Field should display. (If not, Django generates the Field name automatically.) The name of this parameter is also called verbose_name. Most of the field parameter is in the first position, but because ForeignKey and ManyToManyField must pass the first parameter to their associated Model, So for the category and tags fields we use the keyword parameter verbose_name.

The article list shows more detailed information

In the admin post list page, we only see the title of the post, but we want it to display more detailed information. This requires us to customize Admin by adding the following code to admin.py:

blog/admin.py

from django.contrib import admin
from .models import Post, Category, Tag

class PostAdmin(admin.ModelAdmin):
    list_display = ['title'.'created_time'.'modified_time'.'category'.'author']

# Register the new Postadmin as well
admin.site.register(Post, PostAdmin)
admin.site.register(Category)
admin.site.register(Tag)
Copy the code

Refresh the Admin Post list page and you can see that it displays much better.

Simplify the form for adding articles

Next, optimize the unreasonable place of filling in the form data when adding articles. The creation time and modification time of the article should be automatically generated according to the current time, but it is now filled in manually, and the author of the article should be automatically filled in as the background administrator user, so these auto-fill data fields do not need to appear in the form of the new article.

Previously we defined a PostAdmin in blog/admin.py to configure some representation of Post behind Admin. The list_display property controls the fields displayed on the Post list page. There is also a fields property that controls which fields the form displays, which is exactly what we want:

class PostAdmin(admin.ModelAdmin):
    list_display = ['title'.'created_time'.'modified_time'.'category'.'author']
    fields = ['title'.'body'.'excerpt'.'category'.'tags']
Copy the code

The fields defined in fields are the fields that are presented in the form.

The next step is to fill in the creation time, the modification time, and the value of the article author. As mentioned earlier, article authors should be automatically set up as admin users who log in to the background to publish this article. Posting an article is actually an HTTP request. As mentioned earlier, Django wraps the HTTP request in an HttpRequest object and passes it as the first argument to the view function (we don’t see the view for the new article here, If a user logs in to our site, Django will bind the user instance to the request.user property. We can fetch the current requesting user from request.user. Then associate it with the newly created article.

Postadmin inherits from ModelAdmin and has a save_model method that has only one line of code: obj.save(). What it does is save to the database the model instance registered with this Modeladmin association (in this case, Modeladmin association registered with Post). This method takes four parameters: Request, the HTTP request object, and obj, the instance of the associated object. By copying this method, you can associate Request. user with the created Post instance. Then save the Post data to the database:

class PostAdmin(admin.ModelAdmin):
    list_display = ['title'.'created_time'.'modified_time'.'category'.'author']
    fields = ['title'.'body'.'excerpt'.'category'.'tags']

    def save_model(self, request, obj, form, change):
        obj.author = request.user
        super().save_model(request, obj, form, change)
Copy the code

One idea is to duplicate the save_model method and associate the post object with the current time. However, there is a problem with this. Only posts created by admin can associate these times automatically. However, creating articles doesn’t have to be in Admin, but may also be through the command line. This can be done by customizing the Post model.

First, each Field defined in the Model takes a default keyword argument, which means that if the corresponding Field is not set when the Model instance is saved to the database, Django takes the default value specified by default. Save it to the database. Therefore, for the article creation time field, when no value is initially specified, the default should be the current time, so it happens to be specified with the default keyword argument:

from django.utils import timezone

class Post(models.Model):. created_time = models.DateTimeField('Creation time', default=timezone.now)
    ...
Copy the code

Here default can be specified as either a constant value or a callable object. We specify timezone.now so that if created_time is not specified, Django will specify it as the value after the timezone.now call. Timezone. now is a django utility function that returns the current time. Because the functions in the Timezone module automatically handle time zones for us, we use django’s Timezone module instead of Python’s DateTime module to handle time.

Can you use default to change the time modified_time? The answer is no, because although the current time is specified by default the first time the model data is saved, the second time it is saved the default value will not take effect since modified_time already has a value, that is, the default value the first time. If we do not change the value of modified_time, the value is always the default value when the database is first saved.

So the key here is that you should change the modified_time value every time you save the model. Each Model has a save method that contains the logic to save the Model data to the database. Override this method by specifying modified_time to the current time before the model is saved to the database. The code is as follows:

from django.utils import timezone

class Post(models.Model):.def save(self, *args, **kwargs):
        self.modified_time = timezone.now()
        super().save(*args, **kwargs)
Copy the code

Note that after specifying the modified_time value, don’t forget to call the parent class’s save to perform the logic of saving the data back to the database.