C:\Users\windows\Downloads\111\dev08\dev08\urls.py
"""dev08 URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('projects/', include('projects.urls')),
path('interfaces/', include('interfaces.urls')),
]
C:\Users\windows\Downloads\111\dev08\dev08\settings.py
"""
Django settings for dev08 project.
Generated by 'django-admin startproject' using Django 3.2.5.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = 'django-insecure-n0emb&jl!nt1t(z3&uz2oei-+n2e74z=53wfo*8t-g4czv5m4)'
DEBUG = True
ALLOWED_HOSTS = []
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'projects',
'users',
'interfaces',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'dev08.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'dev08.wsgi.application'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
},
'db': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
},
}
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = True
STATIC_URL = '/static/'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
REST_FRAMEWORK = {
}
C:\Users\windows\Downloads\111\dev08\interfaces\urls.py
"""
-------------------------------------------------
-------------------------------------------------
"""
from django.urls import path
from . import views
urlpatterns = [
path('<int:pk>/', views.InterfacesDetailView.as_view()),
path('', views.InterfacesView.as_view()),
]
C:\Users\windows\Downloads\111\dev08\projects\urls.py
"""
-------------------------------------------------
-------------------------------------------------
"""
from django.urls import path
from . import views
urlpatterns = [
path('<int:pk>/', views.ProjectDetailView.as_view()),
path('', views.ProjectView.as_view()),
]
C:\Users\windows\Downloads\111\dev08\interfaces
from django.db import models
from utils.base_model import BaseModel
class Interfaces(BaseModel):
name = models.CharField(unique=True, verbose_name='接口名称', help_text='接口名称', max_length=15)
tester = models.CharField(verbose_name='接口测试人员', help_text='接口测试人员', max_length=13)
projects = models.ForeignKey('projects.Projects', on_delete=models.CASCADE,
related_name='interfaces'
)
class Meta:
db_table = 'tb_interfaces'
verbose_name = '接口表'
verbose_name_plural = '接口表'
ordering = ['id']
def __str__(self):
return f"<{self.name}>"
C:\Users\windows\Downloads\111\dev08\projects\models.py
from django.db import models
from utils.base_model import BaseModel
class Interfaces(BaseModel):
name = models.CharField(unique=True, verbose_name='接口名称', help_text='接口名称', max_length=15)
tester = models.CharField(verbose_name='接口测试人员', help_text='接口测试人员', max_length=13)
projects = models.ForeignKey('projects.Projects', on_delete=models.CASCADE,
related_name='interfaces'
)
class Meta:
db_table = 'tb_interfaces'
verbose_name = '接口表'
verbose_name_plural = '接口表'
ordering = ['id']
def __str__(self):
return f"<{self.name}>"
C:\Users\windows\Downloads\111\dev08\interfaces\serializers.py
"""
-------------------------------------------------
-------------------------------------------------
"""
from rest_framework import serializers
from rest_framework import validators
from .models import Interfaces
from projects.models import Projects
class InterfaceModelSerializer(serializers.ModelSerializer):
projects_id = serializers.PrimaryKeyRelatedField(queryset=Projects.objects.all())
class Meta:
model = Interfaces
fields = ('id', 'name', 'projects_id')
extra_kwargs = {
'name': {
'min_length': 3
}
}
def validate(self, attrs):
return attrs
def create(self, validated_data):
projects = validated_data.pop('projects_id')
validated_data['projects'] = projects
instance = super().create(validated_data)
return instance
C:\Users\windows\Downloads\111\dev08\projects\serializers.py
"""
-------------------------------------------------
-------------------------------------------------
"""
from rest_framework import serializers
from rest_framework import validators
from .models import Projects
from interfaces.models import Interfaces
class InterfaceSeri(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(min_length=2, max_length=20)
tester = serializers.CharField(read_only=True)
def validate_project_name(value: str):
if '项目' not in value:
raise serializers.ValidationError("项目名称中未包含“项目”关键字")
class ProjectSerializer(serializers.Serializer):
"""
为什么需要使用序列化器类?
1.可以实现序列化输出操作
2.可以实现反序列化输入操作
3.数据校验操作
4.数据操作
如何定义序列化器类?
1.一般在子应用中创建serializers.py文件,用于定义序列化器类
2.必须继承Serializer类或者Serializer的子类
3.序列化输出的参数名要与创建的序列化器字段(序列化器类中的类属性)名称保持一致
4.序列化输出的参数类型要与创建的序列化器字段(序列化器类中的类属性)类型保持一致
5.序列化器字段必须得为Field子类
6.序列化器字段类型种类?
a.IntegerField -> int
b.CharField -> str
c.BooleanField -> bool
如何使用序列化器类实现序列化输出操作?
1.先创建序列化器对象
2.在创建序列化器对象时,使用instance创建参数
3.序列化操作的对象有四种?
a.模型对象 -- 无需传递many关键字参数
b.普通对象 -- 无需传递many关键字参数
c.查询集 -- 必须传递many=True
d.嵌套普通对象的列表 -- 必须传递many=True
4.使用创建序列化器对象.data属性获取序列化之后的数据(字典或者嵌套字典的列表)
定义的序列化器字段以及常用参数?
1.默认定义的序列化器字段,都会进行序列化输出
2.定义的序列化器字段名称和类型必须与模型类中的字段名或者普通对象的属性名保持一致
3.公共的参数
a.label、help_text与ORM模型类中的verbose_name、help_text参数一致
b.如果当前字段仅仅只需反序列化输入,可以设置write_only=True
c.如果当前字段仅仅只需序列化输出,可以设置read_only=True
d.required指定某个字段是否为必传字段,默认required=True,默认定义的字段为必传字段
e.如果required=False,那么该字段为可选参数,如果前端未传递,那么序列化输出时不会输出,如果前端有传递,那么序列化输出时会输出
f.如果同时设置required=False和write_only=True,那么write_only=True参数会被忽略
g.如果同时设置required=False和read_only=True,那么read_only=True参数会被忽略
h.default给某个字段指定默认值
i.如果给某个字段指定了默认值,那么前端未传递该字段,会把该字段作为输入值,如果指定了该字段,那么会使用该字段作为输入值
j.某个字段不同同时指定default=True, required=True
k.allow_null指定某个字段是否允许传递null值,默认不允许传递null值,如果指定了allow_null=True,那么允许该值传递null
l.error_messages可以定制字段的具体错误提示信息,该参数必须传递字典类型,将具体校验规则名称作为key,把报错提示字符串作为value
m.validators参数指定自定义校验规则(校验器),为列表类型
n.可以使用DRF提供的UniqueValidator对字段是否唯一性进行校验,queryset参数为所有模型对象的查询集,message指定校验失败的错误提示信息
o.可以在序列化器类外定义校验函数,作为validators参数值列表中的元素(使用校验函数名)
p.定义校验函数,必须接受一个参数(待校验的值),如果校验不通过,必须得抛出serializers.ValidationError异常,
可以指定具体的报错字符串作为ValidationError参数,如果校验通过,无需返回
q.某个字段的校验顺序:当前字段的类型 -> 当前字段的所有校验规则项进行校验
(段的所有校验关键字参数、validators参数列表中的所有校验规则一般都会被校验) -> 单字段校验方法 -> 多字段的联合校验
r.可以在类里面对单字段进行校验
》单字段校验的方法名称必须为validate_该字段名称
》仅仅只有当定义的字段上所有校验规则通过的情况下,才会在类里面调用对单字段进行校验的方法
4.CharField类型字段
a.默认该字段不允许传递空空字符串
b.可以指定allow_blank=True,那么允许该字段传递空字符串
c.max_length指定最大长度字节数,min_length指定最小字节长度
d.如果前端传递该字段值为str, int, float,会自动转化为字符串类型(不会对类型进行校验),如果传递其他类型,
会校验失败(invalid)
e.trim_whitespace参数默认为True,会自动清空左右两侧的空格
5.IntegerField类型字段
a.max_value参数指定最大值
c.min_value参数指定最小值
6.DateTimeField类型字段
a.format指定格式化字符串,
如何使用序列化器类实现反序列化输入操作?
1.在创建序列化器对象时,使用data传递待校验的参数(需要接收json转化为字典之后的数据)
2.传递给data的参数,必须为待校验的字典数据
3.必须得调用序列化器对象.is_valid()方法,才会开始对数据进行校验
4.仅仅只有调用is_valid()方法之后,才能通过序列化器对象.errors属性获取校验的结果(一般字典类型)
5.默认定义的序列化器字段,都会进行反序列化输入(前端都必须得传递),也会进行序列化输出操作
6.往往把前后向后端发起请求的过程称为写(write),也称为反序列化输入
7.往往把后端向前端响应数据的过程称为读(read),也称为序列化输出
8.如果当前字段仅仅只需反序列化输入,可以设置write_only=True
9.如果当前字段仅仅只需序列化输出,可以设置read_only=True
10.可以在调用序列化器对象.is_valid()方法时,指定raise_exception=True,那么校验不通过时,会抛出异常,否则不会抛出异常
11.如果未调用序列化器对象.is_valid()方法,那么是不会开始校验的,
所以不能调用序列化器对象的errors属性(获取错误提示字典信息)、data属性(序列化输出的数据)、validated_data属性(获取校验通过的数据)
序列化器类中的校验方法?
1.单字段的校验方法
》方法名:validate_字段名称()
》如果校验不通过,必须抛出serializers.ValidationError异常
》如果校验通过,必须将校验通过之后的数据返回
2.多字段联合校验方法
》方法名为:validate()
》会接收上述所有字段校验通过之后的字典
》如果校验不通过,必须抛出serializers.ValidationError异常
》如果校验通过,必须将校验通过之后的数据返回
某个字段的校验顺序:
先调用to_internal_value方法(
for 单字段 in 所有反序列化输入字段的列表:
当前字段的类型 -> 当前字段的所有校验规则项进行校验 -> 单字段校验方法
)
最后再调用validate()方法 ,该方法返回的数据就为序列化器对象.validated_data
关联字段序列化?
1.如果需要获取关联表的数据,需要定义RelatedField类型的字段
2.字段名称有要求
》如果是父表获取从表的数据,那么关联字段的名称默认为从表模型类名小写_set
》如果在定义从表模型类外键字段时,指定了related_name参数,那么elated_name参数值与关联字段的名称一致
3.如果关联字段为PrimaryKeyRelatedField,那么操作的关联表的主键id
》如果需要进行反序列化输入(对数据进行校验),那么必须指定queryset参数,为关联表的查询集对象
》如果不需要进行反序列化输入,那么必须指定read_only=True
》如果关联字段的数据有多条,那么必须指定many=True
4.如果关联字段为StringRelatedField,那么会将关联模型类中定义的__str__方法返回值作为输出内容
》StringRelatedField默认指定了read_only=True
》如果关联字段的数据有多条,那么必须指定many=True
5.如果关联字段为SlugRelatedField,那么操作的关联表的特定字段
》如果需要进行反序列化输入(对数据进行校验),那么必须指定queryset参数,为关联表的查询集对象,同时关联字段最好要有唯一约束
》如果不需要进行反序列化输入,那么必须指定read_only=True
》如果关联字段的数据有多条,那么必须指定many=True
6.由于定义的任意序列化器类最终为Field子类,所有可以作为任意一个序列化器类中的字段来使用
》
序列化器类与模型类的关系?
1.这两个类高度相似
2.当模型类中字段非常多时,定义序列化器类就相当麻烦
3.可以定义模型序列化器,来自动将模型类中的字段生成序列化器中的字段
》必须继承serializers.ModelSerializer父类
》必须在Meta内部类中,使用model类属性关联一个模型类
》需要在在Meta内部类中,使用fields指定模型类中哪些字段需要生成序列化器字段
》如果指定fields = '__all__',那么会将模型类中的所有字段生成序列化器字段
》在生成的字段中,会将主键id设置为IntegerField类型,同时会自动指定read_only=True
》会将DateTimeField类型中有添加auto_now_add或auto_now参数,会自动指定read_only=True
》会将unique=True的字段,自动生成validators=中UniqueValidator唯一约束
》null=True -> allow_null=True
blank=True -> allow_blank=True
default='xxx' -> required=False
》如果只需要将模型类中某些字段生成序列化器字段,可以将这些字段组成元组,传递给fields
》exclude与fields功能相反
》可以在模型序列化器类中定义模型类中的字段(会覆盖自动生成的字段)
》fields类属性,如果指定的说元组类型,那么必须包含所有的序列化器字段(模型类中的、模型类外的)
》如果fields为'__all__'或者exclude,那么无需指定模型类外的字段
》模型序列化器类自带create、update方法,一般无需重写
》可以在Meta内部类中的extra_kwargs类属性中对模型类中自动生成的字段进行修改
将模型类字段名作为key,把具体要修改的参数key-value字典作为值
不同方式定义的序列化器对象的区别?
1.如果在创建序列化器对象时,仅仅只传递instance参数,那么当前只会进行序列化输出操作,不可能进行反序列化输入,
不可以调用序列化器对象的save()的方法
2.如果在创建序列化器对象时,仅仅只传递data参数,那么在调用is_valid()方法后会进行反序列化输入,
同时在调用save方法时,会自动调用序列化器对象的create方法(用于数据的创建操作),会把create方法返回的数据作为
序列化输出的数据源
3.如果在创建序列化器对象时,仅仅只传递data参数,对数据进行校验之后,调用is_valid()方法后,直接调用data属性(未调用save方法),
会把校验通过的数据作为序列化输出的数据源,如果校验通过的数据中有相应的数据,同时该字段需要输出,那么输出的数据中才会有该字段
4.如果在创建序列化器对象时,同时传递instance和data参数,那么在调用save方法时,会自动调用序列化器对象的update方法(用于数据的更新操作),
会把update方法返回的数据作为序列化输出的数据源
"""
id = serializers.IntegerField(max_value=10000, min_value=1,
label='项目id', help_text='项目id',
read_only=True)
name = serializers.CharField(max_length=20, label='项目名称', min_length=3,
help_text='项目名称',
validators=[
validators.UniqueValidator(queryset=Projects.objects.all(), message='项目名称已存在'),
validate_project_name,
],
error_messages={'required': '项目名称为必传字段', 'null': '项目名称不能为null值',
'max_length': '项目名称不能超过20个字节'})
is_execute = serializers.BooleanField()
leader = serializers.CharField()
create_time = serializers.DateTimeField(format='%Y年%m月%d日 %H:%M:%S', read_only=True)
xxx = serializers.CharField(write_only=True)
token = serializers.CharField(read_only=True)
def validate_name(self, value: str):
if not value.startswith('x'):
raise serializers.ValidationError('项目名称必须以“x”开头')
return value
def validate(self, attrs):
if len(attrs.get('name')) <= len(attrs.get('leader')):
raise serializers.ValidationError('项目名称的长度不能小于或等于项目负责人名称长度')
attrs['name'] = attrs.get('name').upper()
attrs.pop('xxx')
return attrs
def create(self, validated_data):
obj = Projects.objects.create(**validated_data)
obj.token = 'dfshofshfo gfhfshfosfsfhsof sf'
return obj
def update(self, instance, validated_data):
instance.name = validated_data.get('name') or instance.name
instance.leader = validated_data.get('leader') or instance.leader
instance.is_execute = validated_data.get('is_execute') or instance.is_execute
instance.desc = validated_data.get('desc') or instance.desc
instance.save()
return instance
class UsersSerializer(serializers.Serializer):
username = serializers.CharField()
score = serializers.IntegerField()
gender = serializers.BooleanField()
class ProjectModelSerializer(serializers.ModelSerializer):
name = serializers.CharField(max_length=20, label='项目名称', min_length=3,
help_text='项目名称',
validators=[
validators.UniqueValidator(queryset=Projects.objects.all(), message='项目名称已存在'),
validate_project_name,
],
error_messages={'required': '项目名称为必传字段', 'null': '项目名称不能为null值',
'max_length': '项目名称不能超过20个字节'})
class Meta:
model = Projects
fields = ('id', 'name', 'leader')
extra_kwargs = {
'name': {
'min_length': 3,
'label': '项目名称',
'validators': [
validators.UniqueValidator(queryset=Projects.objects.all(), message='项目名称已存在'),
validate_project_name,
],
'error_messages': {'required': '项目名称为必传字段', 'null': '项目名称不能为null值',
'max_length': '项目名称不能超过20个字节'}
}
}
def validate(self, attrs):
if len(attrs.get('name')) <= len(attrs.get('leader', '')):
raise serializers.ValidationError('项目名称的长度不能小于或等于项目负责人名称长度')
attrs['name'] = attrs.get('name').upper()
return attrs
C:\Users\windows\Downloads\111\dev08\projects\views.py
import json
from django.http import HttpResponse, JsonResponse, Http404
from django.views import View
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import Projects
from . import serializers
class ProjectView(APIView):
"""
可以继承DRF中的APIView视图
1.APIView为View的子类
2.每一个实例方法的第二个参数为Request对象
3.Request在Django的HttpRequest之上做了拓展
》与HttpRequest中解析参数的方法完全兼容
》解析查询字符串参数:GET -> query_params
》解析application/x-www-form-urlencoded参数:POST -> data
》解析application/json参数:body -> data
》解析multipart/form-data参数:POST、FILES -> data
4.提供了认证、授权、限流功能
5.返回DRF中的Response
》为HttpResponse子类
》可以自动根据请求头中的Accept字段,自动返回相应格式的数据
"""
def get(self, request):
qs = Projects.objects.all()
serializer = serializers.ProjectSerializer(instance=qs, many=True)
return Response(serializer.data)
def parse(self, request):
msg = {
'status': '1',
'msg': '参数有误'
}
content_type = request.headers.get('Content-Type')
if content_type == 'application/json':
try:
return json.loads(request.body, encoding='utf-8')
except Exception as e:
return JsonResponse(msg, status=400)
elif content_type == 'application/x-www-form-urlencoded':
return request.POST
else:
pass
def render(self, request):
pass
def post(self, request):
serializer = serializers.ProjectModelSerializer(data=request.data)
try:
serializer.is_valid(raise_exception=True)
except:
return JsonResponse(serializer.errors, status=400)
serializer.save()
return JsonResponse(serializer.data, json_dumps_params={'ensure_ascii': False})
class ProjectDetailView(APIView):
primary_key_name = 'pk'
def get_object(self):
try:
pk = self.kwargs.get(self.primary_key_name)
return Projects.objects.get(pk=pk)
except Exception:
raise Http404
def get(self, request, pk):
obj = self.get_object()
serializer = serializers.ProjectSerializer(instance=obj)
return JsonResponse(serializer.data, json_dumps_params={'ensure_ascii': False})
def put(self, request, pk):
obj = self.get_object()
serializer = serializers.ProjectSerializer(instance=obj, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return JsonResponse(serializer.data, json_dumps_params={'ensure_ascii': False})
def delete(self, request, pk):
obj = self.get_object()
obj.delete()
return HttpResponse(None, status=204)
C:\Users\windows\Downloads\111\dev08\interfaces\views.py
import json
from django.http import HttpResponse, JsonResponse
from django.views import View
from .models import Interfaces
from . import serializers
class InterfacesView(View):
def get(self, request):
"""
GET /projects/ 获取所有的项目数据(将所有的项目数据以json数组形式返回)
:param request:
:return:
"""
qs = Interfaces.objects.all()
serializer = serializers.InterfaceModelSerializer(instance=qs, many=True)
return JsonResponse(serializer.data, safe=False, json_dumps_params={'ensure_ascii': False})
def post(self, request):
msg = {
'status': '1',
'msg': '参数有误'
}
try:
python_dict = json.loads(request.body, encoding='utf-8')
except Exception as e:
return JsonResponse(msg, status=400)
serializer = serializers.InterfaceModelSerializer(data=python_dict)
try:
serializer.is_valid(raise_exception=True)
except:
return JsonResponse(serializer.errors, status=400)
serializer.save()
return JsonResponse(serializer.data, json_dumps_params={'ensure_ascii': False})
class InterfacesDetailView(View):
def get(self, request, pk):
try:
obj = Projects.objects.get(id=pk)
except Exception:
return JsonResponse({
'msg': '参数有误',
'status': '1'
}, status=400)
serializer = serializers.ProjectSerializer(instance=obj)
return JsonResponse(serializer.data, json_dumps_params={'ensure_ascii': False})
def put(self, request, pk):
msg = {
'status': '1',
'msg': '参数有误'
}
try:
python_dict = json.loads(request.body, encoding='utf-8')
except Exception as e:
return JsonResponse(msg, status=400)
try:
obj = Projects.objects.get(id=pk)
except Exception:
return JsonResponse({
'msg': '参数有误',
'status': '1'
}, status=400)
serializer = serializers.ProjectSerializer(instance=obj, data=python_dict)
serializer.is_valid(raise_exception=True)
serializer.save()
return JsonResponse(serializer.data, json_dumps_params={'ensure_ascii': False})
def delete(self, request, pk):
try:
obj = Projects.objects.get(id=pk)
except Exception:
return JsonResponse({
'msg': '参数有误',
'status': '1'
}, status=400)
obj.delete()
return HttpResponse(None, status=204)
|