自动化-day16-Django3(数据库进阶(多对多、一对多、一对一、配置数据库路由)、fvb与cvb、中间件)
1、数据库多对多关系,一对一关系,配置多数据库路由
a、创建表之间的多对多关系需使用models.ManyToManyField方法
class Teacher(models.Model): name = models.CharField(max_length=50) def __str__(self): return self.name class Meta: db_table = 'teacher' class Student(models.Model): name = models.CharField(max_length=50,verbose_name='学生姓名') teacher = models.ManyToManyField(Teacher,verbose_name='老师') def __str__(self): return self.name class Meta: db_table = 'student'
表创建之后,在数据库中除了生成student、teacher两张表之外,还会自动生成student_teacher表来储存两张表数据的关系。

可以使用如下方法新增表数据及新增、取消关联
#新增多对多的关系数据 #新增student表数据,并实例化 stu_creat = models.Student.objects.create(name = '444444') #存在就get,不存在就创建(返回数据为元组,两个元素,分别为数据、状态) stu,status = models.Student.objects.get_or_create(name ='444444') stu.teacher.add(1) #该student数据关联teacher表id=1的数据 stu.teacher.add(2) #该student数据关联teacher表id=2的数据 stu.teacher.remove(1) #删除关系中的一条 print(stu.teacher.all()) #查看关联该学生的所有老师 teacher = stu.teacher.get(id=1)
反向查询:由于在teacher表没有创建存储与student表关联的字段,因此如果想通过teacher表查询student的信息,需要用到<表名>.set方法来反向查询
#反向查询 teacher,status= models.Teacher.objects.get_or_create(name='马老师') print(teacher.student_set.all())#查询所有与该数据关联的所有数据 # print(teacher.student_set.remove())#删除与该数据关联的所有数据 # print(teacher.student_set.add())#新增与原表数据关联 print(teacher.student_set.filter(name='444444'))#根据条件查询,可以返回多条数据 print(teacher.student_set.create(name='55555'))#根据条件查询,可以返回多条数据
自关联:当表中数据需要关联本表中的其他数据时,可以使用以下方法
class Case(models.Model): name = models.CharField(max_length=50) url = models.CharField(max_length=50) method = models.CharField(max_length=50) parmam = models.CharField(max_length=50) requiet_case = models.ForeignKey('self',on_delete=models.PROTECT,verbose_name='依赖用例',null=True,blank=True) #requiet_case依赖于本表其他用例,数据库可以为空,admin页面可以为空
b、创建表之间的多对多关系需使用models.OneToOneField方法
class Account(models.Model): balance = models.IntegerField(verbose_name='余额',default=0) class Meta: db_table='account' class User(models.Model): name = models.CharField(max_length=50) account = models.OneToOneField('Account',on_delete=models.CASCADE,verbose_name='账户') # 将User与Account进行1对1关联 def __str__(self): return self.name class Meta: db_table = 'user'
其他方法与多对多关系一致
c、配置多数据库路由及使用※多数据库路由未包括
首先添加数据库信息在setting.py中
DATABASES = { 'default': {#默认数据库 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), }, 'mysql': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'jxz', 'HOST': '118.24.31.40', 'PASSWORD': '123456', 'USER': 'jxz', 'PORT': 3306, } }
之后在总项目下新建database_router,进行数据库路由配置
db_mapper = { 'sqlite':'default', 'new_user':'mysql' } class DatabaseAppsRouter(object): def db_for_read(self, model, **hints): app_label = model._meta.app_label #获取表中的meta信息 if app_label in db_mapper:#若meta.app_label存在于db_mapper中 return db_mapper[app_label]#则返回该数据库 return 'default'#否则返回默认数据库
最后在项目下的__init__.py中重命名MySQLdb
import pymysql #使用MySQL数据库时需使用pymysql方法重命名MySQLdb 以免报错 pymysql.install_as_MySQLdb()
设置完成后,在建表时,使用migrate命令时,需要添加order --database [数据库名称]来明确创建表到哪个数据库

在新项目中可以在表的meta中增加app_label参数来控制访问哪个数据库
而redis数据库需要先安装django_redis模块,之后在catch中配置
CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/0", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"max_connections": 100}, "PASSWORD": "123456", # 密码 } }, "redis2": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/1", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"max_connections": 100, 'decode_responses': True}, "PASSWORD": "123456", # 密码 } } } # redis配置
使用redis数据库时需先获得redis连接
r = django_redis.get_redis_connection('redis数据库名称') r.set() r.get()
2、fvb(方法类接口)与cvb(class类接口)
fvb与cvb表示写接口的方法不同,之前写的接口都为fvb模式,即函数类接口。
cvb,即class类接口在使用时需使用as_view()方法来将cvb方法转换为接口

3、中间件
中间件处于客户请求与后端处理之间,即先于后端拿到用户请求,先于客户端拿到请求结果。根据这一特性,可以将中间件用于权限验证、接口调用次数统计等需要优先进行校验的情况。

中间件在settings.py中的middleware中进行设置,接受请求是从上至下依次加载,返回结果时从下至上依次加载

from django.middleware.common import MiddlewareMixin from django.shortcuts import HttpResponse from user.models import Interface class TestMiddleWare(MiddlewareMixin): def process_request(self,request): #/pay path = request.path_info.replace('/','',1) #pay interface = Interface.objects.filter(url=path) if interface: interface = interface.first() return HttpResponse(interface.response) def process_response(self,request,response): print('process_response') return response def process_exception(self,request,exception): print(exception) return HttpResponse("系统开小差了~") if __name__ == "__main__": pass
※中间件也可以用于一些简单的mock接口开发,即拦截请求后直接返回结果,可以动态调整。避免创建新接口时需要配置及重启等一系列操作
4、纯后台接口开发
a、后台接口开发自定义默认返回参数
在项目下common中自定义公共文件respons.py可以自定义默认返回参数
from django.http.response import JsonResponse def SkyResponse(code=0,msg='操作成功',**kwargs): data = {'code':code,'msg':msg} data.update(**kwargs) return JsonResponse(data,json_dumps_params={'ensure_ascii':False} )
之后在接口中引用respons.py即可
from django.forms import model_to_dict from django.views import View from common.responses import SkyResponse from . import models from django.db.models import Q from django.core.paginator import Paginator from common.const import page_limit class BaseView(View): filter_field = [] search_field = [] model_class = None @property def get_filter_dict(self): filter_dict = {} #{id:1,name:lhy} for field in self.filter_field: value = self.request.GET.get(field) if value: filter_dict[field] = value return filter_dict @property def get_search_obj(self): q_obj = Q()#空白的q对象 search = self.request.GET.get('search') if search: for field in self.search_field: d = {'%s__contains' % field:search} q_obj = q_obj | Q(**d) #这是每次在拼Q对象,生成or条件 return q_obj # 'select * from interface where url like 'aa' or name like 'aa' or response like 'aa'; # models.Interface.objects.filter( Q(url__contains=search) # |Q(name__contains=search)| # Q(response__contains=search) ) def get_page_data(self,obj_list): try: limit = int(self.request.GET.get('limit',page_limit)) #limit = s page = int(self.request.GET.get('page',1)) except: limit = page_limit page = 1 page_obj = Paginator(obj_list,limit) result = page_obj.get_page(page)#分好页的数据 return page_obj,result #page=1,limit=10,page=2 def get(self, request): # get 一条?id=1 筛选 # get 多条?all # get 模糊查询 name=登 # 分页 l = [] interface_query_set = self.model_class.objects.filter(**self.get_filter_dict).filter(self.get_search_obj) page_obj, page_data = self.get_page_data(interface_query_set) for d in page_data: dic = model_to_dict(d) l.append(dic) return SkyResponse(data=l, count=page_obj.count) def delete(self,request): id = request.GET.get('id') if id: query_set = self.model_class.objects.filter(id=id) if query_set: query_set.delete() return SkyResponse() else: return SkyResponse(code=404, msg='id不存在') else: return SkyResponse(code=-1,msg='请传入id') class InterfaceView(BaseView): filter_field = ['id','name'] search_field = ['name','url','response'] model_class = models.Interface class UserView(BaseView): model_class = models.User filter_field = ['id','name'] #增删改查
最后一个半小时内容讲解以上代码,后续补充详细解析

浙公网安备 33010602011771号