Django by Example·Chapter 1|Building a Blog Application(developing a personal blog system)@Notes

Django by Example·Chapter 1|Building a Blog Application(developing a personal blog system)@Notes

I believe many friends have heard of this book written by Antonio Melé. The structure and content are remarkable, so I made a little record for emergencies.


Part of the content is quoted from the original book. If you are interested in this book,
please support the original Django by Example·Antonio Melé


Preface·Chapter 1

The first chapter mainly introduces the basic usage of Django and some necessary basic knowledge. It mainly includes the following contents:

  • Installing Django and creating your first project
  • Designing models and generating model migrations
  • Creating an administration site for your models
  • Working with QuerySet and managers
  • Building views, templates, and URLs
  • Adding pagination to list views
  • Using Django class-based views

1 Django installation

Django works fine with Python 2.7 or 3 versions. In the examples in this book, Python3 is used . If you're using Linux or Mac OS X, you probably have Python installed. If you are not sure if Python is installed in your computer, you can verify it by typing Python in the terminal. If you see something like the following, you have Python installed on your computer:

Python 3.5.0 (v3.5.0:374f501f4567, Sep 12 2015, 11:00:19)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type “help”, “copyright”, “credits” or “license” for more information. >>>

If your installed version of Python is lower than 3, or Python is not installed on your computer, please download it from http://www.python.org/download/ and install it.

1.1 Create an independent python environment

It is recommended that you use virtualenv to create isolated Python environments so that you can use different package versions for different projects, which is more practical than installing Python packages system-wide. Another advantage of using a virtualenv is that installing Python packages does not require any administrative privileges. Run the following command in the shell to install virtualenv:

pip install virtualenv

After installing virtualenv, use the following command to create an isolated environment:

virtualenv my_env

This will create the my_env/ directory containing the Python environment. Any Python libraries installed while the virtual environment is active will go into the my_env/lib/python3.5/site-packages directory.

Activate the virtual environment (under the my_env\scripts directory):

activate

This enters the virtual environment. You can exit the virtual environment with deactivate.

1.2 Install Django

Once inside the virtual environment, you can install django with pip:

pip install Django==1.8.6

Django will be installed in the Python site-packages/ directory of the virtual environment.

Now check if Django has been successfully installed. Run python on terminal and import Django to check its version:

import django
django.VERSION
django.VERSION(1, 8, 5, ‘final’, 0)

If you get this output, Django has been successfully installed on your machine.

Django can be installed in several other ways. You can find a complete installation guide at https://docs.djangoproject.com/en/1.8/topics/install/.


2 Create your first project

The first Django project in the book is a full blog site. Django provides a command that allows you to easily create an initial project file structure. Run the following command from the shell:

django-admin startproject mysite 

This will create a Django project called mysite .

Let's see the generated project structure:
Django project structure

These files are as follows:

  • manage.py : A command-line program for interacting with the project. It is a wrapper around the django-admin.py tool. You do not need to edit this file.

  • mysite/ : project directory. Contains the following files:

    • _init_.py : an empty file that tells Python to treat the mysite directory as a Python module .
    • settings.py : Settings and configuration files for the project. Contains the initial default settings, and you need to edit this file for later project configuration.
    • urls.py : Where URL patterns live. Each URL defined here maps to a view, or url module, of the application.
    • wsgi.py : Configuration file to run the project as a WSGI application.

Execute the migration:

cd mysite
python manage.py migrate

After performing the migration, the tables of the initial application are created in the database.


3 Start the development server

Django comes with a lightweight web server that can run code quickly without spending time configuring production servers. When you run the Django development server , it constantly checks for changes in the code. It automatically reloads, saving you from having to manually reload after code changes. However, it may not notice certain actions, such as adding new files to the project, so in these cases you will have to restart the server manually.

Start the development server by typing the following command in the project's root folder:

python manage.py runserver

Then you can see:

Performing system checks…
System check identified no issues (0 silenced). November 5, 2015 - 19:10:54
Django version 1.8.6, using settings ‘mysite.settings’ Starting development server at http://127.0.0.1:8000/Quit the server with CONTROL-C.

Now, open the URL http://127.0.0.1:8000/ in your browser. You should see a page, a little rocket taking off, and seeing this means you succeeded.

You can instruct Django to run the development server on a custom host and port, or tell it that you want to load a different settings file to run the project. For example, the manage.py command can be run as follows:

python manage.py runserver 127.0.0.1:8001 --settings=mysite.settings

This is handy for dealing with multiple environments that require different settings. Remember, this server is for development only, not for production. In order to deploy Django in production, you should run it as a Web Server Gateway Interface (WSGI) application using a real web server such as Apache, Gunicorn, or uWSGI. For more information on how to deploy Django on different web servers, visit https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/.


4 Configuration of the project

Let's open the settings.py file and take a look at our project's configuration. Django includes several settings in this file, but these are only a subset of all settings available to Django. You can see all the settings and their default values ​​at https://docs.djangoproject.com/en/1.8/ref/settings/.

4.1 Configuration items worth looking at

  • DEBUG : is a boolean value used to turn on/off the debug mode of the project. If set to True, Django will display detailed error pages when the application throws an uncaught exception. Remember that this must be set to False when you deploy your project to production. Never deploy your site to production with DEBUG enabled, as this will expose sensitive data of your project.

  • ALLOWED_HOSTS : Not applied when debug mode is on or running tests. Once you're moving your site to production and setting up debugging, if set to False, you must add your domain name/host to ALLOWED_HOSTS for it to serve your Django site.

  • INSTALLED_APPS : This setting tells Django which applications are active on this site, whether it is a test environment or a production environment. By default, Django includes the following applications:

    • django.contrib.admin : This is the background administration site.
    • django.contrib.auth : This is the authentication framework.
    • django.contrib.contenttypes : This is the framework for content types.
    • django.contrib.sessions : A framework for managing sessions.
    • django.contrib.messages : Framework for message management.
    • django.contrib.staticfiles : A framework for managing static files.
  • MIDDLEWARE_CLASSES : Tuple containing middleware to execute.

  • ROOT_URLCONF : The root URL of the project.

  • DATABASES : is a dictionary containing settings for all databases used in the project. The default database must always exist. The default configuration uses the SQLite3 database.

  • LANGUAGE_CODE : Defines the default language code for Django sites, the default is English.


5 Create an application

Now, let's create our first Django application. We're going to create a blogging application from scratch. In the root directory of the project, run the following command:

python manage.py startapp blog

This will create the basic structure of the application as follows:
The basic structure of a django application

These files are as follows:

  • admin.py : Here you can register the model for inclusion into the Django admin site. Administering the site with Django is optional.
  • migrations : This directory will contain the application's database migrations. Migrations allow Django to track model changes and sync the database accordingly.
  • models.py : The application's data models. All Django applications require a models.py file, but this file can be left blank.
  • tests.py : Here you can add tests for the application.
  • views.py : The logic of the application goes here. Each view receives an HTTP request, processes it, and returns a response.

6 Designing a data model for a blog

We'll start by defining the initial data model for the blog. A model is a Python class that is django.db.models.Modela subclass of , where each attribute represents a database field. Django will create a table for each model defined in the models.py file. When you create your models, Django provides you with a useful API to easily query the database.

First, we'll define the Post model. Add the following line to the models.py file of the blog application:

from django.db import models 
from django.utils import timezone
from django.contrib.auth.models import User

class Post(models.Model):
	STATUS_CHOICES = (
		('draft', 'Draft'),
		('published', 'Published'),
	)
	title = models.CharField(max_length=250)
    slug = models.SlugField(max_length=250, unique_for_date='publish')
    author = models.ForeignKey(User, related_name='blog_posts', on_delete=models.DO_NOTHING)
    body = models.TextField()
    publish = models.DateTimeField(default=timezone.now)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    status = models.CharField(max_length=10, 

	class Meta:
		ordering = ('-publish',)
	
		def __str__(self):
			return self.title

This is the basic model of a blog post as we define it. Let's take a look at the fields we just defined for this model:

  • title : A field for the title of the blog post. The field is CharField, which corresponds to the VARCHAR column in the SQL database.
  • slug : slug is a field for URL. A slug is a short tag containing only letters, numbers, underscores or hyphens. We'll use the slug field to build beautiful, SEO-friendly URLs for our blog posts. We've added the unique_for_date parameter to this field so we can use the post's date and slug to build the post's URL. Django will prevent multiple posts with the same slug on the same date.
  • author : This field is a foreign key. This field is used to define a one-to-many relationship. It means that each user can write multiple posts, and each post corresponds to a user. For this field, Django will create a foreign key in the database using the primary key of the related model. In this example, we rely on the User model of Django's authentication system. We use the related_name attribute to specify the name of the reverse relationship, from User to Post. We'll learn more about this later.
  • body : The body of the post. This field is a TextField which translates to a TEXT column in the SQL database.
  • publish : The time field type indicates when the article was published. We use Django's timezone.now method as the default. Its value is related to the time zone configured in settings.py.
  • created : The time field type indicates when the article was created. Because we set autonow_add to True here, the date will be saved automatically when the object is created.
  • updated : The time field type indicates when the article was created and updated. Because we set autonow_add to True here, this date will be automatically modified when saving the object.
  • status : This is a field that shows the status of the post. We use the choice parameter, so the value of this field can only be set to one of the given options.

Django also provides other different types of fields that you can use to define your models. You can find all field types in https://docs.djangoproject.com/en/1.8/ref/models/fields/ .

The class Meta in the model contains metadata. We're telling Django to sort by publish time descending by default when querying the database. Descending order can be specified with a negative prefix.

In order for SQLite to handle datetimes properly. You need to install pytz, use the following command to open a shell and install pytz:

pip install pytz

Django supports timezone-aware datetimes by default. You can activate/deactivate timezone support using the USE_TZ setting in your project's settings.py file .


7 Activate your application

In order for Django to track our application and be able to create database tables for its models, we need to activate it. To do this, edit the settings.py file and add the blog to the INSTALLED_APPS setting:

INSTALLED_APPS = (
	'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',    
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',  # 新添加的
)

After the application is activated, Django can track changes to the view and data model.


8 Generate the migration file and execute the migration

This step is to create data tables in the database according to the data model. Django comes with a migration system that tracks changes you make to your models and propagates them to the database. The migrate command applies migrations to all applications listed in INSTALLED_APPS; it synchronizes the database with the current models and migrations.

First, we need to generate migration files for the new model we just created. In the root directory of the project, enter the following command:

python manage.py makemigrations blog

You can see the following output:

Migrations for ‘blog’:
0001_initial.py:
– Create model Post

Django just created a file 0001_initial.py in the migrations directory of the blog application. You can open this file to view the contents of the migration file.

Let's take a look at the SQL code that Django will execute in the database in order to create the tables for our models. sqlmigratecommand takes a migration name and returns its SQL without running it. Run the following command to check its output:

python manage.py sqlmigrate blog 0001

After executing this command, the output will be as follows:

BEGIN;
CREATE TABLE "blog_post" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(250) NOT NULL, "slug" varchar(250) NOT NULL, "body" text NOT NULL, "publish" datetime NOT NULL, "created" datetime NOT NULL, "updated" datetime NOT NULL, "status" varchar(10) NOT NULL, "author_id" integer NOT NULL REFERENCES "auth_user" ("id")); 
CREATE INDEX "blog_post_2dbcba41" ON "blog_post" ("slug");
CREATE INDEX "blog_post_4f331e2f" ON "blog_post" ("author_id");
COMMIT;

The output SQL statement format depends on the database you use. The output above is determined by the SQLite database. As you can see, Django generates table names by combining the application name and the model's lowercase name (blog_post), but you can also specify them in the model's Meta class using the db_table attribute. Django automatically creates a primary key for each model, but you can also override a primary key specifying primary_key=True on a model field.

Next let's execute the migration to create the corresponding tables in the database, executing the migration actually executes the migration file. Enter the following command:

python manage.py migrate

You will get output like this:

Applying blog.0001_initial… OK

We just performed migrations for the applications listed in INSTALLED_APPS, including our blog application. After the migration is performed, the corresponding database tables will be created in the database.

If you edited the models.py file, added, removed, or changed fields of existing models, or added new models, you must use the makemigrationsgenerate-migration command again. Migrations will allow Django to track model changes. Then, use migratethe command to perform a migration to keep the database in sync with the model.


9 Create an admin site for the model

Now that we have defined the Post model, we will create a simple admin site to manage the database tables corresponding to this model. Django comes with a built-in admin interface that is very useful for editing content. The Django admin site is built dynamically by reading model metadata and providing an interface for editing content. You can use it out of the box or add some configuration items.

Remember to django.contrib.adminalready include in our project's INSTALLED_APPS setting, otherwise you won't be able to create site admins.

9.1 Create a super administrator

First, we need to create a user to manage the admin site. Run the following command:

python manage.py createsuperuser

You will see the following output. You will need to enter the required username, email and password:

Username (leave blank to use ‘admin’): admin Email address: [email protected]
Password: ********
Password (again): ********
Superuser created successfully.

9.2 Django's admin site

Now, python manage.py runserverstart the development server with the command and open http://127.0.0.1:8000/admin/ in your browser. You should see the admin login page, as shown in the image below:
django administrator interface
Login with the credentials of the user created in the previous step. You will see the Manage Site Index page, as shown in the image below:

django admin site homepage
The group and user models you see here, which are part of Django's authentication framework, are located in Django.contrib.auth. If you click on Users, you will see the previously created users. The Post model of the blog application has a relationship with this User model. Remember, this is the relationship defined by the author field. But right now you can't see the model for the blog application because we haven't added the model to the admin site yet.


10 Adding the model to the admin site

Let's add the post model from your blog application to the admin site. Edit the admin.py file of the blog application and add the following code:

from django.contrib import admin
from .models import Post

admin.site.register(Post)

Now, reload the admin site in your browser. You should see your Post model in the admin site like so:

Add custom model to django site
It's easy, right? When you register a model with the Django admin site, you get a user-friendly interface generated by introspecting the model, allowing you to list, edit, create and delete objects in an easy way.

Click the add link to the right of Posts to add a new post. You'll see Django's dynamically generated create form for the model, like so:

insert image description here
Django uses a different form widget for each type of field. Even complex fields like DateTimeField can be displayed with a simple interface like JavaScript Date Picker.

Fill out the form and click the "Save" button. You should be redirected to the posts list page with a success message and the post just created, as shown in the image below:
insert image description here


11 Customize the way the model is displayed

Now we'll see how to customize the admin site, such as customizing the fields displayed, adding filters, searching, and more. Edit the admin.py file of the blog application and change it to:

from django.contrib import admin
from .models import Post

class PostAdmin(admin.ModelAdmin):
	list_display = ('title', 'slug', 'author', 'publish', 'status')

admin.site.register(Post)

We tell the Django admin site that our models are registered with the admin site using a custom class that inherits from ModelAdmin. In this class we can include information about how to display the model in the admin site and how to interact with it. list_displayProperties allow you to set the model fields to be displayed in the admin object list page.

Let's use more options to customize the model, modify the code in admin.py under the blog application:

class PostAdmin(admin.ModelAdmin):
	list_display = ('title', 'slug', 'author', 'publish', 'status')
    list_filter = ('status', 'created', 'publish', 'author')
    search_fields = ('title', 'body')
    prepopulated_fields = {
    
    'slug': ('title',)}
    raw_id_fields = ('author',)
    date_hierarchy = 'publish'
    ordering = ['status', 'publish']

Go back to your browser and reload the article listing page. It will now look like this: As
insert image description here
you can see, the fields displayed on the post list page are the ones you specified in the list_display property. List pages now include a right sidebar that allows you to filter results by fields included in the list_filter property. A search bar appears on the page. This is because we have defined a list of searchable fields using the search_fields property. Right below the search bar, there is a bar for quickly navigating through the date hierarchy. This is defined by the date_hierarchy attribute. You can also see that by default the posts are sorted by the "status" and "publish" columns. You have specified a default order using the sort property.

Now click on the Addpost link. You'll see some changes here too. As you
type the title of your new post, the slug field will be automatically populated. We've told Django to prepopulate the slug field with input from the header field using the prepopulated_fields attribute. Also, the author field now shows a lookup widget that scales much better than a dropdown select input when you have thousands of users, as shown in the image below: With a few lines of code, we customized how the model is displayed in the admin site
insert image description here
. There are many ways to customize and extend the Django admin site. Later in the book, this will be further explained.


12 Using QuerySet and Manager (Django's ORM)

Now that you have a fully functional admin site for managing your blog content, it's time to learn how to retrieve and interact with information from the database. Django provides a powerful database abstraction API that allows you to easily create, retrieve, update, and delete objects. The Django Object Relational Mapper (ORM) is compatible with MySQL, PostgreSQL, SQLite, and Oracle. Remember that you define your project's databases by editing the DATABASES setting in your project's settings.py file. Django can handle multiple databases at once, and you can even program a database router to handle data in any way you like.

Once you've created your data models, Django provides a free API for you to interact with them. You can find the data model reference for the official documentation at https://docs.djangoproject.com/en/1.8/ref/models/.

12.1 Creating Objects Using an ORM

Open a Python shell with the following command in Terminal:

python manage.py shell

Then enter the following code:

>>> from django.contrib.auth.models import User 
>>> from blog.models import Post
>>> user = User.objects.get(username='admin')
>>> Post.objects.create(title='One more post',
						slug='one-more-post',
						body='Post body.',
						author=user
						)
>>> post.save()

Let's analyze what this code does.
First, we get the user object with the username admin:

user = User.objects.get(username='admin')

The get() method allows you to retrieve a single object from the database . Note that this method requires a result that matches the query. This method will throw a DoesNotExist exception if the database returns no results, and a MultipleObjectsReturn exception if the database returns multiple results. Both of these exceptions are properties of the model class that is executing the query.

Then we create a Post instance with a custom title, slug, and body; we set the previously retrieved user as the author of the post:

post = Post(title='Another post', slug='another-post', body='Post body.', author=user)

Finally, we save the Post object to the database using the save() method:

post.save()

This operation will execute the INSERT SQL statement. We've seen how to create an object in memory first and then persist it to the database, but we can also create the object directly into the database using the create() method:

Post.objects.create(title='One more post', slug='one-more-post', body='Post body.', author=user)

12.2 Modifying Objects Using the ORM

Now, change the article title to something else, and save the object again:

>>> post.title = 'New title'
>>> post.save()

If the object already exists, the save() method executes the UPDATE SQL statement.

12.3 Retrieving Objects

12.3.1 Retrieve all objects

Django Object Relational Mapping (ORM) is based on QuerySet. A QuerySet is a collection of objects in a database that can have several filters to limit the results. You already know how to retrieve a single object from the database using the get() method . Every Django model has at least one manager, and the default manager is called an object. You can obtain QuerySet objects using the model manager. To retrieve all objects from a table, simply use the all() method on the default object manager, like this:

>>> all_posts = Post.objects.all()

This is how we create a QuerySet that returns all objects in the database. Note that this QuerySet is not yet executed. Django's QuerySet is a lazy query; only when operating on a specific object will the corresponding SQL be executed to modify the content in the database. This behavior makes QuerySet very efficient. If we don't set the QuerySet as a variable, but write it directly to the Python shell, the SQL statement of the QuerySet will be executed, because at this point we printed out the QuerySet in the shell:

>>> Post.objects.all()

12.3.2 Using the filter() method

This is the conditional query provided by Django ORM. Using this method, we can query the QuerySet under certain conditions. To filter the QuerySet, the manager's filter() method can be used. For example, we can retrieve all posts published in 2015 using the following QuerySet:

>>>Post.objects.filter(publish__year=2015)

You can also filter by multiple fields. For example, we can retrieve all posts by an author in 2015 using the username admin:

Post.objects.filter(publish__year=2015, author__username='admin')

This is equivalent to building the same QuerySet chaining multiple filters (chained usage of filter() ):

Post.objects.filter(publish__year=2015).filter(author__username='admin')

We build queries using field lookup methods with two underscores ( publish__year ), but we also use two underscores ( author__username ) to access fields of related models.

12.3.3 Using the exclude() method

Certain results can be excluded from the QuerySet using the manager's exclude() method. For example, we can retrieve all posts published in 2015 whose title does not start with Why:

Post.objects.filter(publish__year=2015)..exclude(title__startswith='Why')

12.3.4 Using order_by() to sort a QuerySet

The results can be sorted by different fields using the manager's order_by() method. For example, all objects sorted by title can be retrieved:

Post.objects.order_by('title')

order_by() results in ascending order by default. Descending order can be indicated using a minus sign prefix, as follows:

Post.objects.order_by('-title')

12.4 Deleting objects

If you want to delete an object, you can delete from the object instance:

post = Post.objects.get(id=1) 
post.delete()

Of course, you can also use delete() on the query set to achieve the effect of batch deletion. It is important to note that deleting an object also deletes any dependencies.

12.5 Under what circumstances, the query will execute the SQL statement

You can attach any number of filters to a QuerySet, and you won't hit the database until you actually manipulate the QuerySet. The database will only be accessed under the following circumstances:

  • When iterating the QuerySet for the first time.
  • When performing a slice operation on a QuerySet.
  • When you cache or print the QuerySet.
  • When you call repr() or len() on the objects in the QuerySet.
  • when you call list() explicitly.
  • When you test it in a bool(), or, and, or if statement, etc.

13 How to create a model manager

The above-mentioned various operations on the data model use the manager that comes with Django. But we can also define custom managers for models. We'll create a custom manager to retrieve all posts with a published status.

There are two ways to add managers to the model: you can add additional manager methods or modify the initial manager QuerySet. The first is like Post.objects.my_manager() and the latter is like Post.my_manager.all(). Our manager will allow us to retrieve posts using Post.published.

Edit the models.py file of the blog application to add a custom manager:

class PublishedManager(models.Manager):
	def get_queryset(self):
		return super(
			PublishedManager,
			self
		).get_queryset().filter(status='published')

		
class Post(models.Model):
	# ...
	
	objects = models.Manager()  # The default manager.  							
	PublishedManager() # Our custom manager.						
		

get_queryset() is the method that returns the QuerySet to be executed. We use this to include custom filters in the final QuerySet. We've defined our custom manager and added it to the Post model; we can now use it to execute queries. For example, we can retrieve all published posts whose title starts with Who using:

Post.published.filter(title__startswith='Who')

14 Define View Functions

Now that you have some knowledge of how to use an ORM, it's time to build the blog application's views. A Django view is just a Python function that takes a web request and returns a web response. Inside the view, all the logic to return the desired response is defined.

First, we'll create the application views, then define a URL pattern for each view; finally, we'll create HTML templates to render the data generated by the views. Each view will render a template passed variables and will return an HTTP response with the rendered output.

14.1 Create a view that displays a list of posts

Let's first create a view to display a list of posts. Edit the views.py file of the blog application and add the following code:

from django.shortcuts import render, get_object_or_404
from .models import Post

def post_list(request):
	posts = Post.published.all()
	
	return render(
		request,
		'blog/post/list.html',
		{
    
    'posts': posts}
	)

You just created your first Django view. The post_list view takes the request object request as the only parameter. Remember, all views require this parameter. In this view, we retrieve all posts with published status using the published manager created earlier.

Finally, we render the list of posts with the given template using the render() shortcut provided by Django. This function takes as parameters the request object, the template path, and a variable to render the given template. It returns an HttpResponse object and the rendered text (usually HTML code). The render() shortcut takes the request context into account, so a given template can access any variables set by the template context processor. Template context processors are just callables that set variables into the context. You'll learn how to use them in Chapter 3, "Extending Your Blogging Application."

14.1 Create a view that displays post details

Let's create a second view to display the details of an article. Add the following function to the views.py file:

def post_detail(request, year, month, day, post):
    post = get_object_or_404(
    			Post,
    			slug=post,
    			status='published',
    			publish__year=year,
    			publish__month=month,
    			publish__day=day
    		)
    
    return render(request,
    			'blog/post/detail.html',
    			{
    
    'post': post},
    		)

This is the post detail view. The view uses the year, month, day, and post parameters to retrieve published posts with a given segment and date. Note that when we created the Post model, we added a unique_for_date parameter to the slug field. In this way, we can ensure that there is only one post with a slug in a given date, therefore, we can retrieve a single post by date and slug. In the detail view, we use the get_object_or_404() shortcut to retrieve the desired Post. This function retrieves an object matching the given parameters, and if the object is not found, an HTTP 404 (Not Found) exception is initiated. Finally, we render the retrieved posts using the template using the render() shortcut.


15 Adding URL patterns to your views

A URL pattern consists of a Python regular expression, a view, and a name that allows project-wide naming. Django runs through each URL pattern, and stops at the first pattern that matches the requested URL. Django then imports the view matching the URL pattern and executes it, passing an instance of the HttpRequest class and keyword or positional arguments.

If you haven't used regular expressions before, you might want to take a look at python's regular expressions link first

Create a urls.py file in the blog application's directory and add the following lines:

from django.conf.urls import url 
from . import views

urlpatterns = [
	# post views
    url(r'^$', views.post_list, name='post_list'),
    url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/(?P<post>[-\w]+)/$', views.post_detail, name='post_detail'),
]

The first URL pattern takes no parameters and maps to the post_list view. The second schema takes the following four parameters and maps to the post_detail view. Let's look at the regular expressions for URL patterns:

  • year: Four digits are required.
  • month: Two digits are required.
  • day: Two digits are required.
  • post: Can consist of words and hyphens.

You must now include the blog application's URL pattern into the project's URL pattern. Edit the urls.py file in the project mysite directory and add the following content to it:

from django.conf.urls import include, url from django.contrib import admin

urlpatterns = [
	url(r'^admin/', include(admin.site.urls)),
	url(r'^blog/', include('blog.urls', namespace='blog', app_name='blog')),
]

This way you tell Django to include the URL patterns defined in blog urls.py under blog/path. You name it blog so you can easily refer to this set of URLs.

15.1 Use the get_absolute_url() method to return a standard URL

You can use the URL defined for post_detail in the previous section to get the view's response. But the convention in Django is to add a get_absolute_url() method to the model that returns the canonical url of the object. For this method, we will use the reverse() method, which allows you to build the URL by its name and by passing optional parameters. Edit the models.py file and add the following:

from django.core.urlresolvers import reverse 

Class Post(models.Model):
	# ...
	def get_absolute_url(self):
		return reverse(
				'blog:post_detail',
				args=[
					self.publish.year,
					self.publish.strftime('%m'),
					self.publish.strftime('%d'),
					self.slug,
					]
				)

We will use the get_absolute_url() method in the template (HTMLa file).


16 Create templates for your view functions

We have created the views and URL patterns for the blog application. Now it's time to add templates for easy display of post content.

Create the following directories and files in the blog application directory:
insert image description here
This will be the file structure of our template. The base.html file will contain the main html structure of the website and divide the content into the main content area and sidebars. The list.html and detail.html files will inherit from the base.html file to render blog post list and detail views respectively.

Django has a powerful templating language that allows you to specify how data is displayed. It is based on template tags, template tags like {%tag%}; template variables like {{{variable}}; and template filters, which can be applied to variables and look like {{ variable | filter}. You can see all built-in template tags and filter links .

Let's edit the base.html file and add the following code:

{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
  <title>{% block title %}{% endblock %}</title>
  <link href="{% static "css/blog.css" %}" rel="stylesheet"> </head>
<body>
<div id="content">
    {% block content %}
    {% endblock %}
</div>
<div id="sidebar">
	<h2>My blog</h2>
	<p>This is my blog.</p>
</div>
</body>
</html>

{%load staticfiles%} tells Django to load Django.contrib.staticfilesthe staticfiles template tag provided by the application. Once loaded, you can use the {%static%} template filter throughout your template. Using this template filter, you can include static files, such as the blog.css file, under the static/ directory of your blog application, which you'll find in the code for this example. Copy this directory to the same location of your project to use existing static files.

Let's edit the post/list.html file and add the following:

{% extends "blog/base.html" %}

{% block title %}My Blog{% endblock %}

{% block content %}
<h1>My Blog</h1>
  {% for post in posts %}
  <h2>
  	<a href="{
     
     { post.get_absolute_url }}">
  		{
   
   { post.title }}
  	</a>
  </h2>
  <p class="date">Published {
   
   { post.publish }} by {
   
   { post.author }}</p>
  {
   
   { post.body|truncatewords:30|linebreaks }}
 {% endfor %}
{% endblock %}

Using the {%extends%} template tag, we tell Django to extend the template file blog/base.html. We then populate the header and content blocks of the base template with content. We iterate over the posts and display their title, date, author, and body, including a link in the title to the post canonical URL. In the body of the article, we apply two template filters: truncatewords truncates the value to the specified number of words, and newlines converts the output to HTML newlines. You can connect as many template filters as you want; each one will be applied to the generated output of the previous one.

Open a shell and execute the command python manage.py runserver to start the development server. Open http://127.0.0.1:8000/blog/ in your browser and you'll see everything running. Note that you need to have some posts with status "Published" to see them here. You should see something like this:
insert image description here
Then, let's edit the post/detail.html file and add the following:

{% extends "blog/base.html" %}

{% block title %}{
   
   { post.title }}{% endblock %}

{% block content %}
  <h1>{
   
   { post.title }}</h1>
  <p class="date">Published {
   
   { post.publish }} by {
   
   { post.author }}</p>
  {
   
   { post.body|linebreaks }}
{% endblock %}  

You can now go back to your browser and click on one of the post titles to view the post's link. You should see something like this:
insert image description here


17 Create a pager for blog content

As you start adding content to your blog, you'll quickly realize that you need to split your post list into several pages. Django has a built-in pagination class that allows you to easily manage paginated data.

Edit the views.py file of the blog application to import the class and modify the post_listDjango paginator view as follows :

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

def post_list(request):
	 object_list = Post.published.all()
	 paginator = Paginator(object_list, 3) # 3 posts in each page
	 page = request.GET.get('page')
	 try:
	 	posts = paginator.page(page)
	 except PageNotAnInteger:
	 	# If page is not an integer deliver the first page 
	 	posts = paginator.page(1)
     except EmptyPage:
    	# If page is out of range deliver last page of results 
    	posts = paginator.page(paginator.num_pages)
    	
     return render(
     		request,
     		'blog/post/list.html',
     		{
    
    'page': page, 'posts': posts},
     	)

So how does Django's own pager work:

  1. First, instantiate the Paginator class for each object displayed on the page.
  2. Get to the page number of the current request.
  3. Use the page number as a parameter to get the data we want.
  4. When the object is less than 1 page and the object is empty, the exception is caught.
  5. Pass the page number and the retrieved object to the template.

Now, we have to create a template to display the pager so that it can be included in any HTML that uses pagination. In the templates folder of the blog application, create a new file and name it pagination.html. Add the following html code to this file:

<div class="pagination">
	<span class="step-links">
		{% if page.has_previous %}
			<a href="?page={
     
     { page.previous_page_number }}">Previous</a>
		{% endif %}
		<span class="current">
			Page {
   
   { page.number }} of {
   
   { page.paginator.num_pages }}.
		</span>
		
		{% if page.has_next %}
			<a href="?page={
     
     { page.next_page_number }}">Next</a>
		{% endif %}
	</span>
</div>

The pagination template requires a Page object in order to render the previous and next links and to display the current page and the total pages of results. Let's go back to the blog/post/list.html template and include the pagination.html template at the bottom of the {%content%} block like this:

{% block content %}
  ...
  {% include "pagination.html" with page=posts %}
{% endblock %}

Since the Page objects we pass to the template are called posts, we include the pagination template into the post list template, specifying the parameters to properly render that template. This is how pagination templates can be reused in pagination views of different models.

Now, open http://127.0.0.1:8000/blog/ in your browser. You should see the pagination at the bottom of the article list, and you should be able to browse the pages:
insert image description here


18 Using python's classes as views (CBV)

Since views are callable objects that accept web requests and return web responses, you can also define views as class methods. Django provides the base view class View. For this, all of them inherit from the View class, which handles HTTP method dispatch and other functionality. This is another way to create views.

We'll change the post_list view to a class-based view to use the generic ListView provided by Django.

Edit the views.py file of the blog application and add the following code:

from django.views.generic import ListView

class PostListView(ListView):
	queryset = Post.published.all()    
	context_object_name = 'posts'
	paginate_by = 3
    template_name = 'blog/post/list.html'

This class-based view has the same function as the original FBV. Here, we tell the ListView:

  • Defines the object to fetch, which is a QuerySet.
  • The template variable context variable of the query result is posts, if no context_object_name is specified, the default template variable is object_list.
  • Quantity per page
  • template file

Now, open the urls.py file of the blog application , comment out the previous post_list URL pattern, and add a new URL pattern using the PostListView class as follows:

urlpatterns = [
	# post views
    # url(r'^$', views.post_list, name='post_list'),
    url(r'^$', views.PostListView.as_view(), name='post_list'),
    url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/(?P<post>[-\w]+)/$', views.post_detail, name='post_detail'),
]   

To ensure that the pager works properly, pass a pager object to the template. Django's ListView passes the selected page in a variable called page_obj, so you'll have to edit the post_list.html template accordingly to include the paginator with the correct variable, like this:

{% include "pagination.html" with page=page_obj %}

Open http://127.0.0.1:8000/blog/ in your browser and check that everything works the same as the previous postlist view. This is a simple example of a class-based view using the generic classes provided by Django. You'll learn more about class-based views in Chapter 10, "Building an e-Learning Platform" and subsequent chapters.


Summarize

In this chapter, you've learned the basics of the Django web framework by creating a basic blog application. You have designed your data model and applied migrations to your project. You've created the views, templates, and URLs for your blog, including object pagination.

In the next chapter, you will learn how to use:

  • comment system
  • marking function
  • Allow users to share
  • Publish by email

Guess you like

Origin blog.csdn.net/qq_42774234/article/details/128332000
Recommended