zoukankan      html  css  js  c++  java
  • Django(十)模型:django模型类对数据库的:增/删/改/查、自关联、管理器、元选项(指定表名)

    一、插入、更新和删除

    • 调用一个模型类对象的save方法的时候就可以实现对模型类对应数据表的插入和更新。
    • 调用一个模型类对象的delete方法的时候就可以实现对模型类对应数据表数据的删除。

    二、自关联

    在这里插入图片描述

    自关联是一种特殊的一对多的关系。

    【案例】:显示广州市的上级地区和下级地区。

    • 地区表:id, atitle, aParent_id;
    • mysql终端中批量执行sql语句:source areas.sql;

    第1步,添加地区模型类 app1/models.py

    【关系属性】,代表当前地区的父级地区

    class AreaInfo(models.Model):
        '''地区模型类'''
        # 地区名称
        atitle = models.CharField(max_length=20)
        # 【关系属性】,代表当前地区的父级地区
        aParent = models.ForeignKey('self', null=True, blank=True)
    
        # class Meta:
        #     db_table = 'areas'
    

    第2步,创建迁移,应用迁移创建对应表

    D:adjango-appproject1>py manage.py makemigrations
    Migrations for 'app1':
      app1migrations004_auto_20200107_1148.py
        - Alter field btitle on bookinfo
        - Create model AreaInfo
    
    D:adjango-appproject1>py manage.py migrate
    Operations to perform:
      Apply all migrations: admin, app1, auth, contenttypes, sessions
    Running migrations:
      Applying app1.0004_auto_20200107_1148... OK
    

    查看表mysql命令窗:

    mysql> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | sakila             |
    | spiders            |
    | sys                |
    | test888            |
    | world              |
    +--------------------+
    8 rows in set (0.07 sec)
    
    mysql> use test888
    Database changed
    mysql> show tables;
    +----------------------------+
    | Tables_in_test888          |
    +----------------------------+
    | app1_areainfo              |
    | app1_bookinfo              |
    | app1_heroinfo              |
    | auth_group                 |
    | auth_group_permissions     |
    | auth_permission            |
    | auth_user                  |
    | auth_user_groups           |
    | auth_user_user_permissions |
    | django_admin_log           |
    | django_content_type        |
    | django_migrations          |
    | django_session             |
    +----------------------------+
    13 rows in set (0.00 sec)
    
    mysql> desc app1_areainfo; 
    +------------+-------------+------+-----+---------+----------------+
    | Field      | Type        | Null | Key | Default | Extra          |
    +------------+-------------+------+-----+---------+----------------+
    | id         | int(11)     | NO   | PRI | NULL    | auto_increment |
    | atitle     | varchar(20) | NO   |     | NULL    |                |
    | aParent_id | int(11)     | YES  | MUL | NULL    |                |
    +------------+-------------+------+-----+---------+----------------+
    3 rows in set (0.11 sec)
    

    第3步,把地区数据表导入刚建的表

    • 表位置:q网盘源码【area.sql】
    • 把例如:
      INSERT INTO app1_areainfo VALUES ('110000', '北京市', NULL);
      中的【app1_】改成 【对应的表名_】
    进入sql命令窗:即可导入(路径不要有中文空格等)
    use test888; #使用对应的表
    source E:/pro_sql/test.sql; #导入数据
    
    #执行效果: Query OK, 1 row affected (0.12 sec)
    

    查询刚导入的表效果

    select * from app1_areainfo;
    | 659000 | 省直辖行政单位                                |     650000 |
    | 659001 | 石河子市                                      |     659000 |
    | 659002 | 阿拉尔市                                      |     659000 |
    | 659003 | 图木舒克市                                    |     659000 |
    | 659004 | 五家渠市                                      |     659000 |
    | 990000 | 新疆建设兵团                                  |       NULL |
    | 990100 | 第一师                                        |     990000 |
    | 990200 | 第二师                                        |     990000 |
    | 990300 | 第三师                                        |     990000 |
    | 990400 | 第四师                                        |     990000 |
    | 990500 | 第五师                                        |     990000 |
    | 990600 | 第六师                                        |     990000 |
    | 990700 | 第七师                                        |     990000 |
    | 990800 | 第八师                                        |     990000 |
    | 990900 | 第九师                                        |     990000 |
    | 991000 | 第十师                                        |     990000 |
    | 991100 | 建工师                                        |     990000 |
    | 991200 | 第十二师                                      |     990000 |
    | 991300 | 第十三师                                      |     990000 |
    | 991400 | 第十四师                                      |     990000 |
    +--------+-----------------------------------------------+------------+
    

    第4步,app1/views.py 编辑对应函数,读取地区信息

    from booktest.models import BookInfo,AreaInfo
    
    def areas(request):
        '''获取广州市的上级地区和下级地区'''
        # 1.获取广州市的信息
        area = AreaInfo.objects.get(atitle='广州市')
        # 2.查询广州市的上级地区
        parent = area.aParent
        # 3.查询广州市的下级地址
        children = area.areainfo_set.all()
        # 使用模板
        return render(request, 'app1/areas.html', {'area':area,'parent':parent, 'children':children})
    

    第5步,配置app1/urls.py

    展示对应省市区信息

    from django.urls import path,re_path
    from . import views
    
    urlpatterns=[
        path('app1/',views.index),
        path('books/',views.books),
    
        # 书详情页,通过url接收参数2种写法以下两种都可:
        # path(r"detail/<int:bookId>",views.detail), #参数用尖括号包起来<>
        re_path(r"^detail/(d+)",views.detail), #参数必须要带括号
    
        path('addInfo/',views.addInfo), #添加三国书
    
        path(r'delete/<int:bid>',views.deleteInfo), #删除对应图书
    
        path(r'area/',views.areas), #展示对应省市区信息
    ]
    

    第6步,添加展示模板templates/app1/areas.html

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>自关联案例</title>
    </head>
    <body>
    <h1>当前地区</h1>
    {{ area.atitle }}<br/>
    <h1>父级地区</h1>
    {{ parent.atitle }}<br/>
    <h1>下级地址</h1>
    <ul>
        {% for child in children %}
            <li>{{ child.atitle }}</li>
        {% endfor %}
    </ul>
    </body>
    </html>
    

    效果:

    当前地区:
    广州市

    父级地区:
    广东省

    下级地址:
    荔湾区
    越秀区
    海珠区
    天河区
    白云区
    黄埔区
    番禺区
    花都区
    南沙区
    萝岗区
    增城市
    从化市

    三、管理器(Manager)

    问:BookInfo.objects.all()->objects是一个什么东西呢?

    • 答:objects是Django帮我自动生成的管理器对象,通过这个管理器可以实现对数据的查询。
    • objects是models.Manger类的一个对象。自定义管理器之后Django不再帮我们生成默认的objects管理器。
    py manage.py shell
    >>> from app1.models import BookInfo,HeroInfo
    >>> type(BookInfo.objects)
    <class 'django.db.models.manager.Manager'>
    

    1 自定义模型管理器类

    1)自定义一个管理器类,这个类继承models.Manger类。
    2)再在具体的模型类里定义一个自定义管理器类的对象。

    例1:在app1/models.py下定义一个管理器类

    自定一个Manager类对象,管理器对象 book = models.Manager()

    # 一类
    # booktest2_bookinfo
    class BookInfo(models.Model):
        '''图书模型类'''
        # 图书名称
        btitle = models.CharField(max_length=20, db_column='title')
        # 图书名字唯一
        # btitle = models.CharField(max_length=20, unique=True, db_index=True)
        # 价格,最大位数为10,小数为2
        # bprice = models.DecimalField(max_digits=10, decimal_places=2)
        # 出版日期
        bpub_date = models.DateField()
        # bpub_date = models.DateField(auto_now_add=True) # 创建时间
        # bpub_date = models.DateField(auto_now=True) # 更新时间
        # 阅读量
        bread = models.IntegerField(default=0)
        # 评论量
        bcomment = models.IntegerField(default=0)
        # 删除标记
        isDelete = models.BooleanField(default=False)
    
        book = models.Manager() # 自定一个Manager类对象,管理器对象
        #objects = BookInfoManager() # 自定义一个BookInfoManager类的对象
    

    自定义管理器类之后再查询数据就变成如下

    由:BookInfo.objects.all() 变:BookInfo.book.all()

    >>> quit()
    
    D:adjango-appproject1>py manage.py shell
    Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 14:57:15) [MSC v.1915 64 bit (AMD6
    4)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> from app1.models import BookInfo
    
    >>> BookInfo.book.all() #【变】
    <QuerySet [<BookInfo: 天龙八部>, <BookInfo: 三国演义>, <BookInfo: 红楼梦>, <Book
    Info: 水浒传>]>
    
    >>> BookInfo.objects.all() #【原】
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
    AttributeError: type object 'BookInfo' has no attribute 'objects'
    

    2 自定义管理器类的应用场景

    1)改变查询的结果集。

    • 比如调用BookInfo.books.all()返回的是没有删除的图书的数据。

    例2:自定义Manager类

    【1】自定义一个BookInfoManager类,实现查寻数据只返回isDelete=False(删除标记(伪删除))的书
    【2】使用自定义的manager类

    from django.db import models
    # 设计和表对应的类,模型类
    
    #【1】自定义一个BookInfoManager类
    class BookInfoManager(models.Manager): #继承自models.Manager
        '''图书模型管理器类'''
        # 1.改变原有查询的结果集
        def all(self):
            # 1.调用父类的all方法,获取所有数据
            books = super().all() # QuerySet
            # 2.对books中的数据进行过滤
            books = books.filter(isDelete=False)
            # 返回books
            return books
    
    # 一类
    # 图书类
    class BookInfo(models.Model):
        '''图书模型类'''
        # 图书名称,CharField说明是一个字符串,max_length指定字符串的最大长度
        btitle = models.CharField(max_length=20,unique=True) #该字段不能重复,db_column='title'
        # 出版日期,DateField说明是一个日期类型
        bpub_date = models.DateField()
        # 阅读量
        bread = models.IntegerField(default=0)
        # 评论量
        bcomment = models.IntegerField(default=0)
        # 删除标记
        isDelete = models.BooleanField(default=False)
    
        #book = models.Manager() # 自定一个Manager类对象,管理器对象
        objects = BookInfoManager() # 自定义一个BookInfoManager类的对象 【2】使用自定义的manager类
    

    2)添加额外的方法。

    • 管理器类中定义一个方法帮我们操作模型类对应的数据表。
    • 使用self.model()就可以创建一个跟自定义管理器对应的模型类对象。

    例3,把插入图书各个语句封装成一个BookInfo类的函数:

    app1/models.py
    1.【封装插入图书方法为BookInfo的函数】
    2.使用时只需要 BookInfo.create_book(书标题,日期) 即可使用详情:

    '''使用下一步封装的函数'''
    from app1.models import BookInfo
    BookInfo.create_book('test','1991-1-1')   
    book.btitle #(返回刚插入的标题)
    
    '''定义类的封装插入图书函数'''
    from django.db import models
    
    # 一类
    # booktest2_bookinfo
    class BookInfo(models.Model):
        '''图书模型类'''
        # 图书名称
        btitle = models.CharField(max_length=20, db_column='title')
        # 图书名字唯一
        # btitle = models.CharField(max_length=20, unique=True, db_index=True)
        # 价格,最大位数为10,小数为2
        # bprice = models.DecimalField(max_digits=10, decimal_places=2)
        # 出版日期
        bpub_date = models.DateField()
        # bpub_date = models.DateField(auto_now_add=True) # 创建时间
        # bpub_date = models.DateField(auto_now=True) # 更新时间
        # 阅读量
        bread = models.IntegerField(default=0)
        # 评论量
        bcomment = models.IntegerField(default=0)
        # 删除标记
        isDelete = models.BooleanField(default=False)
    
        # book = models.Manager() # 自定一个Manager类对象,管理器对象
        #objects = BookInfoManager() # 自定义一个BookInfoManager类的对象
    
        @classmethod #【封装插入图书方法为BookInfo的函数】
        def create_book(cls, btitle, bpub_date):#cls即类名
            '''添加一本图书'''
            # 创建一个cls类的对象
            obj = cls()
            obj.btitle = btitle
            obj.bpub_date = bpub_date
            # 添加进数据库
            obj.save()
            # 返回obj
            return obj
    

    例4,一般把增、删、改、查自定义函数写到Manger自定义类里

    2.封装方法,操作模型类对应的数据表(增删改查)

    class BookInfoManager(models.Manager):
        '''图书模型管理器类'''
        # 1.改变原有查询的结果集
        def all(self):
            # 1.调用父类的all方法,获取所有数据
            books = super().all() # QuerySet
            # 2.对books中的数据进行过滤
            books = books.filter(isDelete=False)
            # 返回books
            return books
    
        # 2.封装方法,操作模型类对应的数据表(增删改查)
        def create_book(self, btitle, bpub_date):
            '''添加一本图书'''
            # 1.创建一个图书对象
            # 获取self所在的模型类
            model_class = self.model
            book = model_class()
            # book = BookInfo()
            book.btitle = btitle
            book.bpub_date = bpub_date
            # 2.添加进数据库
            book.save()
            # 3.返回book
            return book
    

    调用:

    from app1.models import BookInfo
    
    #必须通过关键字传参
    BookInfo.objects.create(btitle='test3',bpub_ date='1990-10-10' )
    <BookInfo:BookInfo object>
    

    上一步写的自定义函数先注释掉:

        # @classmethod
        # def create_book(cls, btitle, bpub_date):
        #     '''添加一本图书'''
        #     # 创建一个cls类的对象
        #     obj = cls()
        #     obj.btitle = btitle
        #     obj.bpub_date = bpub_date
        #     # 添加进数据库
        #     obj.save()
        #     # 返回obj
        #     return obj
    

    小结:

    在这里插入图片描述
    【模型管理器对象】

    1. 改变原有查询的结果集。
    2. 封装方法,用户操作管理器对象所在模型类对应的数据表。

    3. 模型管理器类、模型类间关系

    在这里插入图片描述

    四、元选项(指定表名)

    Django默认生成的表名: 应用名小写_模型类名小写。

    元选项:

    需要在模型类中定义一个元类Meta,在里面定义一个类属性db_table就可以指定表名。
    在这里插入图片描述

    应用场景:应用名(app1)和表名不一致情形

    【问题】比如对应用名不满意想换个别的名字,此时表名已经生成了,这时应该怎么办呢?

    • 【解决】就可通过元选项解决。

    实战app1/models.py

    【1】指定表的名字

    class AreaInfo(models.Model):
        '''地区模型类'''
        # 地区名称
        atitle = models.CharField(max_length=20)
        # 关系属性,代表当前地区的父级地区
        aParent = models.ForeignKey('self', null=True, blank=True)
    
        class Meta: #【1】指定表的名字
            db_table = 'areas'
    
  • 相关阅读:
    pandas Series和DataFrame数据类型
    numpy 统计函数与随机数
    numpy 索引
    numpy 数组复制与广播机制
    numpy 合并数组和切割数组
    numpy 添加删除去重及形状变换
    项目导入问题---讨厌的红色感叹号
    SpringMVC框架-----概述(2)
    SpringMVC框架-----概述(1)
    SpringBoot框架----概述(1)
  • 原文地址:https://www.cnblogs.com/chenxi188/p/12176686.html
Copyright © 2011-2022 走看看