欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

django之模型层

程序员文章站 2022-04-14 18:58:31
[TOC] 配置测试脚本 第一种方法: 直接在某一个应用下的test文件中书写(前四行代码去manage.py中拷贝): 第二种方法: 直接新建一个任意名称的py文件 在里面写上上面的配置 ORM单表操作 先前操作 创建数据 修改数据 注: 会自动查找当前表的主键字段 filter查询出来的结果是一 ......

配置测试脚本

第一种方法:

  • 直接在某一个应用下的test文件中书写(前四行代码去manage.py中拷贝):

    import os
    
    if __name__ == "__main__":
        os.environ.setdefault("django_settings_module", "mysite.settings")
    
        import django
        django.setup()

第二种方法:

直接新建一个任意名称的py文件 在里面写上上面的配置

orm单表操作

先前操作

# 模型类
class books(models.model):
    title = models.charfield(max_length=32)
    price = models.decimalfield(max_digits=8, decimal_places=2)
    publish_date = models.datefield()

创建数据

# 方式1:create方法
models.books.objects.create(title='三国演义', price=345.66, publish_date='2019-11-27')

# 方式2:利用对象的绑定方法
book_obj = models.books(title='红楼梦', price=235.66, publish_date='2018-09-12')
book_obj.save()

修改数据

# 方式1:利用queryset方法
res = book_obj = models.books.objects.filter(pk=1).update(price=320.23)
print(res)    # <queryset [<books: books object>]>


# 方式2:利用对象 (不推荐使用)   利用对象修改 内部其实是从头到尾将数据的所有字段都重新写一遍
book_obj = models.books.objects.get(pk=2)
book_obj.price = 150.33
book_obj.save()

注:

  • pk会自动查找当前表的主键字段
  • filter查询出来的结果是一个queryset对象

queryset对象特点

  • 只要是queryset对象就可以无限制的调用queryset的方法

    book_obj = models.books.objects.filter(pk=1).filter().filter()
    # 可以无限制 的删选
  • 只要是queryset对象就可以用句点符 点query查看当前内部对应的sql语句

    book_obj = models.books.objects.filter(pk=1)
    print(book_obj.query)

get和filter区别

  • filter获取到的是一个queryset对象,类似于一个列表
  • get获取到的直接就是数据对象本身
  • 当条件不存在时,filter不报错直接返回一个空,get直接报错

删除数据

# 方式1:
models.books.objects.filter(pk=7).delete()

# 方式2:
book_obj = models.books.objects.get(pk=6)
book_obj.delete()

必知必会13条操作

如果想要在终端查看 orm对应的sql语句,可以在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',
        },
    }
}

1. all() 查询所有

返回的是queryset对象

res = models.books.objects.all()
print(res)

注意:orm语句的查询默认是惰性查询,只有当你真正使用数据的时候才会执行orm语句

2. filter() 筛选

相当于原生sql语句的where

res = models.books.objects.filter(pk=3, title='人')  # 可以传多个参数,and关系
print(res)

3. get()

筛选,获取的是数据对象本身,条件不存在时报错, 而且查询条件只能是一个

res = models.books.object.get(pk=2)
print(res)

4. first()

取queryset中第一个数据对象

res = models.books.objects.filter(title='西游记').first()
print(res.price)

5. last()

取queryset中最后一个数据对象

res = models.books.objects.filter(title='西游记').last()
print(res)

6. count()

统计数据的个数

num = models.books.objects.count()
print(num)

7. values()

获取对象中指定字段的值,可以传多个参数,返回的是 queryset对象 列表套字典

res = models.books.objects.values('title','price')
print(res)

8. values_list()

获取对象中指定字段的值,可以传多个参数,返回的是 queryset对象 列表套元组

res = models.books.objects.values_list('title','price')
print(res)

9. order_by()

按照指定的字段排序, 默认是升序

降序只要在字段前面加负号(-)

res = models.books.objects.order_by('price')
res = models.books.objects.all().order_by('price')   # 两者等价,默认是升序

res = models.books.objects.order_by('-rice')

10. reverse()

颠倒顺序的前提是 颠倒的对象必须要有顺序(提前排序之后才能颠倒顺序)

所以必须和order_by联用

res = models.books.objects.order_by('price')
res1 = models.books.objects.all().order_by('price').reverse()
print(res1)

11. exclude()

排除

res = models.books.objects.all().exclude(title='人间失格')
print(res)

12. exists()

判断查询结果是否有值,返回结果是一个布尔值

res = models.books.objects.filter(pk=12).exists()
print(res)

13. distinct()

对查询结果去重,但是必须要有完全相同的数据,才能去重

注意:主键id不一样,会忽略

res = models.books.objects.values('title','price').distinct()
print(res)

双下划线查询

  • __gt 大于
  • __lt 小于
  • __gte 大于等于
  • __lte 小于等于
  • __range 范围查询 顾头顾尾
  • __in 在里面
  • __year
  • __month
# 查询价格大于200的书籍
res = models.books.objects.filter(price__gt=200)
print(res)

# 查询价格小于300 的书籍
res = models.books.objects.filter(price__lt=200)
print(res)

# 查询价格大于等于200
res = models.books.objects.filter(price__gte=200)
print(res)

# 查询价格小于等于200
res = models.books.objects.filter(price__lte=200)
print(res)

# 查询价格在200~300之间的书籍
res = models.books.objects.filter(price__range(200, 300))   # 顾头顾尾
print(res)

# 查询价格是200 或 300 的书籍
res = models.books.objects.filter(price__in[200, 300])
print(res)

# 查询出版日期为2019年的书籍
res = models.books.objects.filter(publish_date__year=2019)
print(res)


# 查询出版日期是11月份的书籍
res = models.books.objects.filter(publish_date__month=11)
print(res)
  • __startswitch 以....开头
  • __endswith 以...结尾
  • __contains 包含 如果查询字母,默认区分大小写
  • __icontainsi 忽略大小写
# 查询书籍是以“人”开头的书
res = models.books.objects.filter(title__startswith='人')
print(res)

# 查询书籍是以“梦”结尾的书
res = models.books.objects.filter(title__endswith='梦')
print(res)

# 查询书籍名称中包含“的”字的书籍
res = models.books.objects.filter(title__contains='的')
print(res)

# 查询书籍名称中包含字母p的书籍
res = models.books.objects.filter(title__contains='p')   # 默认区分大小写
res = models.books.objects.filter(title__icontains='p')  # 加i不区分大小

一对多字段外键增删改查

准备工作

先建立图书表、出版社表、作者表、作者详情表

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)

    publish = models.foreignkey(to='publish')
    authors = models.manytomanyfield(to='author')


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)
    email = models.emailfield()

    author_detail = models.onetoonefield(to='authordetail')


class authordetail(models.model):
    phone = models.bigintegerfield()
    addr = models.charfield(max_length=64)

花式操作

增:

# 方法1 :直接传表里面的实际字段
models.book.objects.create(title='人间失格', price=123.56, publish_id=1)

# 方法2 :传虚拟字段  跟数据对象即可
publish_obj = models.publish.objects.filter(pk=2).first()
models.book.objects.create(title='水浒传', price=223.45, publish=publish_obj)

改:

# 方法1: 直接传实际字段
models.book.objects.filter(pk=1).update(publish_id=2)

# 方法2:传数据对象
publish_obj = models.publish.objects.filter(pk=1).first()
models.book.objects.filter(pk=1).update(publish=publish_obj)

删:

# 默认就是级联删除 级联更新
models.publish.objects.filter(pk=1).delete()

多对多外键字段的增删改查

增:add

book_obj = models.book.objects.filter(pk=1).first()
book_obj.authors.add(1)   # book_obj.authors 就已经进入第三张表了

book_obj.authors.add(1, 2)  # 添加两个书籍作者



# 同样支持传数据对象
book_obj = models.book.objects.filter(pk=2).first()
author_obj = models.author.objects.filter(pk=2).first()
book_obj.authors.add(author_obj)

# 数据对象也支持传多个
book_obj = models.book.objects.filter(pk=2).first()
author_obj1 = models.author.objects.filter(pk=1).first()
author_obj2 = models.author.objects.filter(pk=2).first()
book_obj.authors.add(author_obj1, author_obj2)

add方法 能够想第三张关系表添加数据

  • 支持传数字
  • 也支持传对象,并且两者都可以是多个

改:set

# 方法1:传字段
book_obj = models.book.objects.filter(pk=2).first()
book_obj.authors.set([1, 3])
book_obj.authors.set([1,])   # set里面要传可迭代对象

# 方法2:传数据对象
author_obj1 = models.author.objects.filter(pk=1).first()
author_obj2 = models.author.objects.filter(pk=2).first()
book_obj.authors.set((author_obj1,author_obj2))

set方法 能修改多对多关系表中的数据

  • 可以传数字,也可以传对象,都支持传多个
  • set里面传的是可迭代对象

删:remove

# 方法1:传字段
book_obj = models.book.objects.filter(pk=2).first()
book_obj.authors.remove(1)
book_obj.authors.remove(1, 2)   # 支持多个


# 方法2:传数据对象
book_obj = models.book.objects.filter(pk=1).first()
author_obj = models.author.objects.filter(pk=1).first()
book_obj.authors.remove(author_obj)

remove方法 能删除多对多关系表中的数据

  • 可以传数字,也可以传对象,
  • 都支持传多个, 不需要传迭代对象

清空:clear

book_obj = models.book.objects.filter(pk=2).first()
book_obj.authors.clear()

clear清空数据,括号里面不需要传参数

跨表查询

正反向查询

  • 正向查询 关系字段在谁那,由有关系字段的表查,就是正向查询
  • 反向查询 关系字段不在那

正向查询按字段,反向查询按表名小写 + _set

基于对象的跨表查询(子查询)

# 1.查询书籍主键为2的出版社名称
book_obj = models.book.objects.filter(pk=2).first()
print(book_obj.publish.name)

# 2.查询书籍主键为4的作者姓名
book_obj = models.book.objects.filter(pk=1).first()
# print(book_obj.authors)    # app01.author.none
print(book_obj.authors.all())  # 当正向查询点击外键字段数据有多个的情况下 需要.all()

# 3.查询作者是式微的手机号码
author_obj = models.author.objects.filter(name='式微').first()
print(author_obj.author_detail.phone)


# 4.查询出版社是东方出版社出版过的书籍
publish_obj = models.publish.objects.filter(name='东方出版社').first()
print(publish_obj.book_set.all())

# 5.查询手机号是120的作者姓名
author_detail_obj = models.authordetail.objects.filter(phone=120).first()
print(author_detail_obj.author.name)

# 6.查询作者是无名写过的书籍
author_obj = models.author.objects.filter(name='无名').first()
print(author_obj.book_set.all())

总结:

  • 正向查询,点击外键字段数据有多个的情况下 需要.all()
  • 反向查询,一对多和多对多需要表名 + _set,一对一不需要加_set

基于双下划线的跨表查询(联表查询)

# 1.查询书籍pk为2的出版社名称
res = models.book.objects.filter(pk=2).values('publish__name')
print(res)
res = models.publish.objects.filter(book__pk=2).values('name')

# 2.查询书籍pk为2的作者姓名和邮箱
res = models.book.objects.filter(pk=2).values('authors__name', 'authors__email')
print(res)
res = models.author.objects.filter(book__pk=2).values('name', 'email')

# 3.查询作者是邶风的家庭地址
res = models.author.objects.filter(name='邶风').values('author_detail__addr')
print(res)
res = models.authordetail.objects.filter(author__name='邶风').values('addr')


# 4.查询出版社是东方出版社出版过的书的名字
res = models.publish.objects.filter(name='东方出版社').values('book__title')
print(res)
res = models.book.objects.filter(publish__name='东方出版社').values('title')


# 5. 查询书籍pk是2的作者的手机号
res = models.book.objects.filter(pk=2).values('authors__author_detail__phone')
print(res)
res = models.author.objects.filter(book__pk=2).values('author_detail__phone')