Django的平常-模型层(1)

Django的平常-模型层(1)

模型层

模型层其实就是咱们应用名下的models.py文件,咱们在里面写入想要建立的表的表结构,以类的形式表示出来,而后经过django的ORM来实现表的建立,以及表的增删改查等.python

django测试环境

不是正式开发项目的话,其实咱们没必要要必定按正式的流程来,又要建html,又要写urls,写views,由于咱们在学习模型层的时候其实只须要经过ORM来对数据库进行操做,因此咱们大能够搭建一个django的测试环境,以此来实验咱们的一些命令,建立测试环境的步骤以下:mysql

# 咱们须要在应用名下的test.py里面写入以下语句来搭建测试环境

#test.py

import os


if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "建立的项目名字.settings")
    import django
    django.setup()
    
    #在下方写须要测试的对数据库操做的代码便可

另外有一个小点,就是咱们在经过ORM对数据库操做的时候,若是咱们想看到ORM转换过程当中的sql语句,须要在settings.py进行如下的配置git

# settings.py ,在最下方加入这个配置项便可
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level': 'DEBUG',
        },
    }
}

ORM查询

ORM的概念咱们在前文已经介绍过了,下面咱们来看ORM对于数据库的一些具体操做sql

在写ORM语句以前咱们首先要有一个数据库,以及配置好当前django所用的数据库,步骤以下数据库

# 首先,删除或者注释掉settings.py里面的DATABASES选项,而后手动加一个本地数据库的信息

# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mysql1',
        'USER': 'root',
        'PASSWORD': "root",
        'HOST': '127.0.0.1',
        'PORT': 3306,
        'CHARSET': 'utf8'
    }
}
# 设置过这个配置项以后咱们还须要在项目名文件夹下的__init__.py里面写入以下两行代码,以便于让django默认的数据库链接方式从MySQLdb转换成pymysql
import pymysql
pymysql.install_as_MySQLdb()

而后咱们须要在models.py里面写本身想要建立的表结构django

'''咱们以书店为例,须要建立的表为,书籍表,做者表,做者详情表,出版社表,其中
    书籍-出版社,一对多
    做者-做者详情,一对一
    书籍-做者,多对多
'''

# models.py
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    publish_date = models.DateField(auto_now_add=True)
    """
    auto_now:每次修改数据的时候 都会自动更新时间
    auto_now_add:在建立数据的时候 会自动将当前时间记录下来
    后期若是你不人为修改的话 数据不变 
    """

    # 书籍与出版社 是一对多关系
    publish = models.ForeignKey(to='Publish')
    # 书籍与做者 是多对多
    authors = models.ManyToManyField(to='Author')
    """
    authors虚拟字段
        1.告诉orm自动帮你建立第三张关系表
        2.orm查询的时候  可以帮助你更加方便的查询
    """
    
    
class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)
    
    
class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    # author_detail = models.ForeignKey(unique=True,to='AuthorDetail')
    author_detail = models.OneToOneField(to='AuthorDetail')
    
    
class AuthorDetail(models.Model):
    phone = models.BigIntegerField()
    addr = models.CharField(max_length=64)

单表查询

单表查询,顾名思义就是在一张表内进行数据查询,下面的语句就是单表查询所经常使用的一些方法学习

# 对数据库的操做无外乎就是增删改查,下面逐一介绍,下面的语句都是写在test.py里面,就是咱们前面搭建好的测试环境里面
# test.py

from 应用名 import models

# 增
# 方式一,直接调用create添加数据
models.Book.objects.create(title='jpm',price=123.23,publish_date='2019-10-24')
# 方式二,生成对象,以对象.save的方式保存数据
from datetime import date
ctime = date.today()    # 时间格式是能够直接使用date的日期的
book_obj = models.Book(title='sgyy',price=666.66,publish_date=ctime)
book_obj.save()

# 改
# 方式一,以update的方式更新数据
models.Book.objects.filter(pk=1).update(price=999.66)
# 方式二,生成对象,直接修改,而后用.save保存
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.title = '不符合社会主义核心价值观'
book_obj.save()

# 删除
# 筛选出符合条件的记录直接delete()便可
models.Book.objects.filter(pk=1).delete()

# 查
    # 1.all()  查询全部
    res = models.Book.objects.all()  
    # 惰性查询,惰性查询的概念在于,若是咱们只是定义了这个语句的话,他并不会执行,只有在调用它,好比打印的时候,这个语句才会真正运行,查询的这么多方法里面大都是惰性查询
    print(res)
    for i in res:
       print(i.title)

    # 2.filter() 按照条件查询,会匹配到全部符合条件的记录,且filter能够无限叠加
    res = models.Book.objects.filter(pk=2)
    print(res)

    # 3.get()  能够拿到数据对象自己,可是若是符合条件的记录不存在,会报错,因此不推荐使用

    # 4.first()     拿第一个
    res = models.Book.objects.all()
    print(res)
    print(res.first())

    # 5. last()     拿最后一个
    res = models.Book.objects.all()
    print(res)
    print(res.last())

    # 6.exclude()  除此以外,即符合条件的记录不取,取剩余的所有记录
    res = models.Book.objects.exclude(pk=3).filter(pk=4).filter(pk=1).filter(pk=4)
    print(res)

    # 7.values 返回数据的格式是列表套字典
    res = models.Book.objects.values('title')
    for r in res:
        print(r.get('title'))

    # 8.values_list 列表套元组
    res = models.Book.objects.values_list('title')
    print(res)

    # 9.count()  统计数据的个数
    res = models.Book.objects.count()
    res1 = models.Book.objects.all().count()
    print(res,res1)

    # 10.distinct() 去重
    """去重:数据必须是如出一辙的状况下才能去重,包括主键,尤为要注意"""
    res = models.Book.objects.all().distinct()
    res1 = models.Book.objects.values('title','price').distinct()
    print(res1)

    # 11.order_by() 以某个标准排序
    res = models.Book.objects.order_by('price')  # 默认是升序
    res1 = models.Book.objects.order_by('-price')  # 加负号就是降序
    print(res)
    print(res1)

    # 12.reverse()  注意,前面必须是先通过排序后的数据才能够反转,不然反转会无效,数据顺序不会发生变化
    res = models.Book.objects.order_by('price').reverse()
    print(res)

    # 13.exists()  排除符合条件的记录,不太经常使用
    res = models.Book.objects.filter(pk=1).exists()
    print(res)


# 查询还有一类比较好用的方法,即双下划线的方式
# 双下划线能够实现不少很是神奇的筛选方法,好比大于小于,或者是限定范围,还支持模糊匹配

# 1. __gt和__gte,gt是大于,gte是大于等于
res1 = models.Book.objects.filter(price__gt=300)
res2 = models.Book.objects.filter(price__gte=300)
# 上面的语句分别能够查询获得价格大于300和大于等于300的图书的对象

# 2. __lt和__lte,lt是小于,lte是小于等于
res1 = models.Book.objects.filter(price__lt=300)
res2 = models.Book.objects.filter(price__lte=300)
#上面语句能够查询获得价格小于300和小于等于300的全部图书的对象

# 3. __in和__range,in是否在其内,后面一般为容器类型,range,是否在一个范围内,后面一般跟元组表示范围
res = models.Book.objects.filter(price__in=[100,200,456,]) #筛选范围仅仅是列表内的这几个值
res = models.Book.objects.filter(price__range=(100,499)) #筛选价格在100到499范围内的书,这里是顾头不顾尾的,即价格为100的书在范围内,可是价格为499的书不在范围内.

# 咱们知道sql语句里面的模糊匹配其实就只有like,再加上%或者_,%是任意位数的任意字符,而_是一位的任意字符

# 双下划线能够实现ORM里面的模糊匹配,经常使用的几个方法包括contains,icontains,startswith,endswith,year,month等等.

# 1. contains 按字符模糊匹配,区分大小写
# 2. icontains 按字符模糊匹配,不区分大小写
# 3. startswith 以某个字符开头
# 4. endswith 以某个字符结尾
# 5. year 用于断定日期格式数据的年份
# 6. month 用于判断日期格式数据的月份

多表查询

上面咱们介绍了单表查询的一些方法和语句,下面就来看看多表查询经常使用的一些方法测试

咱们依然从增删改查四个方面来分析多表间的操做:url

# 多对多表关系之间修改字段的四个方法,add,set,remove以及clear

# 1. add()添加,括号内能够填多个值,会生成多条记录,其实修改的是多对多的那个关系表,add的括号里面能够传数字,也能够直接传一个对象,ORM会自动把该对象的主键的值取出来,传给add使用,好比

    # 传数字
    book_obj = models.Book.objects.filter(pk = 1).first()#这里取出一个书籍对象
    book_obj.authors.add(1)# 书籍对象.做者,其实获得的就是二者的关系表
    # 传对象
    author_obj = models.Author.objects.filter(pk=1).first()
    book_obj.authors.add(author_obj)

# 2. set() 修改,用法和add类似,也支持多个值,支持传数字和对象,不一样的是括号里要是一个可迭代对象,也就是说括号内不能为一个单独的值,而应该是列表,元素,字典或者集合这种可迭代对象
    # 传数字
    book_obj = models.Book.objects.filter(pk = 3).first()
    book_obj.authors.set([1,])
    # 传对象
    author_obj = models.Author.objects.filter(pk=1).first()
    book_obj.authors.set((author_obj,))#这里是元组,注意,元组若是只有一个值,要加逗号,否则会报错
    
# 3. remove(),移除某条记录,能够传数字和对象,支持传多个值
    # 传数字
    book_obj = models.Book.objects.filter(pk = 3).first()
    book_obj.authors.remove(2)
    # 传对象
    author_obj = models.Author.objects.filter(pk=1).first()
    book_obj.authors.remove(author_obj)
# 4. clear(),清空,括号内不须要任何值,能够直接清空当前关系表
    book_obj = models.Book.objects.filter(pk=2).first()
    book_Obj.authors.clear() # 这里会拿到做者和书籍的关系表,而后把book表里主键值为2对应的全部数据清空

由于实际生产环境中其实仍是多表用的比较多,毕竟不少数据都不是放在一块儿的,这时候咱们就须要经过联表或者是经过子查询的方式来解决数据查询的问题,因此ORM提供给咱们两个更好的多表查询的方法,其原理依然仍是联表和子查询,不过其叫法不一样

  1. 基于对象的跨表查询其实就是子查询
  2. 基于双下划线的跨表查询其实就是联表查询.

这里咱们还要清楚一个正向查询和反向查询的概念,即咱们从外键所在的表向外面的表查询的时候,叫作正向查询,反过来就叫作反向查询.

'''基于对象的跨表查询'''
#顾名思义,咱们要经过筛选并生成出一个对象,而后从这个对象连到其余表,再查询取值,好比:

# 正向查询
    # 单个值
    book_obj = models.Book.objects.filter(title='python').first()
    print(book_obj.publish.name)#这里用书籍对象直接.出版社,此时其实就已经到了publish表里面,而后直接.name就能够拿到相对应的值,这里由于书籍对应的出版社都是单个值,因此能够直接取值

    # 多个值
    book_obj = models.Book.objects.filter(pk = 1).first()
    print(book_obj.authors) # 咱们能够看到这里返回结果是  应用名.Author.None,这并不意味着咱们的语句写错了,而是返回的结果不是单个值,咱们取不到
    print(book_obj,authors.all())# 因此若是查询到结果是多个值,要在后面加.all(),才能正常看到返回结果

# 反向查询
    # 单个值
    author_detail_obj = models.AuthorDetail.objects.filter(pk=1).first()
    print(author_detail_obj.author)
    print(author_detail_obj.author.name)
    # 多个值
    publish_obj = models.Publish.objects.filter(pk = 1).first()
    print(publish_obj.book_set) # 这里结果是 应用名.Book.None,是否是很熟悉?对,要加.all()
    print(publish_obj.book_set.all())
    #总结下来就是,反向查询时,当查询结果是多个值的时候,须要加_set.all()在后面,而查询结果只有一个值的话不须要加这个
'''基于双下划线的跨表查询'''
# 上文中咱们说过,基于双下划线的跨表查询其实就是联表查询,那么在原生sql里面联表方式有几种呢?四种,即左联left join,右联right join,内联inner join,全联 union.在当前的ORM里面咱们没必要关心这些联表方式,内部会帮咱们作处理,咱们须要作的只是理清楚查询逻辑,或者说其实咱们只须要认清楚是正向查询仍是反向查询就能够了.

# 和双下划线相匹配使用的方法就是.values()
res = models.Book.objects.filter(pk=1).values('publish__name')
print(res)
# 上面以书籍的主键来寻找到出版社的名字是正向查询,那么与之对应的反向查询以下
res = models.Publish.objects.filter(book__pk=1),values('name')
print(res)
相关文章
相关标签/搜索