对于drf我们是陌生的,所以我们在使用DRF搭建前后端分离时需要提前学习DRF。
教程来源杜塞-django-vue系列
博客链接 传送门
首先进入虚拟环境,然后进入进入项目根目录,创建博客文章APP:
(venv) E:\drf>cd drf_vue_blog
(venv) E:\drf\drf_vue_blog>python manage.py startapp article
创建简单的博客文章模型:
# article/models.py
from django.db import models
# Create your models here.
from django.utils import timezone
# 博客文章
class Article(models.Model):
# 标题
title = models.CharField(max_length=100)
# 正文
body = models.TextField()
# 创建时间
created = models.DateTimeField(default=timezone.now)
# 更新时间
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
前后端分离设计一个重要概念:序列化(后续讲解)。Django 有一个非常优秀的库 djangorestframework(后称 DRF)。它可以帮我们封装好序列化的底层实现,让开发者专注于业务本身。
安装DRF 及其他库依赖:
pip install djangorestframework
pip install markdown
pip install django-filter
然后将APP注册到列表:
# drf_vue_blo/settings.py
INSTALLED_APPS = [
···
···
···
'article',
'rest_framework'
]
最后进行数据迁移
(venv)E:\drf\drf_vue_blog>python manage.py makemigrations
(venv)E:\drf\drf_vue_blog>python manage.py migrate
前后端分离的核心思想之一,就是两端互不交互不需要再插入模板语言,而只需要在约定好的接口传输数据。因此问题来了。
带Django程序运行过程中,变量都是存储在服务器内存中的;更重要的是,后端Django程序中存储的是python变量,而前端是Javascript变量,这两者无法进行交流
JSON 就是这种标准格式之一。它很轻量,表示出来就是个字符串,可以直接被几乎所有的语言读取,非常方便。
举个例子,把 Python 对象转换为 JSON ,这被称为序列化(serialization):
>>> import json
>>> person = dict(name='Trump', age=82)
>>> json.dumps(person)
# 这是个字符串
'{"age": 82, "name": "Trump"}'
把 JSON 转换为 Javascript 对象,被称为反序列化:
>>> json_str = '{"age": 82, "name": "Trump"}'
>>> json.loads(json_str)
# 这是个 js 对象
{'age': 82, 'name': 'Trump'}
总之,把变量从内存中变成可存储或传输的过程称之为序列化,反过来把变量内容从序列化的对象重新读到内存里称之为反序列化。
回顾 Django 传统流程对一个网络请求的处理:
def a_list(request):
articles = Article.objects.all()
return render(..., context={'articles': articles})
视图函数将数据作为上下文返回,通过模板引擎将上下文渲染为页面中的数据。
Restful 的处理流程仅增加了一步,即对数据序列化的处理:
def a_list(request):
articles = Article.objects.all()
# 序列化数据
serializer = Serializer(articles, many=True)
return JsonResponse(serializer.data, safe=False)
数据被序列化后为Json字符串,直接交付前端处理。
这就是前后端分离的雏形。
这里又出现了与前后端分离联系很紧密的新概念:Rest(表现层状态转化) 和 Restful。Restful 架构是指客户端和服务器之间的交互、操作符合 Rest 规范,即:每一个URI代表一种资源;客户端和服务器之间,传递资源的表现层;客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。有点难理解,推荐读物阮一峰的博客和知乎文章。
按照这个思路,我们来写一个文章列表接口。
article 模型在前面已经写好了,接下来写视图:
# article/views.py
from django.shortcuts import render
# Create your views here.
from django.http import JsonResponse
from article.models import Article
from article.serializers import ArticleListSerializer
def article_list(request):
articles = Article.objects.all()
serializers = ArticleListSerializer(articles, many=True)
return JsonResponse(serializers.data, safe=False)
代码一共3行:
与前文提到的一直,不再使用模板,而是 Json 数据。
代码中的 ArticleListSerializer
我们还没写,其实他就是我们定义的序列化器。
新建py文件名为:article/serializers.py
,写入以下代码:
# article/serializers.py
from rest_framework import serializers
class ArticleListSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(allow_blank=True, max_length=100)
body = serializers.CharField(allow_blank=True)
created = serializers.DateTimeField()
updated = serializers.DateTimeField()
序列化类看上去很想From类,它指定接口数据和各个字段的类型,自动对请求和响应中的数据进行序列化和反序列化的转换。DRF 是已经定义好的,我们无需关心底层逻辑。
最后将各级 urls.py
配置好:
# drf_vue_blog/urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('api/article/', include('article.urls', namespace='article')),
]
以及:
# article/urls.py
from django.urls import path, include
from article import views
urlpatterns = [
path('', views.article_list, name='list'),
]
代码部分已完成。
接下来创建管理员用户,并在后台添加几条article
数据数据用来测试,启动服务器,可以看到如下Json数据(稍作排版,当然也可以使用浏览器插件自动排版):
[
{
"id": 1,
"title": "python",
"body": "Python is one of my favorite programming languages",
"created": "2021-06-11T11:35:50Z",
"updated": "2021-06-11T11:37:14.001883Z"
},
{
"id": 2,
"title": "Java",
"body": "I like too\u3002",
"created": "2021-06-11T11:37:15Z",
"updated": "2021-06-11T11:37:31.117904Z"
},
{"id": 3,
"title": "test",
"body": "I'm testing",
"created": "2021-06-11T11:37:34Z",
"updated": "2021-06-11T11:37:56.285260Z"
}
]
虽然简陋,但也是你已经完成了一个简单的接口:
创建管理员用户和添加数据是很基础的内容,这里不再赘述。
若出现以下错误,需要在article/urls.py
内定义app_name
:
django.core.exceptions.ImproperlyConfigured: Specifying a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.
若出现警告以下警告,点击这里:
WARNINGS:
article.Article: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.
HINT: Configure the DEFAULT_AUTO_FIELD setting or the ArticleConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.