Model篇
使用django可快速定义数据结构,博客中使用的数据库是mysql,首先上个例子:
from django.contrib.auth import get_user_model
from django.db import models
from django_mysql.models import Model
class Check(Model):
STATUS_TYPE = (
(0, '未审核'),
(1, '驳回'),
(2, '通过')
)
check_content = models.JSONField()
remark = models.TextField(null=True, blank=True)
file = models.JSONField(null=True, default=[]) # 多个附件信息地址 {"file":[]}
status = models.IntegerField(choices=STATUS_TYPE, default=0)
uid = models.ForeignKey(get_user_model(), models.CASCADE, to_field='username', null=True, blank=True,db_column='uid') # 审核人
reject_reason = models.CharField(max_length=16, null=True, blank=True) # 驳回项
time = models.DateTimeField(auto_now=True) # 时间 审核资料最后更新的时间
字段解释:
定义了一张名为Check的表,在mysql中的表名就是APP_check,假设我的APP是api,那么数据库的表名就是api_check
check表共有 check_content,remark,file,status,uid,reject_reason,time这些属性,这里列举了我常用的字段类型:
check_content :json类型,需要mysql(5.7以上支持)
remark:长文本类型,属性是可以为空,
file:json类型,默认值是空数组[]
status:整型,可选的值从STATUS_TYPE中进行选择,默认值是0,
uid:外键类型,与表get_user_model(就是django中默认生成的auth_user表)中的username进行关联(外键关联项必须是unique),在check表中的字段名字是uid,如果不这样指定会默认生成外键表_uid这样的名字
reject_reason:char类型,长度是16,
time:datetime类型,属性auto_now是每次更新都会自动修改为当前时间,如果只希望这个时间在创建的时候更新,其余操作不变,那么设为属性auto_now_add=True
其他字段类型参考:
Django 模型(Model)字段类型级参数详解_一念永恒-CSDN博客
定义后执行
1. python manage.py makemigrations 记录我们对models.py的所有改动,并且将这个改动迁移到migrations这个文件下生成一个文件例如:0001_initial.py
2. python manage.py migrate 把这些改动作用到数据库也就是执行migrations里面新改动的迁移文件更新数据库,比如创建数据表,或者增加字段属性(注:必须手动去mysql中创建数据库,才能建表,django没有新建数据库的能力)
2. python manage.py sqlmigrate APPNAME 0001_initial 生成对应的sql语句,可以手动去mysql中执行
以上操作可以在MySQL中操作表,但是无法直接使用这些字段与前端进行操作,此时需要用到serializers
serializers篇
serializers的作用是序列化数据结构,可以通过serializers把表的数据结构序列化成json,在前后端之间进行交互,还可以进行数据校验等功能,举一个例子:
from api.models import Check
from rest_framework import serializers
class CheckSerializer(serializers.ModelSerializer):
telephone = serializers.SerializerMethodField()
class Meta:
model = Check
fields = '__all__'
def get_telephone(self, obj):
return obj.uid.telephone
z这里定义了Check表的序列化组件
fields = '__all__'意味着返回所有数据,也可以定义返回部分数据,比如:
fields = (check_content,remark)
如果还想在json中多加些字段(不是本表的字段)一起返回,可以在类中进行定义,比如这里还想返回用户的电话号码,同时定义get_telephone,在函数内返回obj当前Check对象的uid外键的telephone属性。
现在我们定义好数据表了,也可以将数据进行序列化,就要开始写接口了,前端需要对这些数据进行增删该查,涉及到views模块
views篇
django提供两种接口定义的类可以继承,通用视图APIView和视图集ViewSet,
django自己本身就继承了很多子类供使用:
- GenericAPIView是继承自APIView,GenericAPIView肯定在APIView的基础上 封装了一些属性和方法:增加了对于列表视图和详情视图可能用到的通用方法和属性的支持
属性:queryset 设置结果集、serializer_class 设置序列化器、lookup_field 查询指定的对象
方法:get_queryset(self) 返回视图使用的查询集、get_serializer(self,_args, *_kwargs) 返回序列化器对象、get_object(self) 返回详情视图所需的模型类数据对象
-
CreateAPIView:提供post方法处理程序。
ListAPIView:用于只读端点以表示模型实例的集合。提供get方法处理程序。
RetrieveAPIView:用于表示单个模型实例的只读端点。提供get方法处理程序。
DestroyAPIView:用于单个模型实例的仅删除端点。提供delete方法处理程序。
UpdateAPIView:用于单个模型实例的仅更新端点。提供put和patch方法处理程序。
ListCreateAPIView:用于读写端点以表示模型实例的集合。提供get和post方法处理程序。
RetrieveUpdateAPIView:用于读取或更新端点以表示单个模型实例。提供get,put并且patch方法处理。
RetrieveDestroyAPIView:用于读取或删除端点以表示单个模型实例。提供get和delete方法处理程序。
RetrieveUpdateDestroyAPIView:用于读写 - 删除端点以表示单个模型实例。提供get,put,patch和delete方法处理。
以上转自:https://blog.csdn.net/qq_31742423/article/details/83241461
APIView
在APIView中,可以定义get post delete等方法,上例子:这里是资料附件的上传下载和删除接口
支持定义的属性:
authentication_classes列表或元祖,身份认证类
permissoin_classes列表或元祖,权限检查类
# 提测资料审核附件 的上传和下载
class CheckAttachmentAPIView(APIView):
permission_classes = (IsAuthenticated,)
authentication_classes = (BasicAuthentication,
JWTAuthentication,
TokenAuthentication,
SessionAuthentication,
)
def post(self, request, format=None):
files = request.FILES
file = files.get('file')
if file is None:
raise exceptions.NotAcceptable('upload fail, file param not found')
c_id = request.data.get('id', None)
if c_id is None:
raise exceptions.NotAcceptable('upload fail, check id param not found')
else:
try:
check = SubmitCheck.objects.get(id=c_id)
except:
raise exceptions.NotAcceptable('check is not exist')
file_absolute_path = './checkfile/'
try:
os.mkdir(file_absolute_path)
except:
pass
finally:
try:
os.mkdir(file_absolute_path + str(check.id))
except:
pass
file_name = file_absolute_path + str(check.id) + '/' + file.name
file_handler = open(file_name, 'wb')
try:
for chunk in file.chunks(): # 分块写入文件
file_handler.write(chunk)
finally:
file_handler.close()
check_file = check.file # json :[]
check_file.append(file.name)
SubmitCheck.objects.filter(id=c_id).update(file=check_file)
return JSONResponse(data=file.name)
def get(self, request, format=None):
file_name = request.query_params.get('file')
c_id = request.query_params.get('id')
if c_id is None:
raise exceptions.NotAcceptable('download fail, check id param not found')
else:
try:
check = SubmitCheck.objects.get(id=c_id)
except:
raise exceptions.NotAcceptable('check is not exist')
file_absolute_path = './checkfile/'
file_path = file_absolute_path + str(check.id) + '/' + file_name
file_handler = open(file_path, 'rb')
response = FileResponse(file_handler)
response['Content-Type'] = 'application/octet-stream'
response["Access-Control-Expose-Headers"] = 'Content-Disposition'
response['Content-Disposition'] = 'attachment;filename="{}"'.format(file_name)
return response
def delete(self, request, format=None):
file_name = request.data.get('file', None)
c_id = request.data.get('id', None)
if c_id is None or file_name is None:
raise exceptions.NotAcceptable('delete fail, file or id param not found')
else:
try:
check = SubmitCheck.objects.get(id=c_id)
except:
raise exceptions.NotAcceptable('check is not exist')
file_absolute_path = './checkfile/'
file_path = file_absolute_path + str(check.id) + '/' + file_name
os.remove(file_path)
check_file = check.file # json :[]
check_file.remove(file_name)
SubmitCheck.objects.filter(id=c_id).update(file=check_file)
return JSONResponse()
视图集Viewset
Viewset继承(ModelViewSet,其本身定义好增post删delete改patch查get接口,我们只需要指定字段,也可重写方法,自己定义返回的数据结构,上例子:
class CheckViewSet(ModelViewSet):
serializer_class = CheckSerializer
pagination_class = JSONPagination
filter_fields = ('id',)
queryset = Check.objects.all().order_by('-time')
permission_classes = (IsAuthenticated,)
authentication_classes = (BasicAuthentication,
JWTAuthentication,
TokenAuthentication,
SessionAuthentication,
)
def update(self, request, *args, **kwargs):
data = request.data
status = data.get('status', None)
data.pop('uid')
request._full_data = data
return super().update(request, *args, **kwargs)
def create(self, request, *args, **kwargs): # 创建
data = request.data
data['user'] = request.user
data['status'] = 0
request._full_data = data
return super().create(request, *args, **kwargs)
def get_queryset(self):
user = self.request.user
wait_for_me = self.request.query_params.get('wait_for_me', 'False')
if user.is_staff or user.is_superuser:
res = Check.objects.all().filter(user=user).order_by('-time')
return res
在APIView 和ViewSet中,都需要定义serializer_class = CheckSerializer,来知名用的那个序列化组件。
定义好view之后,需要在urls.py中定义路由:
router.register(r'check', CheckViewSet, 'check')
urlpatterns = [
url(r'^submit-check/attachment$', SubmitCheckAttachmentAPIView.as_view())
]
通过上述操作,可以完成数据库的定义、表的创建,通过接口对数据进行简单的增删改查,在下一篇接着介绍,复杂的数据库操作,django还是有点东西