zoukankan      html  css  js  c++  java
  • web框架-(四)Django进阶之数据库对象关系映射

    Django ORM基本配置

    到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞:

    • 创建数据库,设计表结构和字段
    • 使用 MySQLdb 来连接数据库,并编写数据访问层代码
    • 业务逻辑层去调用数据访问层执行数据库操作

    django为使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM),django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表;

    1、修改project数据库配置(程序主目录下的settings.py文件)

    默认连接数据库为本地文件sqlite3:

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        }
    } 

    更换为指定的mysql数据库:

    DATABASES = {
        'default': {
        'ENGINE': 'django.db.backends.mysql',  
        'NAME':'cc',              #数据库名
        'USER': 'root',              #账号
        'PASSWORD': '123456',      #密码
        'HOST': '192.168.28.129',   #mysql数据库IP
        'PORT': '3306',              #对端端口
        }
    }

    2、创建定义数据库表结构文件(对应app目录下的models.py文件)

    生成一个简单的数据库表:

    from django.db import models
     
    # Create your models here.
     
    class UserInfo(models.Model):
        # 创建的表名名称为cmdb_userinfo
        # 数据库默认创建id列 自增 主键
        # 用户名列 字符串类型 字符长度
        username = models.CharField(max_length=32)   #  max_length 字符长度
        passwd = models.CharField(max_length=64)

    把对应的app名称加入到settings.py文件配置里:

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'cmdb',          # 系统会加载cmdb下的model.py文件
    ]       

    3、生成数据库表

    执行下面命令:

    python manage.py  makemigrations
    python manage.py  migrate         # 生成数据表
    

    查看数据库表详情:

    mysql> desc cmdb_userinfo;
    +----------+-------------+------+-----+---------+----------------+
    | Field    | Type        | Null | Key | Default | Extra          |
    +----------+-------------+------+-----+---------+----------------+
    | id       | int(11)     | NO   | PRI | NULL    | auto_increment |
    | username | varchar(32) | NO   |     | NULL    |                |
    | passwd   | varchar(64) | NO   |     | NULL    |                |
    +----------+-------------+------+-----+---------+----------------+
    3 rows in set (0.01 sec)
    

    注意:Django默认用的MysqlDB模块连接数据库,但在python3.x里面还没有这个模块,所有需要把连接数据库的模块改成pymsyql,修改project目录下的init.py文件

    import  pymysql
    pymysql.install_as_MySQLdb()
    

    4、数据库字段和字段参数

    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 文件
    所有字段
    null               -> db是否可以为空
    default            -> 默认值
    primary_key        -> 主键
    db_column          -> 列名
    db_index           -> 索引
    unique               -> 唯一索引
    unique_for_date    ->
    unique_for_month
    unique_for_year
    auto_now           -> 创建时,自动生成时间
    auto_now_add       -> 更新时,自动更新为当前时间
    choices              -> django admin中显示下拉框,避免连表查询
    blank             -> django admin是否可以为空
    verbose_name      -> django admin显示字段中文
    editable          -> django admin是否可以被编辑
    error_messages    -> 错误信息欠
    help_text         -> django admin提示
    validators          -> django
    form, 自定义错误信息(欠)
    
    所有字段参数...
    所有字段参数

    Django 数据库操作

    1. 增加数据

    ①常用方法

    from cmdb import models
    def ormadd(request):
        models.UserInfo.objects.create(username="James",passwd="8888")
     
        return HttpResponse("ormadd")

    ②常用方法的另外一种写法

    from cmdb import models
    def ormadd(request):
        dicts = {'username':"James",'passwd':"8888"}
        models.UserInfo.objects.create(**dicts)
     
        return HttpResponse("ormadd")

    ③第二种方法

    from cmdb import models
    def ormadd(request):
        obj = models.UserInfo(username='root',passwd='123')
        obj.save()
     
        return HttpResponse("ormadd")
    

    2. 删除数据

    from cmdb import models
    def ormdel(request):
        models.UserInfo.objects.filter(id=3).delete()
     
        return HttpResponse("ormdel")
    

    3. 更新数据

    ①第一种方式

    from cmdb import models
    def ormupdate(request):
            models.User.objects.filter(id__gt=1).update(name='cc',age=18)
            return HttpResponse("ormupdate")

    ②第二种方式

    from cmdb import models
    def ormupdate(request):
            dic = {'name': 'cc', 'age': 19}
    	models.User.objects.filter(id__gt=1).update(**dic)
            return HttpResponse("ormupdate")
    

    4. 查询数据

    ①查询所有数据

    from cmdb import models
    def ormselect(request):
        result = models.UserInfo.objects.all()
        print(result)       # QuerySet类型 列表里每个元素都是一个obj对象
        # <QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>
        for row in result:
            print(row.id,row.username,row.passwd)
            # 1 James 8888
            # 2 root 123
            # 3 James 8888
        return HttpResponse("ormselect")

    ②查找指定字段

    from cmdb import models
    def ormselect(request):
        result = models.UserInfo.objects.filter(username='root')  # filter()里可以用,分开 表示and
        if result:
            for row in result:
                print(row.id,row.username,row.passwd)
                # 2 root 123
     
        return HttpResponse("ormselect")

    ③获取查询第一条数据和统计匹配个数

    from cmdb import models
    def ormselect(request):
        obj = models.UserInfo.objects.filter(username='root').first()  # 获取匹配的第一条字段
        c = models.UserInfo.objects.filter(username='root').count()  # 获取匹配的字段个数
        
        return HttpResponse("ormselect")

    ④比较值查询以及多条件查询

    models.User.objects.filter(id=1,name='root')        # id等于1且name等于root
    models.User.objects.filter(id__gt=1,name='root')    # id大于1
    models.User.objects.filter(id__lt=1)                 # id小于1
    models.User.objects.filter(id__gte=1)                # id大等于
    models.User.objects.filter(id__lte=1)                # id小等于  

    ⑤指定查询数据库某个字段的所有数据

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <p>项目组(对象) v1</p>
        <ul>
            {% for row in v1 %}
                <li>{{ row.id }}-{{ row.caption }}-{{ row.code }}</li>
            {% endfor %}
        </ul>
        <p>项目组(字典) v2</p>
        <ul>
            {% for row in v2 %}
                <li>{{ row.id }}-{{ row.caption }}</li>
            {% endfor %}
        </ul>
        <p>项目组(元组) v3</p>
        <ul>
            {% for row in v3 %}
                <li>{{ row.0 }}-{{ row.1 }}</li>
            {% endfor %}
        </ul>
    </body>
    </html>
    business.html

    获取表单数据:

    def business(request):
        v1 = models.Business.objects.all()# QuerySet ,内部元素都是对象
        print("v1",v1)
        # v1 < QuerySet[ < Business: Business object >, < Business: Business object >,
        # < Business: Business object >, < Business: Business object >] >
     
        v2 = models.Business.objects.all().values("id","caption") # QuerySet ,内部元素都是字典
        print("v2",v2)
        # v2 < QuerySet[{'caption': '运维', 'id': 1}, {'caption': '开发', 'id': 2}, {'caption': '销售', 'id': 3},
        # {'caption': '市场', 'id': 4}] >
     
        v3 = models.Business.objects.all().values_list("id","caption") # QuerySet ,内部元素都是元组
        print("v3",v3)
        # v3 < QuerySet[(1, '运维'), (2, '开发'), (3, '销售'), (4, '市场')] >
     
        return render(request,'business.html',{'v1':v1,'v2':v2,'v3':v3})
    

    注:values和values_list后不指定字段的话,获取的是所有的字段数据

    5. 单表外键关联

    ①数据库表结构

    from django.db import models
     
    # Create your models here.
     
    class UserInfo(models.Model):
        # 创建的表名名称为cmdb_userinfo
        username = models.CharField(max_length=32)
        passwd = models.CharField(max_length=64)
        # 关联外键   生成字段名为user_group_id
        user_group = models.ForeignKey("UserGroup",to_field='uid',default=1)    #关联usergroup表的uid字段默认为1
     
    class UserGroup(models.Model):
        # 创建的表名名称为cmdb_usergroup
        uid = models.AutoField(primary_key=True)    #主键 自增
        caption = models.CharField(max_length=32,unique=True)   #唯一索引
        ctime = models.DateField(auto_now_add=True,null=True)   #创建时生成时间
        uptime = models.DateField(auto_now=True,null=True)  #更新是自动更新时间

    ②外键关联表操作

    from cmdb import models
    def ormadd(request):
        models.UserInfo.objects.create(username="James",passwd="8888")
        return HttpResponse("ormadd")
    def ormgroup(request):
        models.UserGroup.objects.create(caption="CEO")
        return HttpResponse("ormgroup")
     
    def userinfo(request):
        obj = models.UserInfo.objects.all().first()
        # user_group_id 指定的是userinfo表里存的id号
        print(obj.id,obj.username,obj.user_group_id)
        # 1 James 1
     
        # user_group 指定的是用户组obj对象
        print(obj.user_group.uid,obj.user_group.caption)
        # 1 CEO
        return HttpResponse("userinfo")

    ③跨表查询,神奇的双下划綫__

    class Business(models.Model):
        # id
        caption = models.CharField(max_length=32)
        code = models.CharField(max_length=32,null=True,default="SA")
    
    
    class Host(models.Model):
        nid = models.AutoField(primary_key=True)
        hostname = models.CharField(max_length=32,db_index=True)
        ip = models.GenericIPAddressField(protocol="ipv4",db_index=True)
        port = models.IntegerField()
        b = models.ForeignKey(to="Business", to_field='id')
    models.py

    获取表单数据:

    def home(request):
        # b__capiton 通过双下划线直接跨表获取对应caption的数据
        v2 = models.Host.objects.filter(nid__gt=0).values('nid','hostname','b_id','b__caption')
        # < QuerySet[{'nid': 2, 'b__caption': '开发', 'hostname': '系统1', 'b_id': 2},
        # {'nid': 3, 'b__caption': '销售','hostname': '系统2', 'b_id': 3}>
     
        return render(request, 'home.html')
    

    Django数据库多对多操作

    1. 自定义创建关系表

    class Host(models.Model):
        nid = models.AutoField(primary_key=True)
        hostname = models.CharField(max_length=32,db_index=True)
        ip = models.GenericIPAddressField(protocol="ipv4",db_index=True)
        port = models.IntegerField()
        b = models.ForeignKey(to="Business", to_field='id')        # 这里先忽略
     
    class Applications(models.Model):
        name = models.CharField(max_length=32)
         
    class HostToAPP(models.Model):
        # 可以自定义多种字段
        hobj = models.ForeignKey(to='Host',to_field='nid')
        aobj = models.ForeignKey(to='Applications',to_field='id')

    创建数据:

    HostToAPP.objects.create(hobj_id=1,aobj_id=2)

    2. 自动创建关系表

    class Host(models.Model):
        nid = models.AutoField(primary_key=True)
        hostname = models.CharField(max_length=32,db_index=True)
        ip = models.GenericIPAddressField(protocol="ipv4",db_index=True)
        port = models.IntegerField()
        b = models.ForeignKey(to="Business", to_field='id')        # 这里先忽略
     
    class Applications(models.Model):
        name = models.CharField(max_length=32)
     
        r = models.ManyToManyField("Host")
    

    自动生成第三张关联表cmdb_applications_r;下面我们就来看看针对这种情况下,如何对表进行操作

    ①增加

    # 第三张表增加
    obj = models.Application.objects.get(id=1)
     
    obj.r.add(1)        # 创建id=1,nid=1
    obj.r.add(2)        # 创建id=1,nid=2
    obj.r.add(2, 3, 4)      # 创建id=1,nid=2、id=1,nid=3 、id=1,nid=4
    obj.r.add(*[1, 2, 3, 4])  # 同上

    ②删除

    # 第三张表删除
    obj = models.Application.objects.get(id=1)
     
    obj.r.remove(1)     # 删除id=1,nid=1
    obj.r.remove(2,4)    # 删除id=1,nid=2、id=1,nid=4
    obj.r.remove(*[1,2,3])  # 批量删
     
    obj.r.clear()       # 所有id=1的关系删除

    ③更新

    # 第三张表更新
    obj = models.Application.objects.get(id=1)
     
    obj.r.set([3,5,7])      # 清空原来的id=1关系,创建id=1,nid=3;id=1,nid=5;id=3,nid=7
                            # 等同于执行obj.r.clear()再执行obj.r.add(*[3,5,7])

    ④查询

    # 第三张表查询
    obj = models.Application.objects.get(id=1)
     
    # 所有相关的主机对象“列表” QuerySet
    obj.r.all()             # 所有对应的Host对象
    

    Django练习

    上面学习了很多知识,然并卵,咱们还是结合具体的实例看下吧~!

  • 相关阅读:
    优化SQL查询:如何写出高性能SQL语句
    提高SQL执行效率的16种方法
    Spring Ioc DI 原理
    java内存泄漏
    转:js闭包
    LeetCode Best Time to Buy and Sell Stock III
    LeetCode Best Time to Buy and Sell Stock with Cooldown
    LeetCode Length of Longest Fibonacci Subsequence
    LeetCode Divisor Game
    LeetCode Sum of Even Numbers After Queries
  • 原文地址:https://www.cnblogs.com/cocc/p/6198025.html
Copyright © 2011-2022 走看看