ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

django之模型层1

2022-09-05 19:01:30  阅读:211  来源: 互联网

标签:__ models res 模型 外键 查询 objects django



# 模型层就是跟数据库打交道的 数据库就是如何查询数据

一、表查询数据准备以及测试环境搭建

'''1.django自带一个数据库sqlite3小型数据库 
这个数据库功能少 而且对日期类型不兼容 只适合做本地测试'''

# 2.django链接mysql数据库
'''链接上之后需要一些配置才能运行
django1.x  
    需要在应用或在与项目同名的文件夹下的__init__.py文件中写固定的代码
    import pymysql
    pymysql.install_as_MYSQLDB()
django2.x、3.x
    只需要下载一个模块即可
    pip3 install mysqlclient'''

# 3.定义模型类
class User(models.Model):
    uid = models.AutoField(primary_key=True, verbose_name='编号')
    name = models.CharField(max_length=32, verbose_name='姓名')
    age = models.IntegerField(verbose_name='年龄')
    join_time = models.DateField(auto_now_add=True)
'''日期类型有两个参数:
auto_now_add: 只有在创建数据库的时候会自动获取时间 之后不在人为改动的情况下不会在修改
auto_now: 每次操作数据并保存都会自动更新时间'''

# 4.执行数据库迁移命令(模型类>>>表)   
    migrations
        migrate

# 5.模型层测试环境准备
    '''因为编写orm代码需要通过编写路由层和视图层代码 这会很麻烦 这个时候就需要一个测试环境就可以直接操作数据库了'''
    # 方式一:这需要在一个空的py文件下编写固定代码即可
        import os
        def main():
            os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'day59.settings')
            import django
            django.setup()

            from app01 import models
            print(models.User.objects.filter())
    # 然后在main函数下编写orm代码即可
        if __name__ == '__main__':
            main()
    # 方式2:pycharm提供测试环境
        python console命令行测试环境    

二、ORM常见查询关键字

# 1.filter()
    <QuerySet [<User: User object (1)>, <User: User object (2)>, <User: User object (3)>]>
    '''筛选条件  返回值是一个QuerySet对象(可以看成是一个列表套数据对象)
        1.括号内不写条件就是查询全部
        2.括号内可以写条件 而且可以是多个 逗号隔开 是and关系 '''

# 2.all()
    '''查询所有数据 返回值是一个QuerySet对象(可以看成是一个列表套数据对象)'''

# 3.first()
    '''当查询出来的数据对象可以使用索引获取
       res = models.User.objects.filter()[0] 就可以获取到第一个数据对象
        然后就可以点出该对象的值 print(res.name)  # jason  
       不支持负数索引
        但是不推荐使用索引 推荐使用first 获取第一个
        res = models.User.objects.filter().first()
        也是获取QuerySet第一个数据对象 print(res.name)  # jason  
    两者的区别 如果该索引没有就会报错  而first如果没有值不会报错返回None'''

# 4.last()
    获取QuerySet最后一个数据对象

# 5.get()
    直接根据条件条件查询具体的数据对象 但是没有的话就会报错 不推荐使用
    res = models.User.objects.get(pk=2)
        print(res.name)  # kevin

# 6.values()
    指定查询字段 结果是一个Queryset (可以看成是一个列表套字典数据)
res = models.User.objects.filter().values('name')  # 条件不写就是查询全部
    print(res)  # <QuerySet [{'name': 'jason'}, {'name': 'kevin'}, {'name': 'tony'}]>

# 7.value_list()
    也是指定查询字段 结果是一个Queryset(可以看成是一个列表套元祖数据)
    res = models.User.objects.filter().values_list('name')  # 没写条件就是查询全部
        print(res)  # <QuerySet [('jason',), ('kevin',), ('tony',)]>

# 8.order_by()
    指定字段排序 默认升序 在字段前面加符号就是降序 支持多个字段排序
    res = models.User.objects.order_by('age')
    res1 = models.User.objects.order_by('-age')
    print(res,'\n',res1) 
 <QuerySet [<User: 对象:jason>, <User: 对象:kevin>, <User: 对象:tony>]> 
 <QuerySet [<User: 对象:tony>, <User: 对象:kevin>, <User: 对象:jason>]>

# 9.count()
    统计orm查询之后结果集中的数据格式
    res = models.User.objects.filter().count()
    print(res)  # 3

# 10.distinct()
    去重 需要数据要完全一模一样 不能有主键

# 11.exclude()
    其实就是取反 根据括号内的条件查询不同的值
    res = models.User.objects.exclude(pk=1)
    print(res)  # <QuerySet [<User: 对象:kevin>, <User: 对象:tony>]>

# 12.reverse()
    针对已经排过序的结果集做颠倒  没有排过序会报错

# 13.exists()
    判断查询结果集是否有数据  返回布尔值 基本不用因为所有的数据都自带布尔值

# 14.编写SQL语句
    1.可以使用RAW()
    res = models.User.objects.raw('select * from app01_user')
    print(list(res))
    2.还可以使用模块
 from django.db import connection
    cursor = connection.cursor()
    cursor.execute("insert into app01_user(name,age,join_time) VALUES ('oscar',18)")  # 添加数据
    cursor.execute("update app01_user set name='oscar' WHERE name='jason'")  # 修改数据
    cursor.execute("delete from app01_user where name='oscar'")  # 删除数据
    cursor.execute("select * from app01_user")  # 查看数据
    res = cursor.fetchone()
    res1 = cursor.fetchall()
    print(res, res1)

"""
1.当需要查询数据主键字段值的时候 可以使用pk忽略掉数据字段真正的名字
2.在模型类中可以定义一个__str__方法 便于后续数据对象被打印展示的是查看方便
3.Queryset中如果是列表套对象那么直接for循环和索引取值但是索引不支持负数
4.虽然queryset支持索引但是当queryset没有数据的时候索引会报错 推荐使用first
    1.create()
        创建数据 返回值就是当前创建的数据对象
        ps:还可以利用类实例化对象然后调用save方法创建
      2.update()
             更新数据
    3.delete()
         删除数据
5.first和all、exclude获取的都是列表套数据对象
6.values和values_list 分别获取的是列表套字典数据和列表套元祖数据
"""

三、神奇的双下划线查询

# 当我们查询年龄大于20的数据的时候怎么查询呢?
# res = models.User.objects.filter(age > 18)  这样是会报错的 不能使用特殊符号

# 这个时候就需要双下划线查询了 
    res = models.User.objects.filter(age__gt=18)  # 查询年龄大于18的数据
    print(res)  # <QuerySet [<User: 对象:kevin>, <User: 对象:tony>]>

# 只需要在字段名后面加上双下划线再写上特定符号即可

# 1.比较运算符
    字段__gt       大于
    字段__lt        小于
    字段__gte      大于等于
    字段__lte       小于等于

# 2.成员运算符
    字段__on        是否在什么什么之内

# 3.范围查询
    字段__range  # 左右包含
 res = models.User.objects.filter(age__range=(18, 38))
 print(res)  # <QuerySet [<User: 对象:jason>, <User: 对象:kevin>, <User: 对象:tony>, <User: 对象:oscar>]>

# 4.模糊查询
    在mysql中使用like
    在orm中使用
    字段__contains   不忽略大小写
    字段__icontains    忽略大小写
 res = models.User.objects.filter(name__contains='j')
 print(res)  # <QuerySet [<User: 对象:jason>, <User: 对象:jerry>]>

# 5.日期处理
    # 就是获取日期中含有的年月日
    字段__year       # 年
    字段__month     # 月
    字段__day         # 日
  res = models.User.objects.filter(join_time__year=2018)
    print(res)  # <QuerySet [<User: 对象:jason>, <User: 对象:kevin>]>

四、查看ORM底层SQL语句

# 方式1:
    如果结果是Queryset对象 那么直接点query即可
    res = models.User.objects.filter(join_time__year=2018)
    print(res.query)  
# SELECT `app01_user`.`uid`, `app01_user`.`name`, `app01_user`.`age`, `app01_user`.`join_time` FROM `app01_user` WHERE `app01_user`.`join_time` BETWEEN 2018-01-01 AND 2018-12-31 # 方式2: 如果不是Queryset对象那么直接在配置文件中配置下面代码即可 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中外键字段建在多的一方 models.ForeignKey()
           会自动在外键字段名称添加_id后缀
多对多
    ORM中有三种创建多对多字段的方式 models.ManyToManyField()
        方式1:直接在查询频率较高的表中填写字段即可 自动创建第三张关系表
       方式2:自己创建第三张关系表
       方式3:自己创建第三张关系表 但是还是要orm多对多字段做关联
一对一
    ORM中外键字段建在查询频率较高的表中 models.OneToOneField()
        会自动在外键字段名称添加_id后缀
 
django1.X 针对 models.ForeignKey() models.OneToOneField()不需要on_delete
django2.X 3.X 则需要添加on_delete参数
'''

六、外键字段数据操作

1.数据准备

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)  # 总共八位 小数点后面站两位
    publish_time = models.DateTimeField(auto_now=True)

    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return '书籍对象:%s' % self.title


class Publish(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField()

    def __str__(self):
        return '出版社对象:%s' % self.name


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)

    def __str__(self):
        return '作者对象:%s' % self.name


class AuthorDetail(models.Model):
    phone = models.BigIntegerField()
    addr = models.CharField(max_length=255)

    def __str__(self):
        return '作者详情对象:%s' % str(self.phone)

2.外键字段操作数据

'''
因为书和作者的关系是多对多关系所以ORM会帮我们创建一张虚拟的表
而我们现在需要往这张表添加书与作者的对应关系的时候
models点点不出来这张表  该怎么添加数据呢'''

# 多对多
models.ManyToManyField(to='Author')
# 我们可以先创建一个数的对象通过这个对象添加数据
     book_obj = models.Book.objects.filter(pk=1).first()
     book_obj.authors.add(1)  # 朝第三张关系表添加数据 就是将主键为1的书籍与主键为1的作者绑定
    # 可以添加多个
    book_obj.authors.add(2,3)  # 也是朝第三张关系表添加数据
    # 也可以吧作者对象先创建出来也可以
    author_obj1 = models.Author.objects.filter(pk=1).first()
    author_obj2 = models.Author.objects.filter(pk=2).first()
    book_obj.authors.add(author_obj1)  # 将主键是1的作者跟主键为1的书籍绑定
    book_obj.authors.add(author_obj1,author_obj2)

# 删除
    book_obj.authors.remove(1)  # 删除主键为1的书籍与主键为1的作者的绑定关系
    book_obj.authors.remove(2, 3)
    book_obj.authors.remove(author_obj1)
    book_obj.authors.remove(author_obj1,author_obj2)

# 修改
     # book_obj.authors.set([2,])  # 把主键为1的书籍遂改为与主键为2的作者绑定
    book_obj.authors.set([2,3])
    book_obj.authors.set([author_obj1, ])
    book_obj.authors.set([author_obj1, author_obj2])
    # 其实就是把原来的删除 然后在添加 set后必须要是可迭代对象

# 清空
    book_obj.authors.clear()  # 将主键为1的书籍与绑定的作者清空

#一对多
models.ForeignKey(to='Publish', on_delete=models.CASCADE)
      # 方式1直接给实际字段添加关联数据值     publish_id = 1
models.Book.objects.create(title='python从入门到放弃',price=29800.88,publish_id=1)  # 创建的时候直接写上即可
      # 方式2间接使用外键虚拟字段添加数据对象 publish=publish_obj

# 一对一
models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)
      # 方式1直接给实际字段添加关联数据值     author_detail_id = 1
      # 方式2间接使用外键虚拟字段添加数据对象 author_detail=authorDetail_obj

七、正反向概念

# 当我们用ORM进行跨表查询的时候需要知道什么是正向和反向

'''
正向与反向的核心就是 外键字段在哪个表上面
正向查询
    通过书查询出版社 书与出版社的外键字段在书表上 所以是正向查询 

反向查询
    通过出版社查询书  出版社与书的外键字段不在出版社上 所以是反向查询
一对多、多对多、一对一都是看外键字段在谁手上
'''

# 然后ORM跨表查询口诀:
    '''
正向查询按外键字段 反向查询按表名小写
    '''

八、基于对象跨表查询(子查询)

'''我们可以做几道题目理解'''

'''基于对象的正向跨表查询'''
# 1.查询主键为1的书籍对应的出版社(书>>>出版社)
    book_obj = models.Book.objects.filter(pk=1).first()
    # 1.1 因为外键字段在书表上 所以是正向
    print(book_obj.publish)  # 出版社对象:北方出版社

# 2.查询主键为3的书籍对应的作者(书>>>作者)
    book_obj = models.Book.objects.filter(pk=3).first()
    # 2.1 因为外键字段在书表上 所以是正向
    # print(book_obj.authors)  # app01.Author.None
    print(book_obj.authors.all())  # <QuerySet [<Author: 作者对象:jason>, <Author: 作者对象:tony>]>

# 3.查询jason的作者详情(作者>>>作者详情)
    author_obj = models.Author.objects.filter(name='jason').first()
    # 3.1 因为外键字段在作者表上  所以是正向
    print(author_obj.author_detail)  # 作者详情对象:111
'''如果查询的结果是多个 那么必须要加上.all
查询结果是一个 那么不需要加'''

'''基于对象的反向跨表查询'''
    # 4.查询南方出版社出版的书籍(出版社>>>书)
    publish_obj = models.Publish.objects.filter(name='南方出版社').first()
    # 4.1因为外键字段在书籍表上 所以是反向查询
    print(publish_obj.book_set)  # app01.Book.None
    print(publish_obj.book_set.all())  # <QuerySet [<Book: 书籍对象:java>]>

    # 5.查询jason写过的书(作者>>>书)
    author_obj = models.Author.objects.filter(name='jason').first()
    # 5.1 因为外键字段在书籍表上 所以是反向查询
    # print(author_obj.book_set)  # app01.Book.None
    print(author_obj.book_set.all())  # <QuerySet [<Book: 书籍对象:java>, <Book: 书籍对象:golang>]>

    # 6.查询电话是111的作者(作者详情>>>作者)
    author_detail_obj = models.AuthorDetail.objects.filter(phone=111).first()
    # 6.1 因为外键字段在作者表上  所以是反向查询
    print(author_detail_obj.author)  # 作者对象:jason
'''
如果查询结果为多个那么必须要加上_set.all()
如果查询结果为一个 那么不需要加
'''

九、基于双下划线跨表查询(链表操作)

'''题目还是一样只不过现在需要一条ORM代码就要得出结果'''

    '''基于双下划线的正向跨表查询'''
    # 1.查询主键为1的书籍对应的出版社名称及书名
    # 因为外键字段在书籍表中 所以是正向
    res = models.Book.objects.filter(pk=1).values('publish__name', 'title')  # publish是书籍表中的外键字段名称
    print(res)  # <QuerySet [{'publish__name': '北方出版社', 'title': 'python'}]>
    '''当我们写上外键字段就已经跳到出版社表了 在双下划线就可以拿到出版社表的字段了 因为前面是书籍对象所以只要写字段名即可'''

    # 2.查询主键为3的书籍对应的作者姓名及书名
    # 因为外键字段在书籍表中 所以是正向
    res = models.Book.objects.filter(pk=3).values('authors__name', 'title')  # authors是书籍表中的外键字段名称
    print(res)  # <QuerySet [{'authors__name': 'jason', 'title': 'golang'}, {'authors__name': 'tony', 'title': 'golang'}]>

     # 3.查询jason的作者的电话号码和地址
    # 因为外键字段在作者表中 所以是正向
    res = models.Author.objects.filter(name='jason').values('author_detail__phone','author_detail__addr')  # author_detail是作者表中的外键字段
    print(res)

    '''基于双下划线的反向跨表查询'''
    # 4.查询南方出版社出版的书籍名称和价格
    # 因为外键字段在书籍表中  所以是反向 
    res = models.Publish.objects.filter(name='南方出版社').values('book__title','book__price')  # book就是表Book的小写
    print(res)  # <QuerySet [{'book__title': 'java', 'book__price': Decimal('333333.00')}]>
    '''当我们写上小写表名的时候其实就已经跳到了书籍表 然后在双下划线就能拿到书籍表中的字段了'''

    # 5.查询jason写过的书的名称和日期
    # 因为外键字段在书籍表中  所以是反向
    res = models.Author.objects.filter(name='jason').values('book__title', 'book__publish_time')
    print(res)

    # 6.查询电话是111的作者姓名和年龄
    # 因为外键字段在作者表 所以是反向 
    res = models.AuthorDetail.objects.filter(phone=111).values('author__name', 'author__age')
    print(res)  # <QuerySet [{'author__name': 'jason', 'author__age': 18}]>

'''

双下划线其实是可以一直点的只要可以点

    # 7.查询主键为1的书籍对应的作者电话号码
    res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')  authors是书籍表中的外键字段     author_detail是作者表中的外键字段
    print(res)  # <QuerySet [{'authors__author_detail__phone': 222}]>

    因为书籍和作者表的外键字段在书籍表中 所以是正向所以只要写外键字段名称即可 
    写下外键字段名称其实就是跳到了作者表中 然后作者表和作者详情表的外键字段在作者表所以是正向
    所以只要写外键字段名称即可  然后写下外键字段其实就是跳转到了作者详情表中 
    然后在双下划线就可以拿到作者详情表对应的值
'''

 

标签:__,models,res,模型,外键,查询,objects,django
来源: https://www.cnblogs.com/stephenwzh/p/16659219.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有