六,一:orm查询,新增,删除

单表查询

Django自带的sqlite3数据库对日期格式不是很敏感,处理的时候容易出错

  • 数据的增加
"""方式一:"""
res = models.User.objects.create(
        username='egon_dsb',
        password='dbj123',
        gender='female',
        age=84,
        phone=18677436477,
        email='18677436477@163.com',
        register_time='2020-5-29'
    )
"""方式二:"""
    user_obj = models.User(
        username='jason_dsb',
        password='hecha444',
        gender='male',
        age=18,
        phone=18306477402,
        email='23446783@qq.com',
        register_time='2020-5-28'
    )
    user_obj.save()
  • 数据的查询
"""
pk:会自动地帮我们找到当前表的主键字段
"""
user_obj = models.User.objects.filter(pk=1).first()
print(user_obj)

"""
当前对象:egon_dsb
"""
  • 数据的删除
"""方式一:"""
user_obj = models.User.objects.filter(pk=2).delete()
"""方式二:"""
user_obj = models.User.objects.filter(pk=1).first()
user_obj.delete()
  • 数据的更改
"""方式一:"""
user_obj = models.User.objects.filter(pk=3).update(username='jason')
"""方式二:"""
    user_obj = models.User.objects.get(pk=3) #返回的是当前额数据对象
    user_obj.username = 'jason_DSB'
    user_obj.save()

get方法与filter方法的区别

当数据对象不存在时,filter方法会返回一个None,而get方法会直接报错,因此推荐使用filter方法。
对比字典的取值,推荐使用get方法,而不使用['键']取值。

常用的单表操作方法

  • 查询出所有的数据
"""
<QuerySet [<User: 当前对象:jason_DSB>, <User: 当前对象:egon_dsb>, <User: 当前对象:egon_dsb>, <User: 当前对象:egon_dsb>, <User: 当前对象:tank_dsb>]>
"""
    query_set = models.User.objects.all()
    for item in query_set:
        print(item)
  • 带过滤条件的查询
user_obj = models.User.object.filter(pk=7)
  • 直接获取数据对象,对象不存在时候报错
user_obj = models.User.object.get(pk=11)
"""
app01.models.DoesNotExist: User matching query does not exist.
"""
  • 获取query_set里面的第一个元素对象
user_obj = models.User.objects.all().first()
  • 获取query_set里面的最后一个元素对象
user_obj = models.User.objects.all().last()
  • 获取指定的数据字段

    query_set对象列表套字典的形式展示

 query_set = models.User.objects.all().values('username','phone')
"""
<QuerySet [{'username': 'jason_DSB', 'phone': 18306477402}, {'username': 'egon_dsb', 'phone': 18677436477}, {'username': 'tank_dsb', 'phone': 13806477412}]>
"""
相当于sql语句
select username,phone from user;

query_set对象列表套元组的形式展示

query_set = models.User.objects.all().values_list('username','phone')
"""
<QuerySet [('jason_DSB', 18306477402), ('egon_dsb', 18677436477), ('tank_dsb', 13806477412)]>
"""

查看内部封装的sql语句:

print(query_set.query)
"""
SELECT `app01_user`.`username`, `app01_user`.`phone` FROM `app01_user`
"""

# 仅适用于queryset对象
  • 去重distinct()
query_set = models.User.objects.all().values_list('username','phone').distinct()

# <QuerySet [('jason_DSB', 18306477402), ('egon_dsb', 18677436477), ('tank_dsb', 13806477412)]>

"""
SELECT DISTINCT `app01_user`.`username`, `app01_user`.`phone` FROM `app01_user`
"""

注意:去重一定是一模一样的数据,因此不能忽略主键的作用,所以可以先values('非唯一的字段',...), 然后再distinct()

  • 排序 order_by
默认升序排序:
query_set = models.User.objects.all().order_by('age')

降序排序:
query_set = models.User.objects.all().order_by('-age')
或者:
query_set = models.User.objects.all().order_by('age').reverse()
  • 反转reverse()
"""
反转的前提是数据已经进行了排序,否则将不做任何操作
"""
query_set = models.User.objects.all().order_by('age').reverse()
  • 统计query_set里对象的个数
count = models.User.objects.all().count()
  • 将某个对象排除exclude
query_set = models.User.objects.all().exclude(username='tank_dsb')

"""
<QuerySet [<User: 当前对象:jason_DSB>, <User: 当前对象:egon_dsb>]
"""
  • 判断对象是否存在exists(),返回一个布尔值
is_exists = models.User.objects.filter(pk=12).exists()
print(is_exists)  # False
基本用不到,因为查询数据本身就自带布尔值

测试脚本

当你仅仅只是想测试django某一py文件的内容,可以直接写个测试脚本,脚本可以是应用下的tests.py文件,也可以是自定义的py文件。

# 测试环境准备
"""
需要在py文件的开头导入manage.py的前四句,然后自己在写上两句
"""

import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
    
    import django
    django.setup()
    # 在此代码块的下面可以测试django里面的单个py文件
    # 如:
    from app01 import models
    is_exists = models.User.objects.filter(pk=12).exists()
    print(is_exists)    

查询内部sql语句的方式

# 方式一
queryset对象可以直接通过query方法查询
query_set = models.User.objects.all().values_list('username','phone')

print(query_set.query)
"""
SELECT `app01_user`.`username`, `app01_user`.`phone` FROM `app01_user`
"""

# 方式二
所有的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',
        },
    }
}

models.User.objects.all().values_list('username','phone').first()

"""
(0.003) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.003) SELECT `app01_user`.`username`, `app01_user`.`phone` FROM `app01_user` ORDER BY `app01_user`.`id` ASC LIMIT 1; args=()
"""

双下划线查询

  • 查询年龄大于35岁的数据
query_set = models.User.objects.filter(age__gt=35)

<QuerySet [<User: 当前对象:egon_dsb,年龄:84>, <User: 当前对象:kevin,年龄:40>]>
  • 查询年龄小于35的数据
query_set = models.User.objects.filter(age__lt=35)

<QuerySet [<User: 当前对象:jason_DSB,年龄:18>, <User: 当前对象:tank_dsb,年龄:18>, <User: 当前对象:surpass,年龄:32>]>
  • 查询年龄大于等于35的数据
query_set = models.User.objects.filter(age__gte=35).order_by('age')

<QuerySet [<User: 当前对象:alex_dsb,年龄:35>, <User: 当前对象:kevin,年龄:40>, <User: 当前对象:egon_dsb,年龄:84>]>
  • 查询年龄小于等于32的数据
query_set = models.User.objects.filter(age__lte=32).order_by('-age')

<QuerySet [<User: 当前对象:surpass,年龄:32>, <User: 当前对象:jason_DSB,年龄:18>, <User: 当前对象:tank_dsb,年龄:18>]>
  • 查询年龄是18,32,40的数据
query_set = models.User.objects.filter(age__in=[18,32,40]).order_by('-age')

<QuerySet [<User: 当前对象:kevin,年龄:40>, <User: 当前对象:surpass,年龄:32>, <User: 当前对象:jason_DSB,年龄:18>, <User: 当前对象:tank_dsb,年龄:18>]>
  • 查询年龄在18到40之间的数据(首尾都要)
query_set = models.User.objects.filter(age__range=[18,40]).order_by('-age')

<QuerySet [<User: 当前对象:kevin,年龄:40>, <User: 当前对象:alex_dsb,年龄:35>, <User: 当前对象:surpass,年龄:32>, <User: 当前对象:jason_DSB,年龄:18>, <User: 当前对象:tank_dsb,年龄:18>]>
  • 模糊查询,查询名字中带有’s‘的数据
query_set = models.User.objects.filter(username__contains='s').order_by('-age')

"""
<QuerySet [<User: 当前对象:egon_dsb,年龄:84>, <User: 当前对象:alex_dsb,年龄:35>, <User: 当前对象:surpass,年龄:32>, <User: 当前对象:jason_DSB,年龄:18>, <User: 当前对象:tank_dsb,年龄:18>]>
"""

注意:模糊查询默认是区分大小写的,如果要忽略大小写,使用__icontains

query_set = models.User.objects.filter(username__icontains='s').order_by('-age')

"""
<QuerySet [<User: 当前对象:egon_dsb,年龄:84>, <User: 当前对象:alex_dsb,年龄:35>, <User: 当前对象:surpass,年龄:32>, <User: 当前对象:jason_DSB,年龄:18>, <User: 当前对象:tank_dsb,年龄:18>, <User: 当前对象: Steven,年龄:12>]>
"""
  • 查询名字以什么开头,以什么结尾的
query_set = models.User.objects.filter(username__startswith='j')

query_set = models.User.objects.filter(username__endswith='n')
"""
<QuerySet [<User: 当前对象:jason_DSB,年龄:18>]>

<QuerySet [<User: 当前对象:kevin,年龄:40>, <User: 当前对象: Steven,年龄:12>]>
"""
  • 查询注册时间
# 查询注册的月份是5月份的数据
query_set = models.User.objects.filter(register_time__month='5')
# 查询注册年份是2020年的数据
query_set = models.User.objects.filter(register_time__year='2020')

一对多外键查询

orm环境:

"""用户表"""
class User(models.Model)
    username = models.CharField(max_length=64, verbose_name="用户名")
    password = models.CharField(max_length=64, verbose_name="密码")
    age = models.IntegerField(verbose_name="年龄")
    phone = models.BigIntegerField(verbose_name="手机号码")
    email = models.EmailField(verbose_name="个人邮箱")
    register_time = models.DateField(auto_now_add=True, verbose_name="注册时间")

    def __str__(self):
        return f'当前对象:{self.username},年龄:{self.age}'
    
"""书籍表"""
class Book(models.Model):
    name = models.CharField(max_length=64, verbose_name="书名")
    price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name="价格")
    publish_date = models.DateField(auto_now_add=True, verbose_name="出版日期")
    # 一对多关系,外键建在多的那一方
    publish = models.ForeignKey(to="Publish")
    # 多对多关系,外键推荐建在查询频率较高的那一方
    authors = models.ManyToManyField(to="Author")
    
"""出版社"""
class Publish(models.Model):
    name = models.CharField(max_length=64, verbose_name="出版社名称")
    addr = models.CharField(max_length=64, verbose_name="出版社地址")
    email = models.EmailField(verbose_name="出版社邮箱")
    
"""作者"""
class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者名称")
    age = models.IntegerField()
    # 一对一关系,外键推荐建在查询频率较高的那一方
    author_detail = models.OneToOneField(to='AuthorDetail')

"""作者详情"""
class AuthorDetail(models.Model):
    phone = models.BigIntegerField(verbose_name="作者手机")
    email = models.EmailField(verbose_name="作者邮箱")
    addr = models.CharField(max_length=64, verbose_name="作者联系地址")

一对多外键的增删改查

# 增
方式一:直接写实际字段的id
models.Book.object.create(
    name='钢铁是怎样炼成的',
    price=70.50,
    publish_id=1,
)
方式二:写虚拟字段,对象
publish_obj = models.Publish.object.filter(pk=3).first()
models.Book.object.create(
    name='野性的呼唤',
    price='100.64',
    publish=publish_obj,
)

# 删除(级联删除)
models.Publish.object.filter(pk=3).delete()

# 修改
方式一
models.Book.object.filter(pk=1).update(publish_id=3)
方式二:
publish_obj=models.Publish.object.filter(pk=3).first()
models.Book.object.filter(pk=1).update(publish=publish_obj)

多对多外键的查询(操作第三张表)

# 给图书添加作者
    方式一:直接添加作者的主键字段
    book_obj = models.Book.objects.filter(pk=4).first()
    book_obj.authors.add(1,3) # 为书籍id为4的书籍绑定主键为1,3的作者
    方式二:添加作者对象
    book_obj = models.Book.objects.filter(pk=6).first()
    author_obj1 = models.Author.objects.filter(pk=5).first()
    author_obj2 = models.Author.objects.filter(pk=7).first()
    book_obj.authors.add(author_obj1,author_obj2)
    
    add给第三张表添加数据,括号内可以是对象,也可以是数字
    
    
# 删除图书的作者
book_obj = models.Book.object.filter(pk=8).first()
book_obj.authors.remove(3,5)

方式二:
book_obj = models.Book.object.filter(pk=10).first()
author_obj1 = models.Author.object.filter(pk=1).first()
author_obj2 = models.Author.object.filter(pk=7).first()
book_obj.authors.remove(author_obj1,author_onj2)

# 修改图书的作者
    book_obj = models.Book.objects.filter(pk=10).first()
    book_obj.authors.set((1,5)) # 括号内必须是一个可迭代对象

    方式二:
    book_obj = models.Book.objects.filter(pk=8).first()
    author_obj1 = models.Author.objects.filter(pk=1).first()
    author_obj2 = models.Author.objects.filter(pk=7).first()
    book_obj.authors.set((author_obj1,author_obj2))

"""
book_obj.authors.set(1,5)
TypeError: set() takes 2 positional arguments but 3 were given

objs = tuple(objs)
TypeError: 'int' object is not iterable
"""
set:括号内必须是一个可迭代的对象,该对象内,可以是字段,也可以是对象
    
# 清空
在第三张表关系中,解除图书与作者的绑定关系
book_obj = models.Book.object.filter(pk=1).first()
book_obj.authors.clear() # 括号内不加任何的参数

正反向的概念

"""
正向:外键字段在我表中,我查你就是正向
反向:外键字段不在我这里,我查你就是反向
"""
 book >>>外键字段在书那儿(正向)>>> publish
 publish >>>外键字段在书那儿(反向)>>> book

结论:
正向查询按字段
反向查询按照表名的小写_set

多表查询

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

  • 查询书籍主键为4的出版社
# 书籍查出版社(外键在书籍一方,正向查询)
    book_obj = models.Book.objects.filter(pk=4).first()
    res = book_obj.publish
    print(res)  # 出版社:东方出版社
  • 查询书籍主键为8的作者
# 书籍查作者(外键在书籍一方,正向查询)
    book_obj = models.Book.objects.filter(pk=8).first()
    res = book_obj.authors.all()
    print(res)  # <QuerySet [<Author: Author object>, <Author: Author object>]>
  • 查询作者“刘.易斯”的邮箱
# 作者查作者详情(外键在书籍一方,正向查询)
    author_obj = models.Author.objects.filter(name="刘.易斯").first()
    author_obj.author_detail
    print(author_obj.author_detail.email)
    # 13657440321@126.com
  • 查询出版社是东方出版社的书
# 出版社查书籍(外键在书籍一方,反向查询)
    publish_obj = models.Publish.objects.filter(name="东方出版社").first()
    res = publish_obj.book_set.all()
    print(res)
    # <QuerySet [<Book: Book object>, <Book: Book object>]>
  • 查询作者是"刘.易斯"的书
# 作者查书籍(外键在书籍一方,反向查询)
    author_obj = models.Author.objects.filter(name="刘.易斯").first()
    res = author_obj.book_set.all()
    print(res)
    # <QuerySet [<Book: Book object>]>
  • 查询住址为“浙江杭州” 的作者
# 由作者详情查作者(外键在作者一方,反向查询)
    author_detail_obj = models.AuthorDetail.objects.filter(addr="浙江杭州").first()
    res = author_detail_obj.author
    print(res) # Author object

总结:

1.正向查询,按字段
2.反向查询,按表名:
    (1)查询结果有多个,要加_set.all();
    (2)查询结果只有一个,无须加_set.all()

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

  • 查询“刘.易斯”的年龄和邮箱
    # 正向查询
    res = models.Author.objects.filter(name="刘.易斯").values('age','author_detail__email')
    print(res)
    
    """
    <QuerySet [{'age': 44, 'author_detail__email': '13657440321@126.com'}]>
    """
    
    # 反向查询
    res = models.AuthorDetail.objects.filter(author__name="刘.易斯").values('author__age','email')
    print(res)
    
    """
    <QuerySet [{'author__age': 44, 'email': '13657440321@126.com'}]>
    """
  • 查询书籍主键为4的出版社名称和书籍名称
# 正向查询
res = models.Book.objects.filter(pk=4).values('publish__name','name')
print(res)
"""
<QuerySet [{'publish__name': '东方出版社', 'name': '钢铁是怎样炼成的'}]>
"""

# 反向查询
res = models.Publish.objects.filter(book__pk=4).values('name','book__name')
print(res)

"""
<QuerySet [{'name': '东方出版社', 'book__name': '钢铁是怎样炼成的'}]>
"""
  • 查询书籍主键为4的作者姓名
# 正向查询
    res = models.Book.objects.filter(pk=4).values('authors__name')
    print(res)
    """
    <QuerySet [{'authors__name': '奥斯特洛夫斯基'}, {'authors__name': '刘.易斯'}]>
    """
    
# 反向查询
    res = models.Author.objects.filter(book__pk=4).values('name')
    print(res)
    """
    <QuerySet [{'name': '奥斯特洛夫斯基'}, {'name': '刘.易斯'}]>
    """
  • 查询书籍主键是4的作者邮箱
# 正向查询
    res = models.Book.objects.filter(pk=4).values('authors__author_detail__email')
    print(res)
    """
    <QuerySet [{'authors__author_detail__email': '18466075732@163.com'}, {'authors__author_detail__email': '13657440321@126.com'}]>
    """
    
# 反向查询
    res = models.AuthorDetail.objects.filter(author__book__pk=4).values('email')
    print(res)
    """
    <QuerySet [{'email': '18466075732@163.com'}, {'email': '13657440321@126.com'}]>
    """
posted @ 2020-11-08 16:39  为了等  阅读(101)  评论(0编辑  收藏  举报