自动化-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']





#增删改查

 

 

 

  

  

 

 

 

 

 

  

最后一个半小时内容讲解以上代码,后续补充详细解析

posted @ 2020-12-26 19:43  心淡灬人懒  阅读(184)  评论(0)    收藏  举报