项目介绍
我习惯由项目开始整理所学, 本次将构建一个项目, 介绍:
- 本项目为某软件配置分享后端
- 用户可以匿名上传/下载对软件的个性化配置
- 用户可以删除自己上传的配置文件
- 用户可以对配置进行点赞
- 本软件有PC/Android端, 因此将使用json传输
项目环境
- Python 3.8,1
- Django 3.0.4
- Django restframework-3.11.0
- Markdown-3.2.1
- Django-filter-2.2.0
0x00 开始
- 安装Drf, 前往Django REST framework安装所有依赖
pip install djangorestframework
pip install markdown # Markdown support for the browsable API.
pip install django-filter # Filtering support
并把 rest_framework
加入 INSTALLED_APPS
INSTALLED_APPS = [
...
'rest_framework',
]
-
初始化项目, 我的项目结构如下
-
在
settings.py
内加入以下代码
import sys
sys.path.insert(0, BASE_DIR)
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
sys.path.insert(0, os.path.join(BASE_DIR, 'extra_apps'))
apps
用于放所有的app, extra_apps
用于储存第三方包, 特别是可能需要自己修改源码的包, 例如jwt, 这样此包不会被安装入依赖
0x02数据库实现
数据库包含两张表, 一张为记录用户, 另一张为记录配置文件, 具体如下
import time
from django.db import models
class User(models.Model):
sign = models.CharField(max_length=32, verbose_name='签名')
username = models.CharField(max_length=20, verbose_name="用户名")
create_time = models.IntegerField(default=time.time, blank=True, verbose_name='创建时间')
class Meta:
verbose_name = '用户'
verbose_name_plural = verbose_name
def __str__(self):
return f"用户: {self.username} 签名: {self.sign}"
class Config(models.Model):
uid = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.DO_NOTHING)
nickname = models.TextField(max_length=32, default='匿名', verbose_name="作者")
title = models.TextField(verbose_name='标题')
desc = models.TextField(verbose_name='描述')
config = models.TextField(default='{}', verbose_name='配置文件')
user_like = models.ManyToManyField(User, blank=True, related_name='user_like', verbose_name='点赞数')
create_time = models.IntegerField(default=time.time, blank=True, verbose_name='创建时间')
last_download = models.IntegerField(default=time.time, blank=True, verbose_name='最后下载时间')
class Meta:
verbose_name = '配置'
verbose_name_plural = verbose_name
def __str__(self):
return f'昵称: {self.nickname}\n' \
f'标题: {self.title}\n' \
f'描述: {self.desc}\n' \
f'时间: {self.create_time}\n'
为了防止用户伪造username而去删除其他人的配置文件, 这里引用sign对用户进行验证, 此次简单使用md5(username + “123456”)
使用python manage.py makemigrations
和python manage.py migrate
使数据库生效
0x03 编写视图
首先我们先添加一些测试数据, 再根目录下创建文件test.py
, 填写以下内容
import os
import sys
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DrfStudy.settings')
pwd = os.path.dirname(os.path.realpath(__file__))
sys.path.append(pwd)
import django
django.setup()
from apps.configs.models import User, Config
from apps.configs.utils import md5
user = User.objects.get_or_create(username='admin', sign=md5('admin123456'))
for i in range(100):
Config.objects.get_or_create(
user=user[0],
nickname="管理员",
title=f"测试配置{i}",
desc=f"测试所加配置{i}",
config="{}",
)
创建好100条数据库数据后, 接下来我们drf的APIView
来返回数据, 视图如下
from rest_framework.views import APIView
from rest_framework.response import Response
import rest_framework.status as status
from .models import Config
class ConfigView(APIView):
def get(self, request):
config_list = Config.objects.all() # 取所有数据
response = [] # 构造返回
for config in config_list: # 遍历数据返回数据
response.append({
'nickname': config.nickname,
'title': config.title,
'desc': config.desc,
'config': config.config,
'user_like': config.user_like.count(),
'last_download': config.last_download
})
return Response(response, status=status.HTTP_200_OK)
在url.py
编写如下
from django.contrib import admin
from django.urls import path
from apps.configs.views import ConfigView
urlpatterns = [
path('admin/', admin.site.urls),
path('configs/', ConfigView.as_view())
]
运行浏览器访问http://127.0.0.1:8000/configs/
成功了
0x04 提交数据
现在用户可以通过post来上传一些数据, 于是我们在apiview里添加post视图
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Config
from .utils import md5
from .models import User
from .serializers import ConfigListSerializer
class ConfigView(APIView):
def post(self, request):
form = request.POST # 取出post表单
username = form['username']
sign = form['sign']
nickname = form['nickname']
title = form['title']
desc = form['desc']
config = form['config'] # 提取表单内容
if username and nickname and title and desc and config: # 验证表单数据
if md5(username + "123456") != sign: # 验证签名
return Response({"error": "用户验证错误"}, status=status.HTTP_400_BAD_REQUEST)
user = User.objects.get_or_create(username=username, sign=sign)[0] # 获取或创建用户
Config.objects.get_or_create( # 存储配置
user=user,
nickname=nickname,
title=title,
desc=desc,
config=config,
)
return Response({"data": "创建完成"}, status=status.HTTP_201_CREATED)
return Response({"error": "表单错误"}, status=status.HTTP_400_BAD_REQUEST)
尝试使用postman发送数据, 成功了, 而且显示了出来
0x05 总结
最后我们发现一个问题, 不管在get还是在post里, 我们花费了大量篇幅取定义表单, 取验证字段, 有没有什么好的方法快速验证表单然后储存数据呢? 而且如此写法, 和传统Django没有什么区别嘛, 下一章Serializer将会体现出drf的强大