• Django之操作数据库


    1:数据库:

    2:MySQL驱动程序的安装

    3:Django配置连接数据库

    4:在Django中操作数据库

      (1)原生SQL语句操作

      (2)ORM模型操作

    5:ORM模型的介绍

    6:创建一个ORM模型并映射模型到数据库中

    7:模型常用的属性

      (1)常用的Field字段

      (2)Field字段常用的参数

      (3)模型中Meta的配置

    8:外键

    9:表关系

      (1)一对一

      (2)一对多(多对一)

      (3)多对多

    10:模型的操作

      (1)数据的增删改查

      (2)聚合函数

      (3)aggregate和annotate的区别

      (4)F表达式和Q表达式

    11:查询集(QuerySet

    12:ORM模型迁移

    -------------------------------------------------------------------------------------------------------------------------------

    1数据库:简而言之就是存放数据的一个库,用户可以对数据进行增删改查;是网站重要的一个组成部分,只有提供了数据库,网站才能动态的展示。常用的数据库有MySQL,Oracle等。

    2MySQL驱动程序的安装:我们使用Django来操作mysql,实际上底层使用的还是python;因此如果我们想要操作数据库首先要安装一个驱动;python3中有多个驱动可供选择如下;

      (1)MySql-python :也就是MySQLdb 。是对C语言操作mysql的一个简单封装;只支持python2,不支持python3,运行速度最快。

      (2)mysqlclient:是MySql-python的另一个分支,支持python3。

      (3)pymsql:纯python实现的一个驱动,效率不高,可以和python无缝连接。

      (4)mysql-connector-python:mysql官方推出的,纯python开发的,效率不高

    本文使用的是mysqlclient:   安装方式: pip install mysqlclient

    3:Django配置连接数据库:在操作数据库之前需要Django先连接上数据库,不需要单独创建一个连接对象,只需要在setting中做好相关的配置即可。

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',   #数据库引擎(mysql还是Oracle)
            'NAME': "my01",  #数据库的名字
            "USER":"root",    #数据库的用户名
            "PASSWORD":"qwe123",    #数据库密码
            "HOST":"localhost",   #数据库的主机地址
            "PORT":"3306"      #数据库的端口号
        }
    }

    4:在Django中操作数据库:Django操作数据库有两种方式。第一种是原生的SQL语句操作,另一种是ORM模型操作

      (1)原生SQL语句操作

        缺点:(1)重复利用率不高(2)不易修改(3)安全问题(SQL注入)

      (2)ORM模型操作

    5:ORM模型的介绍

      (1)ORM,全称Object Relational Mapping,中文叫做对象-关系映射。

      (2)通过ORM我们可以通过类的方式来操作数据库,通过把类映射成表,把实例映射为行,把属性映射为字段;ORM在执行对象操作的时候最终还是会把对应的操作转换为SQL语句。

    6:创建一个ORM模型并映射模型到数据库中

      第一步:创建一个User模型类(在数据库中的表现:类--表名(app的名字_类名(小写)),属性--字段,实例-行)

    class User(models.Model):
        username = models.CharField(max_length=10)
        telephone = models.CharField(max_length=11)
        email = models.EmailField()
        sex = models.BooleanField()

      第二步:执行makemigrations [app_name]       #后面可以跟APP的名字,生成迁移脚本文件

      第三步:执行migrate [app_name]     #映射到数据库中

    7:模型常用的属性

      (1)常用的Field字段

        AutoField:int类型,自动增长

        BigAutoField:类似于AutoField,范围1-9223372036854775807

        BooleanField:tinyint类型,True/False 

        CharField:  varchar类型,使用时必须指定最大长度,即max_length参数必须传递

        DateField: 日期类型;两个参数auto_now:每次保存的时候都是用当前的时间,比如记录一个记录修改的日期;auto_now_add:在数据第一次创建的时候用当前的时间,比如记录第一次入库的时间。

        DateTimeField:日期时间类型;不仅可以存储日期还可以存储时间。两个参数(auto_now和auto_now_add)

        TimeField:时间类型;

        EmailField:varchar类型;最大长度254

        FileField:用来存储文件的

        FloatField:浮点类型

        ImageField:存储图片

        IntegerField:整型,-2147483648 - 2147483647

        BigIntegerField:大整形,

        PositiveIntegerField:正整型;0-2147483647

        SmallIntegerField:小整型,-32768 - 32767

        TextField:大量的文本类型,longtext

        UUIDField:存储uuid格式的字符串,是一个32位的全球唯一的字符串,一般做主键

        URLField:存储url格式的字符串,max_length默认是200

      (2)Field字段常用的参数

        null:表示映射为表的时候是否可以为空,默认为False(不能为空);在使用字符串相关的Field时(CharField、TextField)一般保持默认的False,因为即便是Flase,Django也会创建一个空字符串 " "作为默认值传递进去,如果再设置为True的话,就会用null来存储空值,默认值就变为了两个(""和null)

        blank:表示验证的时候是否可以为空,默认是False。(和null的区别:null是一个数据库级别的,blank是表单验证级别的)

        db_column:表示字段在数据库中的名字

        default:默认值,可以是一个值或者函数,不支持lambda表达式,并且不支持列表、字典。集合等可变的数据结构

        primary_key:默认值false,是否为主键

        unique:是否唯一,一般手机号或者邮箱用

      (3)模型中Meta的配置

        对于一些模型级别的配置,我们可以在模型中定义一个类,叫做Meta,然后在这个类中添加一些类属性来控制模型。比如在映射到数据库中表的名字使用自己定义的。

    from django.db import models
    
    class User(models.Model):
        username = models.CharField(max_length=10)
        telephone = models.CharField(max_length=11)
        email = models.EmailField()
        sex = models.BooleanField(db_column="sex_a")
        create_time = models.DateTimeField(auto_now_add=True)
        
        class Meta:
            db_table = "User",      //表的名字
            ordering = ["create_time"]   //在查找数据的时候根据添加的时间排序

     8:外键

       如果一张表中非主键的某个字段指向了另一张表中的主键,那么这个字段就是该表的外键。

      外键的作用是:防止一张表过于复杂(比如一个需求是一个名字对应一张照片,如果保存在同一种表中数据可能有些乱,最好是分开两张表,一种保存名字,另一张保存图片,同时两张表又有一种制约,可以通过名字找到这张图片,或者通过图片找到这个名字)。

      在mysql中,表有两种引擎,一种是InnoDB,支持外键的使用;另一种是myisam,暂时不支持外键的使用。

      Django中的外键使用ForeignKey(to,on_delete,**options),第一个参数是引用的是哪个模型,第二个参数是使用外键引用的模型被删除的时候,这个字段该如何处理。

      注意:如果引用的模型在另一个APP中,则第一个参数需要添加app_name.模型名;如果引用的是模型本身自己可以用self或者模型自己的名字

    from django.db import models
     
    class User(models.Model):         //用户模型
        username = models.CharField(max_length=10)
        password = models.CharField(max_length=20)
    
    
    class Article(models.Model):   //文章模型
        title = models.CharField(max_length=20)
        content = models.TextField()
        author = models.ForeignKey("User",on_delete=models.CASCADE)         //外键
        category = models.ForeignKey("login.Tags",on_delete=models.CASCADE)  //另一个app,login中model的Tags模型
    
    
    class Comment(models.Model):
        content = models.TextField()
        origin_comment = models.ForeignKey("self",on_delete=models.CASCADE,null=True)   //外键是模型自己
        # origin_comment = models.ForeignKey("Comment",on_delete=models.CASCADE,null=True)

      外键删除操作:

      如果一个模型引用了外键,在对方那个模型被删除掉,该进行什么样的操作;通过on_delete来指定:

        CASCADE:级联操作,如果外键对应的那条数据被删除,那么这条数据也被删除。

        PROTECT:受保护,即只要这条数据引用了外键的那条数据,那么就不能删除外键的那条数据。

        SET_NULL:设置为空,如果外键的那条数据被删除,那么本条数据设置为空,前提是这个字段可以为空。

        SET_DEFAULT:设置为默认值,如果外键的那条数据被删除,那么本条数据设置默认值,前提是要指定一个默认值。

        SET():如果外键那条数据被删除,则调用set函数的值,作为外键的值

        DO_NOTHING:不采取任何行为,看数据库级别的约束。

    9:表关系:表之间的关系都是通过外键进行关联的,三种关系,一对一,一对多(多对一),多对多

      (1)一对一

        应用场景:一个用户和一个用户信息表

        实现方式:通过OneToOneField来实现 

      (2)一对多(多对一)

        应用场景:比如作者和文章之间的关系,一个作者可以有多篇文章,但是一篇文章只能有一个作者

        实现方式:一对多或者多对一,都是通过ForeignKey来实现的    

      (3)多对多

        应用场景:比如文章和标签之间的关系;一篇文章可以有多个标签,一个标签可以被多篇文章引用

        实现方式:通过ManyToManyField来实现

      表之间的查询方式:related_name和related_query_name;我们依然使用上面的User模型和Article模型来举例:

      (1)如果我们想要通过文章获取该作者:

     article = Article.objects.first()   //获取这篇文章
     print(article.author.username)    //直接通过author获取作者

      (2)如果想要通过作者获取其下的所有文章方式有两种:

    #方式一:Django默认每个主表都有一个默认的属性来获取子表的信息,这个属性就是子表模型的小写加上_set(),默认返回一个querydict对象,可以进一步操作 
    author = User.objects.first()
     print(author.article_set.all())
    
    #方式二:在默认中添加related_name,以后主表直接通过这个值来获取子表的信息,得到的也是一个querydict对象。
    author = models.ForeignKey("User",on_delete=models.CASCADE,related_name="article")
    
    #我们可以直接使用这个值
    print(author.article.first().title)

      (3)relate_name=“+”,表示禁止使用反向查询

    10:模型的操作:在ORM框架中,所有的模型操作其实都是映射到数据库中一条数据的操作,因此模型操作也就是数据库表中数据的操作。

      (1)数据的增删改查

          一:以上面表User为例:

            (1)增加数据:

    User.objects.create(username="王三",password="123")

           (2)查数据:(all(),get(),filter())

      #查找所有的数据:返回的是一个queryset集合,没有满足条件返回空列表
        users = User.objects.all()
        for user in users:
            print(user.username)
        print(users)
    
        #查找单个的对象,返回一个对象,没有满足条件时报错
        user = User.objects.get(username="张帆")
        print(user.username)
    
        #数据过滤查找filter;查询的时候有时需要对数据进行过滤再查询,返回所有满足条件的QuerySet集合
        user = User.objects.filter(username="张帆",password="213123")
        print(user)
    
        #数据排序;查找数据的时候都是无序的,如果想对某个数据进行排序使用order_by,反向排序加个减号
        users = User.objects.order_by("username")

           (3)改数据:

     #修改数据:获取这条数据,对属性修改,然后保存
        user = User.objects.get(username="张帆")
        user.username = "李四"
        user.save()

           (4)删除数据

     #删除数据;获取数据,然后执行delete()函数
        user = User.objects.get(username="李四")
        user.delete()

          二:查询条件:查找的时候一般使用filter,get,exclude三个方法来实现,我们可以对其传递不同的参数,来实现不同的需求。格式(约束条件_查找条件)

            第一组:精确和like

              exact:使用精确 = 进行查找 ; User.objects.get(id_exact = 2),如果提供一个None值,sql层面被解释为null

              iexact:  使用like进行查找

            第二组:包含(title_contains = "hello")

              contains:大小写敏感

              icontains:大小写不敏感

              第三组:提供包含在容器中值,容器可以是列表,元组,任意一个可迭代的对象

              in:User.objects.get(id_in=[1,2,3])

              也可以传递一个queryset对象进去:获取标题中包含张三的文章

              username = User.objects.filter(username_contains = "张三")

              user = Article.objects.filter(title_in = username)

            第四组:(id__gt = 3)

              gt:大于

              gte:大于等于

              lt:小于

              lte:小于等于

            第五组:判断某个字段是否以某个值为开始(结束) (title_startwith = "hello")

              startwith:

              istartwith:

              endswith:

              iendswith:

            第六组:

              range:判断是否在某个区间;(create_time = range(start,end))

            第七组:根据时间查询

              date:年月日  (create_time_date=date(2018,3,23))

              year:年(create_time_year = 2108)

              month:月(同上)

              day:天(同上)

              wek_day:星期几(1表示星期天,7表示星期六)

              time:时分秒(create_time= datetime_time(2,2,2)),2点2分2秒

            第八组:是否为空

              isnull:(title_isnull = False) 不为空

            第九组:正则

              regex:大小写敏感:(title_regex=r"hello")

              iregex:大小写不敏感:(title_regex=r"hello")

         三:关联表查询 

            比如有两个模型,一个是User,一个是Article;想要获取文章标题中带有“中国”的用户

            user = User.objects.filter(article_title_contains = "hello")    

      (2)聚合函数:聚合函数是同aggregate方法来实现的。

          (1)Avg:求平均值

          (2)Count:获取指定对象的个数

          (3)Max和Min:获取最大值最小值

          (4)Sum:求和

    假设有这样一个模型:

    class BookOrder(models.Model):
        book_name = models.CharField(max_length=12)
        price = models.FloatField()

    数据表为:

      # result = BookOrder.objects.aggregate(Avg("price"))    //所有书的平均价格,名字规则为field_avg组成
        result = BookOrder.objects.aggregate(book_price = Avg("price"))    //给这个价格指定一个名字
        print(result)
     
        result = BookOrder.objects.aggregate(book_num = Count("id"))   //求所有的书
        print(result)
    
        result = BookOrder.objects.aggregate(book_price_max = Max("price"))  //求最大值
        print(result)
    
        result = BookOrder.objects.aggregate(book_price_min=Min("price"))  //求最小值
        print(result)
    
        result = BookOrder.objects.aggregate(books_price = Sum("price"))  //求最和
        print(result)

      (3)aggregate和annotate的区别

      (4)F表达式和Q表达式

       F表达式是用来优化ORM模型操作数据库的,并不会立刻去数据库中获取数据,而是在生成SQL语句的时候,动态的获取传给F表达式的值

    BookOrder.objects.update(price = F("price")+100)            //更新图书的价格

      Q表达式:一般查询条件比较多的时候使用,可以使用与或非,&,|,~

    books = BookOrder.objects.filter(Q(id=3) | Q(book_name__contains=""))

    11:查询集(QuerySet

      (1)查询集就是通过查询后得到的一个对象集合。

      Django中查询操作都是通过 模型名.objects的方式进行;这个objects是一个Manager对象,而这个Manager这个类是一个空壳的类,它本身没有任何的属性和方法;都是通过Python从QuerySet类中动态的添加过来的。

    class Manager(BaseManager.from_queryset(QuerySet)):
        pass
    
    
    class BaseManager:
        @classmethod
        def from_queryset(cls, queryset_class, class_name=None):
            if class_name is None:
                class_name = '%sFrom%s' % (cls.__name__, queryset_class.__name__)
            return type(class_name, (cls,), {
                '_queryset_class': queryset_class,
                **cls._get_queryset_methods(queryset_class),
            })
    
       
    class QuerySet:
    """Represent a lazy database lookup for a set of objects."""

    def __init__(self, model=None, query=None, using=None, hints=None):
    self.model = model
    self._db = using
    self._hints = hints or {}
    self.query = query or sql.Query(self.model)
    self._result_cache = None
    self._sticky_filter = False
    self._for_write = False
    self._prefetch_related_lookups = ()
    self._prefetch_done = False
    self._known_related_objects = {} # {rel_field: {pk: rel_obj}}
    self._iterable_class = ModelIterable
    self._fields = None


        ............(后面省略)
     

      (2)两大特性:

        惰性执行:创建查询集不会立刻执行,只到调用数据时才会去数据库中查询,调用数据包括:迭代,使用步长做切片操作,调用len函数,调用list函数,判断

        缓存:使用同一个查询集,第一次会发生数据库查询,然后django会把数据缓存起来,以后再使用的时候不会去数据库查询而是直接使用

      (3)常用的API:

        1.filter:将满足条件的数据提取出来,返回一个queryset对象

        2.exclude:排除满足条件的对象,返回一个queryset对象

        3.annotate:

        4.order_by:排序(倒序加减号),多个order_by链式使用时,会把前面的打乱,以后面的为准

        5.values:规定提取那些字段,返回的是一个字典类型。默认会把所有字段都提取出来

        6.values_list:同上,不过返回的是一个元组

        7.defer:过滤掉一些字段,返回的是一个模型

        8.only:只保留这个字段(和上面相反)

        9.all:返回queryset对象

        10.select_related:

        11.prefetch_related:

        12.get:只返回一条满足条件的数据,如果是多条或者没有都会报错

        13.create:创建一条数据,并保存

        14.get_or_create:如果数据库中存在这个数据就返回,不存在就创建;返回一个元组(第一个参数是这个对象,第二个参数是boolean类型)

        15.bulk_create:一次创建多个数据;bulk_create([book_name="111",book_name="222"])

        16.count:获取数据的个数,比len函数高效

        17.first和last:返回queryset中的第一条和最后一条

        18.aggregate:使用聚合函数

        19.exists:判断是否存在

        20.distinct:去掉重复的数据;

        21.update:更新

        22.delete:删除数据

        23.切片:Books.objects.all()[1:3];切片不是把数据都提取出来再做切片,而是在底层直接使用LIMIE和OFFSET

     12:ORM模型迁移

      (1)makemigrations:将模型生成迁移脚本

          app_label:后面跟一个或者多个app,只会针对这几个app生成迁移脚本,如果没有写就是针对所有都生成

          --name:给这个迁移脚本生成一个名字

          --empty:生成一个空的迁移脚本

      (2)migrate:将生成的迁移脚本映射到数据库中

          app_label:规定那几个app

          app_label migrationname;将某个app下指定名字的migration文件映射到数据库中

          --fake:可以将指定的迁移脚本文件名字添加到数据库中,但是并不会把迁移脚本文件转换为sql语句,修改数据库中的表

          --fake-initial:将第一次生成的迁移文件版本号记录在数据库中,但并不会执行迁移脚本

      (3)showmigrations:查看某个app的迁移文件;如果后面没有app将查看所有的

      (4)sqlmigrate:查看某个迁移文件映射到数据库中转换的SQL语句

  • 相关阅读:
    Sql 复习(1)
    记录一次git issue
    JWT自校验框架
    分布式事务分布式锁的常用解决方式
    SpringBoot开发文档
    SpringCloud的使用以及五大核心组件
    SpringMVC
    关于开发中使用AOP的坑
    SpringCloud使用feign远程调用服务注入映射接口失败问题
    springBoot使用Restful跳转路径回显异常问题
  • 原文地址:https://www.cnblogs.com/yan-peng/p/10295343.html
Copyright © 2020-2023  润新知