Django之models模型层1

一、测试环境的搭建

1、app应用中默认有一个tests.py的测试文件,拷贝manage.py的内容如下到tests.py中

此时这个测试文件就能使用django环境了

import os
import sys

if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoProject222.settings')
    import django

    django.setup()
   from app01 import models

二、models层中常见的几种查询方法

1、.values()和.values_list()方法

默认查询所有的字段,也可以指定某一个字段

res = models.Userinfo.objects.values()  # 默认查询所有的字段
    # <QuerySet [{'id': 1, 'username': 'cc1', 'password': '123'}, {'id': 2, 'username': 'cc2', 'password': '123'}, {'id': 3, 'username': 'cc3', 'password': '123'}]>
    res = models.Userinfo.objects.values('username')
    # <QuerySet [{'username': 'cc1'}, {'username': 'cc2'}, {'username': 'cc3'}]>
    res = models.Userinfo.objects.values_list()
    # <QuerySet [(1, 'cc1', '123'), (2, 'cc2', '123'), (3, 'cc3', '123')]>
    print(res)

2、排序

 order by age asc/desc

res = models.User.objects.all().order_by('age')  # 默认是升序排列
res = models.User.objects.all().order_by('-age')  # 降序排列
res = models.User.objects.all().order_by('age', 'id')  # 降序排列
res = models.User.objects.all().order_by('age', '-id', '')  # 降序排列

3、去重,

每一条数据都要完全一样,如果说带主键,一定不会重复

res = models.User.objects.all().values('password', 'age').distinct()
print(res)

4、反转,先排序,数据要先有序才能反转

降序---> 升序

res=models.User.objects.all().order_by('-age').reverse()
print(res)

5、count

select count(*) from user
res = models.User.objects.count()
print(res)

6、exclude 排除

res=models.User.objects.exclude(username='kevin1')
print(res)

7、exist 是否存在

res = models.UserInfo.objects.filter(pk=1).exist()
print(res) 

三、查看原生sql语句

1、方法一

print(res.query)

res = models.Userinfo.objects.values()  # 默认查询所有的字段
print(res)
print(res.query)

## 输出
SELECT "app01_userinfo"."id", "app01_userinfo"."username", "app01_userinfo"."password" FROM "app01_userinfo"  

2、方法二

修改settings配置文件

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 年龄大于35岁的数据
    # select * from user where age > 10
    # res = models.User.objects.filter(age__gt=10).all()
    # print(res)

    # 2 年龄小于10岁的数据
    # res = models.User.objects.filter(age__lt=10).all()
    # print(res)

    # 3 年龄大于等于10岁的数据 e---------->equal
    # res = models.User.objects.filter(age__gte=10).all()
    # res = models.User.objects.filter(age__lte=10).all()

    #  4 年龄是11 或者 20 或者 23
    # select * from user where age in (11, 20, 23)
    # res = models.User.objects.filter(age__in=[11,20,23]).all()
    # print(res)

    # 5 年龄在18到40岁之间的  首尾都要
    # select * from user where age between 18 and 40
    # res = models.User.objects.filter(age__range=[11,40])
    # print(res)

    # 6  查询出名字里面含有s的数据  模糊查询
    # select *from user where username like '%s%'
    # 回头复习
    # res = models.User.objects.filter(username__contains='s').all()
    # print(res)

    # 7 用户名以s开头的
    res = models.User.objects.filter(username__startswith='s').all()
    # res = models.User.objects.filter(username__endswith='s').all()
    print(res)

    # 8 查询出注册时间是 2023 5月
    # select * from user where reg_time = '2023-05'
    # select date_format(reg_time, '%Y-%m') from user where date_format(reg_time, '%Y-%m') = '2023-05'
    # res= models.User.objects.filter(reg_time__month='5') # 查5月的
    res= models.User.objects.filter(reg_time__month='5',reg_time__year='2023') # 查5月的
    print(res)

补充:时间字段:DateField

其中两个参数:

auto_now:记录修改时间,一旦改动记录,自动修改为当前时间

auto_now_add:记录的创建时间,自动填写

  -default=datatime.datatime:设置默认值,创建时自动添加时间

在django中修改亚洲上海时区,不修改的话,时间相差8小时。

class Userinfo(models.Model):
    username = models.CharField(max_length=64)
    password = models.CharField(max_length=64)
    age = models.IntegerField(default=0)
    reg_time = models.DateField(auto_now=True)
    create_time = models.DateField(auto_now_add=True)

    '''
    auto_now = False,  # 默认是False
    auto_now_add = False
    '''

    def __str__(self):
        return  self.username

五、外键字段的查询

1、数据准备

注意:多对多建外键时不用on_delete参数

# 用图书表,出版社表,作者表,作者详情表
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', on_delete=models.CASCADE)
    # 多对多
    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)
    age = models.IntegerField()
    # 一对一
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)


class AuthorDetail(models.Model):
    phone = models.BigIntegerField()  # 电话号码用BigIntegerField或者直接用CharField
    addr = models.CharField(max_length=64)

2、增删改

增加一本图书?
# 外键字段的查询和增加
    # 增加一本图书
    # models.Book.objects.create(title='洋哥自转', price=1000, publish_date='2023-08-01', publish_id=1)

    # publish_obj = models.Publish.objects.filter(pk=20).first()
    try:
        publish_obj = models.Publish.objects.get(pk=20)
    except:
        pass
    # models.Book.objects.create(title='洋哥自转2', price=2000, publish_date='2023-08-02', publish=publish_obj)
    # print(publish_obj) # None

    # 删除一本图书
    # models.Book.objects.filter(pk=1).delete()

    # 修改
    # models.Book.objects.filter(pk=2).update(publish=publish_obj)
    # models.Book.objects.filter(pk=2).update(publish_id=3)

3、多对多关系表的增删改查

通过对象点外键字段
add(增) remove(删)  set(修改)  clear(清空) 

# 给图书id为2的添加一个作者id=1
    book_obj = models.Book.objects.filter(pk=2).first()
    # print(book_obj.authors)  # app01.Author.None
    # print(book_obj.authors.all()) # app01.Author.

    # 添加
    book_obj.authors.add(1)
    # book_obj.authors.add(2, 3)  # 同时添加多个作者
    
    # 这里的数字也支持对象,但是不推荐
    # author_obj = models.Author.objects.filter(pk=1).first()
    # print(author_obj)
    # book_obj.authors.add(author_obj)

    #  删除
    book_obj.authors.remove('3')  # 也支持一次删除多个。一本书有多个作者,先查书的id,再删除指定作者ID的记录

    # 修改
    book_obj.authors.set([1, 3])

    # 清空表
    book_obj.authors.clear()

4、多表查询

子查询:一个sql语句的执行结果当成另一个sql语句的执行条件,分布操作

连表查询:把多个表关联在一起拼接成一个大的虚拟表,然后按照表单查询

inner join        left join         right join         union

正反向概念

正向概念:

  外键字段在己方,我查你就是正向查询

  # 图书查出版社:外键字段在图书表中,正向查询

反向概念:

  外键字段在己方,你查我就是正向查询

  # 出版社查图书,外键字段在图书表中,反向查询

判断出来正向和反向之后有什么用?
  正向查询按照字段查询(外键字段)
  反向查询按照表名小写或者表名小写_set

查询案例

    # 1、查询书籍主键为1的出版社
    # 书籍查出版社 ----------> 正向查询 ------------> 按外键字段查询
    res = models.Book.objects.filter(pk=1).first()
    # print(res)  # Book object (1)
    # print(res.publish)  # book对象点外键字段publish跳转到出版社表
    print(res.publish.addr)  # 接着可以点表里的字段查记录

    # 2、查询书籍主键为2的作者
    # 书籍查作者 ----------> 正向查询 ------------> 按外键字段查询
    res = models.Book.objects.filter(pk=2).first()
    # print(res.authors)  # app01.Author.None
    # print(res.authors.all())
    # <QuerySet [<Author: Author object (2)>, <Author: Author object (3)>]>
    print(res.authors.all()[1].name)  # 由上可知查询对象有2条结果,按下标取name
    # 循环取出所有的作者名
    # for i in res.authors.all():
    #     print(i.name)

    # 3、查询作者曹雪芹的电话号码
    # 作者查询作者信息 ----------> 正向查询 ------------> 按外键字段查询
    res = models.Author.objects.filter(name='曹雪芹').first()
    print(res.author_detail.phone)

    # 4、查询出版社是北京出版社的书
    # 出版社查书籍----------> 反向查询 ------------> 按照表名小写或者拼接_set
    res = models.Publish.objects.filter(name='北京出版社').first()
    print(res.book_set)  # app01.Book.None
    print(res.book_set.all()[0].title)

    # 5、查询作者是罗贯中写过的书
    # 作者查书籍 ----------> 反向查询 ------------> 按照表名小写或者拼接_set
    res = models.Author.objects.filter(name='罗贯中').first()
    print(res.book_set.all())
    for i in res.book_set.all():
        print(i.title)

    # 6、查询手机号是1209的作者姓名
    # 作者详情查作者 ----------> 反向查询 ------------> 按照表名小写或者拼接_set
    res = models.AuthorDetail.objects.filter(phone='1209').first()
    print(res.author.name)

注意:反向查询按照表名小写或者表名小写+_set

只有在一对一表关系中才能使用小写表名的形式,即当查询的结果只有一条的时候,不能拼接_set

 

posted @ 2023-08-02 18:53  凡人半睁眼  阅读(12)  评论(0编辑  收藏  举报