教程12 drf-yasg + Django REST framework 后端接口开发(用户管理、留言管理)

一、环境搭建

IDE:Pycharm
数据库:MySQL、Navicat
Python版本:python 3.9.2
虚拟环境:virtualenvwrapper

1. 安装Python解释器

官网下载:https://www.python.org
建议下载:Python 3.9.2

2. 安装Pycharm

二、Python创建虚拟环境(可以直接指向Python安装的可执行文件,此步可省略)

创建虚拟环境是为了让项目运行在一个独立的局部的Python环境中,使得不同环境的项目互不干扰。

1. 查看本机的Python版本

python

本地安装了Python 3.9.2,现使用Python3.9.2创建一个虚拟环境。
在这里插入图片描述

2. 本地搜索Python 3.9的文件位置

在这里插入图片描述

3. Python 3.9 (64-bit) 右键,属性

在这里插入图片描述

4. 用命令创建虚拟环境指向Python 3.9,虚拟环境名称为:myapi

pip install virtualenv  -i https://pypi.douban.com/simple/

在这里插入图片描述

pip install virtualenvwrapper-win -i https://pypi.douban.com/simple/

在这里插入图片描述

mkvirtualenv -p C:\python\Python39\python.exe myapi

在这里插入图片描述

6. 进入虚拟环境

workon myapi

7. 退出虚拟环境

deactivate

三、安装Django

pip install Django==4.1.4 -i https://pypi.douban.com/simple

在这里插入图片描述
安装好的Django命令:
在这里插入图片描述
查看Django版本命令为:
在这里插入图片描述

四、新建Django项目

1、使用PyCharm创建Django项目

File——》new Project——》Django
在这里插入图片描述

2、项目结构

在这里插入图片描述

3、项目运行结果

在这里插入图片描述

五、优化项目结构

在前面创建的项目中,优化项目结构:
新建static文件夹:css、js、图片等放入static目录下。
新建media文件夹:存放用户上传图片、文件等放到此文件夹中。
新建一个package,命名为apps,将项目myapi放入此文件夹。
新建一个package,命名为extra_apps,将项目添加的第三方源码放入此目录中。
新建一个文件,名称requirements.txt,用于记录项目依赖的第三方包。

在这里插入图片描述

六、使用Django REST framework自动生成接口文档环境配置

1、 安装

使用 安装pip,包括您想要的任何可选包…

pip install djangorestframework
pip install markdown       # Markdown support for the browsable API.
pip install django-filter  # Filtering support

在这里插入图片描述

2、 配置

(1)添加’rest_framework’到您的INSTALLED_APPS设置中。

INSTALLED_APPS = [
    ...
    'rest_framework',
]

(2)将以下内容添加到您的根urls.py文件中。

urlpatterns = [
    ...
   path('docs/', include_docs_urls(title='留言板项目接口文档')),
]

(3)settings.py模块中增加全局REST_FRAMEWORK

将以下内容添加到您的settings.py模块中:

REST_FRAMEWORK = {
    'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
    # Use Django's standard `django.contrib.auth` permissions,
    # or allow read-only access for unauthenticated users.
    'DEFAULT_PERMISSION_CLASSES': [        'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
    ]
}

七、案例(用户管理)

1、创建一个读写 API 来访问我们项目中用户的信息。

(1)新建一个应用users

manage.py@myapi_project > startapp users

(2)将users拖入到apps中

在这里插入图片描述

(3)在myapi_project\myapi_project\settings.py中增加一行。

INSTALLED_APPS = [  
	'apps.users.apps.UsersConfig',  
]  

2、新建MySQL数据库myapi_db

3、修改settings.py中的数据库配置

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'myapi_db',
        'USER': 'root',
        'PASSWORD': 'root',
        'HOST': '127.0.0.1',
    }
}

4、 安装MySQL驱动:

windows下载安装包的网址:
https://www.lfd.uci.edu/~gohlke/pythonlibs/
在这里插入图片描述
搜索mysqlclient
在这里插入图片描述
根据你Python版本找到相应的mysqlclient版本。此处下载了mysqlclient-1.4.6-cp39-cp39-win_amd64.whl。
找到自己的下载路径:

安装:
进入文件路径:

cd D:\mysqlclient驱动安装

进入虚拟环境:

workon myapi

安装:

pip install mysqlclient-1.4.6-cp39-cp39-win_amd64.whl

在这里插入图片描述

5、修改users models.py

makemigrations
migrate

在这里插入图片描述
在这里插入图片描述

6、修改users models.py

当使用makemigrations、migrate命令后,数据库中会自动添加了一些表。
在这里插入图片描述
因为我们网站中包含用户手机号码注册、登录功能,所以需要在现有的user表中添加一些字段,具体步骤如下。

(1)自定义一张表userprofile

此表保留user表中的字段,再新增如下图所示的一些字段。修改users/models.py

from django.db import models
from django.contrib.auth.models import AbstractUser
from django.db.models import  DateTimeField

GENDER_CHOICES = (
    ("male", "男"),
    ("female", "女")
)


class UserProfile(AbstractUser):
    username = models.CharField(max_length=50, verbose_name="用户姓名", null=True, unique=True, default="")
    nick_name = models.CharField(max_length=50, verbose_name="昵称", null=True, blank=True, default="")
    birthday = models.DateField(verbose_name="生日", null=True, blank=True)
    gender = models.CharField(verbose_name="性别", choices=GENDER_CHOICES, max_length=6, default="男", null=True,
                              blank=True)
    address = models.CharField(max_length=100, verbose_name="地址", null=True, blank=True)
    email = models.CharField(max_length=100, verbose_name="邮箱", null=True, blank=True)
    mobile = models.CharField(max_length=11, verbose_name="手机号码", null=True, blank=True)
    image = models.ImageField(upload_to="head_image/%Y/%m", default="default.jpg", verbose_name="用户头像", null=True,
                              blank=True)  # media目录下
    date_joined = DateTimeField(auto_now_add=True)

    # 通过一个内嵌类 "class Meta" 可以给model定义元数据
    # verbose_name指定在admin管理界面中显示中文;
    # verbose_name表示单数形式的显示,verbose_name_plural表示复数形式的显示;中文的单数和复数一般不作区别。
    class Meta:
        verbose_name = "用户信息"
        verbose_name_plural = verbose_name

        # 平常创建一个类的对象,print这个对象时一般会是这个对象的所属类和内存地址;

    # 我们改写类中的__str__方法后可以在print时得到想要的易于人阅读的对象的信息
    def __str__(self):
        if self.nick_name:
            return self.nick_name
        else:
            return self.username  # username是必填字段,不能为空

(2)先删除数据库中的所有表。

(3)安装pillow包

pip install pillow

(4)在settings.py文件中指名使用的用户表

AUTH_USER_MODEL = "users.UserProfile"     # app的名称加上类名

在这里插入图片描述

(5)分别执行makemigrations、migrate

makemigrations
migrate

此时数据库中的表已发生了变化
在这里插入图片描述
userprofile表的结构:
在这里插入图片描述

7、在apps/users下新建一个serializers.py:

在这里插入图片描述

from rest_framework import serializers

from apps.users.models import UserProfile


class UserProfileSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = UserProfile
        fields = ['id', 'password', 'last_login', 'is_superuser', 'username', 'first_name',
                  'last_name', 'email', 'is_staff', 'is_active', 'date_joined', 'nick_name',
                  'birthday', 'gender', 'address', 'mobile', 'image']

8、修改apps/users/views.py

import json
from django.contrib.auth import authenticate, login, logout
from django.http import JsonResponse, HttpResponse
from django.shortcuts import render, redirect
from django.views.decorators.csrf import csrf_exempt
from rest_framework import viewsets, permissions


from . import models
from .models import UserProfile
from .serializers import UserProfileSerializer


class UserProfileViewSet(viewsets.ModelViewSet):
    queryset = UserProfile.objects.all().order_by('id')
    serializer_class = UserProfileSerializer
    permission_classes = [permissions.IsAuthenticated]


# @api_view(['POST'])
# 忽略csrf校验
@csrf_exempt
# @api_view(['GET', 'POST'])
def register_view(request):
    if request.method == 'POST':
        meta = {
            "msg": "用户注册成功!",
            "status": 200
        }
        form_data = json.loads(request.body.decode("UTF-8"))
        username = form_data['username']
        exists = UserProfile.objects.filter(username=username).exists()

        if exists:
            edit_obj = models.UserProfile.objects.get(username=username)
        else:
            edit_obj = UserProfile.objects.create_user(username=username)

        edit_obj.username = form_data['username']
        edit_obj.set_password(form_data['password'])
        edit_obj.gender = form_data['gender']
        edit_obj.email = form_data['email']
        edit_obj.address = form_data['address']
        edit_obj.mobile = form_data['mobile']
        edit_obj.image = form_data['image']
        edit_obj.save()

        if exists:
            meta = {
                "msg": "用户信息修改成功!",
                "status": 200
            }
        data = {
            "user_id": edit_obj.id,
            "username": edit_obj.username,
            "mobile": edit_obj.mobile,
            "exists": exists
        }
        return JsonResponse({
            'meta': meta,
            'data': data
        })

    if request.method == 'GET':
        data = {}
        meta = {
            "msg": "新用户进入用户注册界面!",
            "status": 200
        }
        form_data = json.loads(request.body.decode("UTF-8"))
        if form_data is not None:
            username = form_data['username']
            exists = UserProfile.objects.filter(username=username).exists()

            if exists:
                edit_obj = models.UserProfile.objects.get(username=username)
                data.update({"username": username})
                data.update({"password": edit_obj.password})
                data.update({"gender": edit_obj.gender})
                data.update({"email": edit_obj.email})
                data.update({"address": edit_obj.address})
                data.update({"mobile": edit_obj.mobile})
                data.update({"image": str(edit_obj.image)})
                meta = {
                    "msg": "用户信息查询成功!",
                    "status": 200
                }
        return JsonResponse({
            'meta': meta,
            'data': data
        })


@csrf_exempt
def login_view(request):
    form_data = json.loads(request.body.decode("UTF-8"))
    username = form_data['username']
    data = {}
    if request.method == 'POST':
        password = form_data['password']
        try:
            user = authenticate(username=username, password=password)
            if user is not None:
                login(request, user)
                meta = {
                    "msg": "登录成功",
                    "status": 200
                }
                data = {
                    "user_id": user.id,
                    "username": username,
                    "mobile": user.mobile
                }
            else:
                meta = {
                    "msg": "用户名或密码错误",
                    "status": 422
                }
        except:
            meta = {
                "msg": "用户名或密码错误",
                "status": 422
            }
        return JsonResponse({
            'meta': meta,
            'data': data
        })


# 修改超级管理员密码
@csrf_exempt
def change_password(request):
    exists = UserProfile.objects.filter(username='admin').exists()
    if exists:
        user = models.UserProfile.objects.get(username='admin')
        user.set_password('admin')
        user.save()
        print(user.password)
        return HttpResponse("密码修改成功")
    else:
        return HttpResponse("对不起,没有该用户")


# 注销接口
@csrf_exempt
# @api_view(['GET', 'POST'])
def logout_view(request):
    logout(request)
    return redirect('login')

9、修改项目根urls.py

from django.contrib import admin
from django.urls import path, include
from rest_framework import routers
from rest_framework.documentation import include_docs_urls

from apps.users.views import UserProfileViewSet, register_view, login_view, logout_view, change_password

# 生成接口文档使用
router = routers.DefaultRouter()
router.register(r'users', UserProfileViewSet)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include(router.urls)),  # 自动生成接口文档
    path('api-auth/', include('rest_framework.urls')),
    path('docs/', include_docs_urls(title='项目接口文档')),  # 自动生成接口文档
    path('register/', register_view, name='register'),
    path('login/', login_view, name='login'),
    path('logout/', logout_view, name='logout'),
    path('change_password/', change_password, name='change_password'),
]

10、添加配置settings.py

# 请在MIDDLEWARE中增加一行注释
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

# 修改语言和时区
LANGUAGE_CODE = 'zh-hans'
USE_TZ = False
TIME_ZONE = 'Asia/Shanghai'
# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Shanghai'  # 时区
USE_I18N = True
USE_TZ = True
# 接口文档
REST_FRAMEWORK = {
    'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
}
# 所有域名都可以跨域访问
CORS_ORIGIN_ALLOW_ALL = True  

11、使用Postman测试接口

(1)postman使用csrftoken

使用postman时,如果项目开启了csrf防护,需要在请求的header中加入“X-CSRFToken”,
1)header头部分别加入Content-Type(根据实际情况设置)和x-csrf-token,{{csrftoken}如下图:   
在这里插入图片描述

(2)注册接口

{   
	"password": "good",
    "last_login": "",
    "is_superuser": false,
    "username": "good",
    "first_name": "",
    "last_name": "",
    "email": "admin@qq.com",
    "is_staff": true,
    "is_active": true,
    "date_joined": null,
    "nick_name": "",
    "birthday": null,
    "gender": "男",
    "address": null,
    "mobile": null,
    "image": null
}

在这里插入图片描述

(3)登录接口

在这里插入图片描述
在这里插入图片描述

七、案例(公告管理)

1、创建一个读写 API 来访问我们项目中用户的信息。

(1)新建一个应用notices

manage.py@myapi_project > startapp notices

(2)将notices拖入到apps中

在这里插入图片描述

(3)在myapi_project\myapi_project\settings.py中增加一行。

INSTALLED_APPS = [  
	  'apps.notices.apps.NoticesConfig',
]  

2、编辑model

myapi_project\apps\notices\models.py

from datetime import datetime
from django.db import models
from apps.users.models import UserProfile


class BaseModel(models.Model):
    add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")

    class Meta:
        abstract = True


class Notice(BaseModel):
    title = models.CharField(max_length=50, verbose_name="公告标题", null=True, unique=True, default="")
    content = models.CharField(max_length=500, verbose_name="公告内容", null=True, blank=True)
    user = models.ForeignKey(UserProfile, on_delete=models.CASCADE, verbose_name="发布人")

    class Meta:
        verbose_name = "公告信息"
        verbose_name_plural = verbose_name


3、同步数据库

makemigrations
migrate

生成的数据库表结构如下:
在这里插入图片描述

4、在apps/notices下新建一个serializers.py:

from rest_framework import serializers

from apps.notices.models import Notice


class NoticeSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Notice
        fields = ['id', 'add_time', 'title', 'content', 'user_id']

5、修改apps/notices/views.py

http://127.0.0.1:8000/notices/
在这里插入图片描述
http://127.0.0.1:8000/notices/1/
在这里插入图片描述
http://127.0.0.1:8000/add_notice/
在这里插入图片描述
在这里插入图片描述
http://127.0.0.1:8000/delete_notice/1/
在这里插入图片描述

http://127.0.0.1:8000/edit_notice/
在这里插入图片描述
在这里插入图片描述

八、drf-yasg: 从Django REST框架代码自动生成真正的Swagger/openapi2.0模式

1、安装

首选的安装方法直接来自pypi:

pip install -U drf-yasg

另外,如果您想使用built-in验证机制(参见4。验证),您需要安装一些额外的要求:

pip install -U drf-yasg[validation]

2、In settings.py:

INSTALLED_APPS = [
   ...
   'drf_yasg',
   ...
]

3、In urls.py:

from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi

schema_view = get_schema_view(
    openapi.Info(
        title="平台API文档",
        default_version='v1',
        description="Welcome to ***",
        # terms_of_service="https://www.tweet.org",
        # contact=openapi.Contact(email="demo@tweet.org"),
        # license=openapi.License(name="Awesome IP"),
    ),
    public=True,
    # 我也添加了此处但是还是有权限问题
    permission_classes=(permissions.AllowAny,),
)


urlpatterns = [
    # 对测试人员更友好
    path('doc/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
    # 对开发人员更友好
    path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),

   ...
]

4、文档地址

http://127.0.0.1:8000/doc/
在这里插入图片描述
http://127.0.0.1:8000/redoc/
在这里插入图片描述

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
本季课程把开发知识拆解到项目里,让你在项目情境里学知识。这样的学习方式能让你保持兴趣、充满动力,时刻知道学的东西能用在哪、能怎么用。平时不明白的知识点,放在项目里去理解就恍然大悟了。  一、融汇贯通本视频采用了前后端分离的开发模式,前端使用Vue.js+Element UI实现了Web页面的呈现,后端使用Python 的Django REST Framework框架实现了数据访问的接口,前端通过Axios访问后端接口获得数据。在学习完本章节后,真正理解前后端的各自承担的工作。 二、贴近实战本课程为学生信息管理系统课程:Vue3 + Vite + ElementPlus + Django REST Framework项目实战 本季课程主学生信息管理系统V5.0,内容包含:Django REST framework安装和项目初始化、数据的序列化、ViewSet视图集、DefaultRouter路由类、django-filter实现过滤、rest framework实现查找、rest framework实现分页、npm的使用、使用Vite构建vue3项目、Package.json解析、ElementPlus安装和应用、vue-router实现路由、使用Vuex的store对象、后台管理系统主界面的布局、axios组件的安装和请求、axios请求的模块化、请求拦截器和响应拦截器、使用el-select实现联级下拉、使用cascader实现联级选择、vue表单的验证、实现学生信息的添加、修改和删除、实现文件的上传等等功能 本案例完整的演示了项目实现过程,虽然不复杂,但涉及的内容非常多,特别是前后端交互的时候,有诸多的坑等着你去踩,好在王老师全程代码呈现,带着大家一起填坑,大大提高学习效率的同时,也培养了大家良好的代码习惯,希望大家一起跟着王进老师学习Python开发。三、后续课程预告:Vue和Django REST Framework实现JWT登录认证 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值