• django数据库操作和中间件


    数据库配置

    django的数据库相关表配置在models.py文件中,数据库的连接相关信息配置在settings.py中

    • models.py相关相关参数配置
    from django.db import models
      
    class userinfo(models.Model):
        name = models.CharField(max_length=30)
        email = models.EmailField()
        memo = models.TextField()

    可用的字段:

    1、models.AutoField  自增列 = int(11)
      如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。
    2、models.CharField  字符串字段
      必须 max_length 参数
    3、models.BooleanField  布尔类型=tinyint(1)
      不能为空,Blank=True
    4、models.ComaSeparatedIntegerField  用逗号分割的数字=varchar
      继承CharField,所以必须 max_lenght 参数
    5、models.DateField  日期类型 date
      对于参数,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
    6、models.DateTimeField  日期类型 datetime
      同DateField的参数
    7、models.Decimal  十进制小数类型 = decimal
      必须指定整数位max_digits和小数位decimal_places
    8、models.EmailField  字符串类型(正则表达式邮箱) =varchar
      对字符串进行正则表达式
    9、models.FloatField  浮点类型 = double
    10、models.IntegerField  整形
    11、models.BigIntegerField  长整形
      integer_field_ranges = {
        'SmallIntegerField': (-32768, 32767),
        'IntegerField': (-2147483648, 2147483647),
        'BigIntegerField': (-9223372036854775808, 9223372036854775807),
        'PositiveSmallIntegerField': (0, 32767),
        'PositiveIntegerField': (0, 2147483647),
      }
    12、models.IPAddressField  字符串类型(ip4正则表达式)
    13、models.GenericIPAddressField  字符串类型(ip4和ip6是可选的)
      参数protocol可以是:both、ipv4、ipv6
      验证时,会根据设置报错
    14、models.NullBooleanField  允许为空的布尔类型
    15、models.PositiveIntegerFiel  正Integer
    16、models.PositiveSmallIntegerField  正smallInteger
    17、models.SlugField  减号、下划线、字母、数字
    18、models.SmallIntegerField  数字
      数据库中的字段有:tinyint、smallint、int、bigint
    19、models.TextField  字符串=longtext
    20、models.TimeField  时间 HH:MM[:ss[.uuuuuu]]
    21、models.URLField  字符串,地址正则表达式
    22、models.BinaryField  二进制
    23、models.ImageField   图片
    24、models.FilePathField 文件

    字段相关参数:

    1、null=True
      数据库中字段是否可以为空
    2、blank=True
      django的 Admin 中添加数据时是否可允许空值
    3、primary_key = False
      主键,对AutoField设置主键后,就会代替原来的自增 id 列
    4、auto_now 和 auto_now_add
      auto_now   自动创建---无论添加或修改,都是当前操作的时间
      auto_now_add  自动创建---永远是创建时的时间
    5、choices
    GENDER_CHOICE = (
            (u'M', u'Male'),
            (u'F', u'Female'),
        )
    gender = models.CharField(max_length=2,choices = GENDER_CHOICE)
    6、max_length
    7、default  默认值
    8、verbose_name  Admin中字段的显示名称
    9、name|db_column  数据库中的字段名称
    10、unique=True  不允许重复
    11、db_index = True  数据库索引
    12、editable=True  在Admin里是否可编辑
    13、error_messages=None  错误提示
    14、auto_created=False  自动创建
    15、help_text  在Admin中提示帮助信息
    16、validators=[]
    17、upload-to
    • settings.py相关配置

    数据库连接配置:

    DATABASES = {
        'default': {
            #'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
            'ENGINE': 'django.db.backends.sqlite3', #添加数据库引擎;选项['postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'].
            'NAME': 'F:/TestPython/blog/blog/db/data.db', # 数据库文件的路径.
            # The following settings are not used with sqlite3:
            # 下面的配置不适用于sqlite3:
            'USER': '',    # 数据库登陆用户名
            'PASSWORD': '', # 数据库登陆密码
            'HOST': '',                      # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. # 主机名
            'PORT': '',                      # Set to empty string for default. # 端口号
        }
    }

    注册app:
    在settings里的INSTALLED_APPS里面加上你的app名字

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01',
    ]

    生成数据库表

    python  manage.py makemigrations 
    # 生成一个数据库结构migrations里面一个表
    python  manage.py migrate      
    # 根据migrations里面的表来创建数据库

    将app的数据库注册到admin

    在app01下面的admin.py写入以下内容:
    from django.contrib import admin
    
    # Register your models here.
    # 导入app01的数据库模块
    from app01 import models
    
    # 注册咱们创建的类,通过他来访问
    admin.site.register(models.UserInfo)

    数据库相关操作

    增删改查

    # 插入数据:
    UserInfo.objects.create(name='rain',password='123',email='rain@163.com')
    
    # 删除数据:
    UserInfo.objects.filter(name='rain').delete()
    
    # 修改数据:
    UserInfo.objects.filter(name='rain').update(name='Rain1')
    
    # 查找数据:
    UserInfo.objects.filter(name='rain')
    UserInfo.objects.all()
    UserInfo.objects.all()[:10] 
    # 切片操作,获取10个人,不支持负索引,切片可以节约内存
    UserInfo.objects.get(name='rain')
    #查找所有
    models.UserInfo.objects.all()
    #查找指定条件
    models.UserInfo.objects.filter(age=18)
    #查找第一个
    models.UserInfo.objects.filter(age=18).first()
    #查找所有并且显示出来
    user_list_obj = models.UserInfo.objects.all()
    for line in user_list_obj:
        print(line.username,line.age)

    进阶操作

    • 利用双下划线将字段和对应的操作连接起来
      # 获取个数
         
        models.Tb1.objects.filter(name='seven').count()
    
        # 大于,小于
     
        models.Tb1.objects.filter(id__gt=1)              # 获取id大于1的值
        models.Tb1.objects.filter(id__lt=10)             # 获取id小于10的值
        models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值
    
        # in
        
        models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
        models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
    
        # contains
       
        models.Tb1.objects.filter(name__contains="ven")
        models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
        models.Tb1.objects.exclude(name__icontains="ven")
    
        # range
       
        models.Tb1.objects.filter(id__range=[1, 2])   # 范围bettwen and
    
        # 其他类似
       
        startswith,istartswith, endswith, iendswith,
    
        # order by
      
        models.Tb1.objects.filter(name='seven').order_by('id')    # asc
        models.Tb1.objects.filter(name='seven').order_by('-id')   # desc
    
        # limit 、offset
       
        models.Tb1.objects.all()[10:20]
    
        # group by
        from django.db.models import Count, Min, Max, Sum
        models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
        SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
    • F和Q操作
    # F 使用查询条件的值
    
    from django.db.models import F
    models.Tb1.objects.update(num=F('num')+1)
    
    # Q 构建搜索条件
    from django.db.models import Q
    con = Q()
    
    q1 = Q()
    q1.connector = 'OR'
    q1.children.append(('id', 1))
    q1.children.append(('id', 10))
    q1.children.append(('id', 9))
    
    q2 = Q()
    q2.connector = 'OR'
    q2.children.append(('c1', 1))
    q2.children.append(('c1', 10))
    q2.children.append(('c1', 9))
    
    con.add(q1, 'AND')
    con.add(q2, 'AND')
    
    models.Tb1.objects.filter(con)
    
    from django.db import connection
    cursor = connection.cursor()
    cursor.execute("""SELECT * from tb where name = %s""", ['Lennon'])
    row = cursor.fetchone()

    连表操作

    连表关系:

    • 一对多,models.ForeignKey(ColorDic)
    • 一对一,models.OneToOneField(OneModel)
    • 多对多,authors = models.ManyToManyField(Author)

    应用场景:

    • 一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了)。 例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据。
    • 一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)。 例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。
    • 多对多:在某表中创建一行数据是,有一个可以多选的下拉框。 例如:创建用户信息,需要为用户指定多个爱好。

    一对多

    • 数据库表:models.py UserType存放用户类型,UserInfo存放用户信息
    from django.db import models
    # Create your models here.
    
    class UserType(models.Model):
        caption = models.CharField(max_length=32)
            # 超级管理员,普通用户,游客,黑河
        def __str__(self):
            return self.caption
    
    class UserInfo(models.Model):
        user = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32)
        user_type = models.ForeignKey('UserType')
    • 创建有外键的数据
    #方法一:需要进行两次数据库操作,不推荐
    UserInfo.objects.create(user='test',pwd='123',user_type=UserType.objects.get(id=1))
    #方法二:利用外键关系进行直接插入值,此时user_type代指的就是usertype表
    UserInfo.objects.create(user='test',pwd='123',user_type_id=1)
    
    >>> from app01 import models
    >>> models.UserInfo.objects.create(user='test',pwd='123',user_type=models.UserType.objects.get(id=1))
    <UserInfo: UserInfo object>
    >>> models.UserInfo.objects.create(user='asdasdadas',pwd='123',user_type_id=3)
    <UserInfo: UserInfo object>
    • 数据:

    • 查找

    1.根据用户,查找用类型

    >>> models.UserInfo.objects.filter(user="test")[0].user_type.caption
    '管理员'
    此时user_type对应的就是usertype的表,所以直接使用.caption就可以拿到数据

    2.根据用户类型查找用户

    #方法一:先查找出用户类型对应的user_type的id,然后再去userinfo表中查找id对应的用户
    >>> role_id = models.UserType.objects.get(caption='管理员').id
    >>> role_id
    1
    >>> models.UserInfo.objects.filter(user_type=role_id).values('user','pwd')
    <QuerySet [{'pwd': '123', 'user': '张三'}, {'pwd': '123', 'user': 'test2'}, {'pwd': '123', 'user': 'test'}]>
    
    #方法二:使用双下划线进行一次连表操作
    >>> models.UserInfo.objects.filter(user_type__caption="管理员")
    <QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>
    >>> sql[0].user
    '张三'
    >>> sql[0].pwd
    '123'
    >>> sql[0].user_type.caption
    '管理员'
    >>> sql[0].user_type.id
    1
    
    继续封装,同时取用户的所有信息:
    >>> sql = models.UserInfo.objects.filter(user_type__caption="管理员").values('user','pwd','user_type__id','user_type__caption')
    >>> sql
    <QuerySet [{'user_type__id': 1, 'pwd': '123', 'user': '张三', 'user_type__caption': '管理员'}, {'user_type__id': 1, 'pwd': '123', 'user': 'test2', 'user_type__caption': '管理员'}, {'user_type__'pwd': '123', 'user': 'test', 'user_type__caption': '管理员'}]>
    
    
    打印sql语句:
    >>> print(sql.query)
    SELECT "app01_userinfo"."user", "app01_userinfo"."pwd", "app01_userinfo"."user_type_id", "app01_usertype"."caption" FROM "app01_userinfo" INNER JOIN "app01_usertype" ON ("app01_userinfo"."user_type_id" = "app01_usertype"."id") WHERE "app01_usertype"."caption" = 管理员

    跨多张表进行操作,如果UserType表中还有外键指向另一张表的主键,怎么查呢?
    新的表结构如下:

    from django.db import models
    # Create your models here.
    
    class UserType(models.Model):
        caption = models.CharField(max_length=32) # 超级管理员,普通用户,游客,黑河
        s = models.ForeignKey('something')
        def __str__(self):
            return self.caption
    
    class UserInfo(models.Model):
        user = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32)
        user_type = models.ForeignKey('UserType')
        
    class something(models.Model):
        name = models.CharField(max_length=32)

    查询:

    models.UserInfo.objects.filter(user_type__s__name="一些条件值"

    这是跨两张表,跨三张表、四张表都这样

    多对多

    • 表结构: 一个girl表、一个boy表,还一个boy_girl的关系表

      

    class Girl(models.Model): 
        name = models.CharField(max_length=32)
        b = models.ManyToManyField('Boy')
    
    class Boy(models.Model):
        name = models.CharField(max_length=32)

    PS:多对多关系需要三张表,两张数据表,一张关系表,但是在django 中如果使用ManyToManyField的话,不需要在指定第三张表,默认django会创建。当然,如果不使用该字段的话,也可以手动指定第三张表,然后使用models.ForeignKey做外键关联

    • 添加数据

    添加数据到关系表:

    女孩跟男孩建立关系   正向操作
    >>> G = models.Girl.objects.get(id=1)
    >>> g = models.Girl.objects.get(id=1)
    >>> girl = models.Girl.objects.get(id=1)
    >>> boy = models.Boy.objects.get(id=3)
    >>> girl.name
    'fuzj3'
    >>> boy.name
    'fuzj2'
    
        #使用对象建立关系
    
    >>> girl.b.add(boy)         #此时的b时多对多的字段
    >>> bs = models.Boy.objects.all()   #获取男孩的所有对象,返回数组
    >>> g.b.add(*bs)        #批量将关系插入到关系表
    
        #使用主键值建立关系
    >>> girl = models.Girl.objects.get(id=3)
    >>> girl.b.add(3)
    >>> bs_list = [1,4,5]
    >>> girl.b.add(*bs_list)
    
    
    男孩跟女孩建立关系  反向操作
    
    >>> boy = models.Boy.objects.get(id=1)
    >>> boy
    <Boy: Boy object>
    >>> boy.girl_set.add(3)

    • 删除

      remove() 删除
      clear() 清空

    >>> g1 = models.Girl.objects.get(id=1)   #获取一个女孩对象
    >>> g1.b.remove(2)              #单个删除一个关系
    >>> g1.b.remove(*[3,4])     #批量删除多个关系
    >>> g1.b.clear()                #清空本对象对应的所有关系
    • 查询
      支持all() filer()等操作

        

    1.通过女孩查找男孩(正向查找)
    >>> models.Girl.objects.filter(name='fuzj2').values('id','name','b__name')
    <QuerySet [{'name': 'fuzj2', 'id': 3, 'b__name': 'fuzj'}, {'name': 'fuzj2', 'id': 3, 'b__name': 'fuzj2'}, {'name': 'fuzj2', 'id': 3, 'b__name': 'fuzj3'}, {'name': 'fuzj2', 'id': 3, 'b__name': None}]>
    
    'b__name'中 b此时代指的关系表,所以b__name 就是跨到了boy表,。此时相当于直接跨了两张表
        2. 通过男孩查找女孩(反向查找)
    >>> models.Boy.objects.filter(name='fuzj').values('id','name','girl__name')
    <QuerySet [{'name': 'fuzj', 'id': 1, 'girl__name': 'fuzj2'}]>
    
    'girl__name' 中,girl是boy表中隐藏的字段,代指的是和girl的关系表,所以girl__name就跨到了girl表
    
    
    • 修改

      默认django不支持修改操作,如果实现修改操作,只能是先删除,然后再创建,显然这个效率不是很高。所以,我们可以通过原生的sql语句进行操作

    from django.db import connection
    cursor = connection.cursor()
    cursor.execute("update tbname set girl_id = '3' where boy_id = %s",[3])

    中间件

    中间件定义:

    • 中间件是一个、一个的管道,如果相对任何所有的通过Django的请求进行管理都需要自定义中间件

    • 中间件可以对进来的请求和出去的请求进行控制

    • 中间件是一类。

    由上图可知,中间件是位于wsgi和路由系统中间的环节。用户请求和和回应请求都会经过中间件。

    看下面的代码在settings里中间件的类:

    MIDDLEWARE_CLASSES = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]

    当有请求过来的时候,默认从上倒下执行!然后在返回的时候从下面在返回回去

    自定义中间件

    中间件中可以定义四个方法,分别是:

    • process_request(self,request)
    • process_view(self, request, callback, callback_args, callback_kwargs)
    • process_exception(self, request, exception) 这个方法只有在出现错误的时候才会触发
    • process_response(self, request, response)
    • process_template_response(self,request,response) 这个方法只有在返回对象中有render方法的时候才执行,如render_to_response('/index/')

    以上方法的返回值可以是None和HttpResonse对象,如果是None,则继续按照django定义的规则向下执行,如果是HttpResonse对象,则直接将该对象返回给用户。

    • 创建中间件脚本

    在django的的project目录下创建一个middleware目录,并创建一个md.py的脚本,内容如下:

    class Testmiddle:
        def process_request(self,request):
            print 'Testmiddle process_request'
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print 'Testmiddle process_view'
        def process_exception(self, request, exception):
            pass
        def process_response(self, request, response):
            print 'Testmiddle process_response'
            return response
        
    class Nextmiddle:
        def process_request(self,request):
            print 'Nextmiddle process_request'
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print 'Nextmiddle process_view'
        def process_exception(self, request, exception):
            pass
        def process_response(self, request, response):
            print 'Nextmiddle process_response'
            return response
    • 注册中间件

    修改settings.py文件,在MIDDLEWARE_CLASSES中添加我们创建的中间件

    MIDDLEWARE_CLASSES = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        'middleware.middle.Testmiddle',
        'middleware.middle.Nextmiddle',
    ]
    • 设置url 略
    • 测试:
    Testmiddle process_request
    Nextmiddle process_request
    Testmiddle process_view
    Nextmiddle process_view
    This app01 Views.index
    Nextmiddle process_response
    Testmiddle process_response

    从输出结果可以看出:

    他是先执行Testmiddle 的request 方法又执行了Nextmiddle的 process_request方法, 然后在执行Testmiddle的view方法,Nextmiddle的view方法

    注意:django版本1.10以后,会报如下错误:

    解决如下:

    from django.utils.deprecation import MiddlewareMixin
    class Testmiddle(MiddlewareMixin):
        def process_request(self,request):
            print 'Testmiddle process_request'
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print 'Testmiddle process_view'
        def process_exception(self, request, exception):
            pass
        def process_response(self, request, response):
            print 'Testmiddle process_response'
            return response
        
    class Nextmiddle(MiddlewareMixin):
        def process_request(self,request):
            print 'Nextmiddle process_request'
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print 'Nextmiddle process_view'
        def process_exception(self, request, exception):
            pass
        def process_response(self, request, response):
            print 'Nextmiddle process_response'
            return response

    注意:
    * 老版本中在中间件中如果某个中间件类的方法返回的不是none,则后面的中间件不会再处理请求,也不会到达路由系统,而是直接到第一个process_response,开始所有的process_response处理
    * 新版本中在中间件中如果某个中间件类的方法返回的不是none,则后面的中间件不会再处理请求,也不会到达路由系统,而是直接到最后一个process_response处理,然后返回给客户端

  • 相关阅读:
    批量刷新远程物化视图的方法(备用)
    Oracle 11g中CTE应用示例
    PL/SQL DEVELOPER中查询结果复制出来中文乱码的解决方案
    RHEL5.5 64位下安装Oracle 11g 64位安装前置条件的两种方法
    不良言论屏蔽方案探讨——自说自话方案
    AWWWB 网站克隆器 v2.0发布
    OneNote中到底能放多少种东西?
    Visual Studio 2010 旗舰版 安装问题小记
    WPF命中测试示例(一)——坐标点命中测试
    网页内嵌Windows Media Player播放器的多文件播放方法
  • 原文地址:https://www.cnblogs.com/pycode/p/db-middleware.html
Copyright © 2020-2023  润新知