【2022-09-05】Django框架(五)

Django框架(五)

定义模型类

from django.db import models


# Create your models here.

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.DateTimeField(auto_now_add=True)

补充知识

# 1、存储时间格式数据:
models.DateField()      # 日期字段:存储年月日
models.DateTimeField()  # 日期字段:存储年月日时分秒

# 日期字段重要参数 
auto_now		:  每次更新操作数据的时候 该字段会自动将当前时间更新
auto_now_add	        :  在创建数据的时候会自动将当前创建时间记录下来,之后只要不人为的修改,那么时间就一直不变
 
 
# 2、pk关键字
作用:pk会自动查找到当前表的主键字段 指代的就是当前表的主键字段
优点:用了pk之后 你就不需要指代当前表的主键字段到底叫什么了(nid,pid,uid....)
 
# 3、.get()方法
作用:.get()方法可直接拿到当前用户对象
eg:
user_obj = models.User.objects.get(pk=1)   # 直接拿到id=1的用户对象
相当于:
user_obj = models.User.objects.filter(pk=1).first()
 
# 但是不推荐使用get方法:因为一旦数据不存在那么使用该方法就会立刻报错,而使用filter方法如果数据不存在则返回空列表[]不会报错

执行数据库迁移命令

方式一:使用命令行

    python manage.py makemigrations
    python manage.py migrate

方式二:使用pycharm快捷方式

    上方菜单栏里找到并点击Tools——Run manage.py Task,依次执行下面两条语句即可
        makemigrations
        migrate

使用pychram连接mysql

一、修改配置文件

二、连接mysql

编写测试脚本

当我们只想操作django中某一个py文件内容时,那么可以不用书写前后端交互的形式来判断运行结果是否正确,我们可以直接写一个测试脚本即可。
  • 在我们创建应用的时候,会自动创建一个tests.py文件,我们可以在这里编写测试脚本。
from django.test import TestCase

# Create your tests here.


# 测试环境准备:去manage.py文件中拷贝下述代码到测试文件,然后自己配置两行,如下:

import os


# from app01 import models.py  不可以写在这里

def main():
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoProject1.settings')
    import django
    django.setup()  # 相当于启动django

    from app01 import models
    print(models.User.objects.filter())


# 注意:如果测试的脚本需要用到模块,必须写在配置好的环境下面,不可在最外层导入模块使用

if __name__ == '__main__':
    main()

  • pycharm也提供了一种测试环境

单表操作

表的新增

# 方式一:
res = models.User.objects.create(name='jack',age=19,register_time='2000-1-2')
print(res)  # 返回值为当前被创建对象本身
 
# 方式二:
import datetime
ctime = datetime.datetime.now()   # 当前时间
user_obj = models.User(name='tom',age=10,register_time=ctime)  # 也可存入一个日期对象
user_obj.save()

表的删除

# 方式一:
res = models.User.objects.filter(pk=2).delete()
print(res)   # 返回值为当前sql语句影响的行数(到底删了几行)
 
# 方式二:
user_obj = models.User.objects.filter(pk=1).first()  # 拿到当前用户对象
user_obj.delete()  # 用户对象也有delete方法

表的修改

# 方式一:
models.User.objects.filter(pk=4).update(name='tom2222')  # 匹配到id=4的记录并只修改name属性
 
# 方式二:
user_obj = models.User.objects.get(pk=4)
user_obj.name = 'tom3333'
user_obj.save()

ORM常见查询关键字

1.all()   
# 查询所有数据
res = models.User.objects.all()  # 括号内不可添加筛选条件
print(res)
 
# 结果:<QuerySet [<User: 对象:jack>, <User: 对象:tom>]>
2.filter() 
# 带有过滤条件的查询
res = models.User.objects.filter(pk=2)   # 括号内可添加筛选条件
print(res)
 
# 结果:<QuerySet [<User: 对象:tom>]>
3.get()  
# 直接拿数据对象,但是条件所匹配的数据不存在则直接报错
res = models.User.objects.get(pk=2)
print(res)   # 结果    对象:tom
res1 = models.User.objects.get(pk=3)
print(res1)  # 结果    报错

4.first()  
# 拿queryset里面的第一个元素
 
res = models.User.objects.filter().first()
print(res)
 
# 结果:对象:jack
5.last()   
# 拿queryset里面的最后一个元素
res = models.User.objects.filter().last()
print(res)
 
# 结果:对象:tom
6.values()  
# 可指定获取的字段,返回结果可以看作是列表套字典的形式
 
# 拿到所有用户的信息
res = models.User.objects.values()
print(res)
 
# 结果:<QuerySet [{'id': 1, 'name': 'jack', 'age': 19, 'register_time': datetime.date(2000, 1, 2)}, {'id': 2, 'name': 'tom', 'age': 10, 'register_time': datetime.date(2022, 2, 26)}]>   # 列表套字典的形式
 
 
eg:
# 1、只拿用户的名字
res = models.User.objects.values('name')
print(res)
    
# 结果:<QuerySet [{'name': 'jack'}, {'name': 'tom'}]>
 
 
# 2、只拿用户的名字和年龄
res = models.User.objects.values('name','age')
print(res)
# 结果:<QuerySet [{'name': 'jack', 'age': 19}, {'name': 'tom', 'age': 10}]>
相当于sql语句:select name,age from user
7.values_list()
# 同样可以指定需要获取的字段
# 但返回结果可以看作是列表套元组的形式
res = models.User.objects.values()
print(res)
 
# 结果:<QuerySet [(1, 'jack', 19, datetime.date(2000, 1, 2)), (2, 'tom', 10, datetime.date(2022, 2, 26))]>

8.distinct()
# 去重
# 注意:去重一定要是一摸一样的数据(一定要考虑主键),一个对象如果包含主键的话永远去不了重复数据
 
res = models.User.objects.filter().distinct()
print(res)  # 查所有:无意义,因为包含主键
 
res1= models.User.objects.values('name').distinct()
print(res1)  # 按照name字段去重
 
# 结果:
# <QuerySet [<User: 对象:jack>, <User: 对象:tom>, <User: 对象:jack>, <User: 对象:gary>]>
# <QuerySet [{'name': 'jack'}, {'name': 'tom'}, {'name': 'gary'}]>
9.order_by()
# 排序
.order_by('age')   # 默认升序
.order_by('-age')  # 降序在参数前加一个-
 
# eg:
    res1 = models.User.objects.values('age').order_by('age')
    print(res1)   # 升序
    res = models.User.objects.order_by('-age')
    print(res)    # 降序

10.reverse()
# 反转
 
# 前提:数据已经排序了,如果没排序是不支持反转的,必须提前排序过。
 
order_by().reverse()   # 通常情况下跟order_by联合使用
 
# eg:
    res = models.User.objects.filter().reverse()
    print(res)
 
    res1 = models.User.objects.order_by('age')
 
    res2 = models.User.objects.order_by('age').reverse()
    print(res2)

11.count()
# 统计当前数据的个数
res = .count()
 
# eg:
    res = models.User.objects.filter().count()
    print(res)  # 统计所有数据对象的个数
 
    res = models.User.objects.values('name').distinct().count()
    print(res)  # 按照name去重之后统计数据个数
    
# 结果:
	4
	3

12.exclude()
# .exclude()  # 排除(括号内匹配成功)之外的数据
 
# eg:
    res = models.User.objects.exclude(name='jack')
    print(res)
# 查询name = 'jack'之外的数据

13.exists()
# 判断是否存在  返回的是布尔值 
# 作用不大:因为数据本身就存在布尔值
 
# eg:
    res = models.User.objects.filter(pk=1).exists()
    print(res)
    res1 = models.User.objects.filter(pk=200)
    print(res1)
    res2 = models.User.objects.filter(pk=200).exists()
    print(res2)
    
# 结果:
    True
    <QuerySet []>
    False

14.raw()
	执行SQL语句
 	还可以借助于模块
    from django.db import connection  
    cursor = connection.cursor()  
    cursor.execute("insert into hello_author(name) VALUES ('郭敬明')") 
    cursor.execute("update hello_author set name='韩寒' WHERE name='郭敬明'")  
    cursor.execute("delete from hello_author where name='韩寒'")  
    cursor.execute("select * from hello_author")  
    cursor.fetchone()  
    cursor.fetchall()

ORM双下划线查询方法

比较运算

# 关键字:
    大于:			 __gt
    小于:			 __lt
    大于等于:	    __gte
    小于等于:		__lte
  
# 举例:
    res = models.User.objects.filter(age__gt=20)
    print(res)   # 年龄大于20
    res1 = models.User.objects.filter(age__lt=30)
    print(res)   # 年龄小于30
    res2 = models.User.objects.filter(age__gte=19)
    print(res2)  # 年龄大于等于19
    res3 = models.User.objects.filter(age__lte=30)
    print(res3)   # 年龄小于等于30

在某一数据集内

# 关键字:__in=['数据集']
 
# 举例:
    res = models.User.objects.filter(age__in=[10,20,30,40])
    print(res)

在某一范围内

# 关键字:__range=[]
# 举例:
    res = models.User.objects.filter(age__range=[19,40])
    print(res)

模糊查询

# 关键字:__contain=''  区分大小写
	 __icontain=''  不区分大小写
# 举例:
    res = models.User.objects.filter(name__contains='k')
    print(res)
    res1 = models.User.objects.filter(name__icontains='k')
    print(res1)

以什么开头/结尾

# 关键字:__startswith=''  以什么开头
	 __endswith=''	 以什么结尾
    	__istartswith=''  不区分大小写
        __iendswith=''   不区分大小写

按照日期查询

# 关键字:
    __month='1'   # 按照月份取
    __year='2020'  # 按照年份
    __day='29'    # 按照天筛选
    __weekday=''  # 按照日期
 
# 举例:
    res = models.User.objects.filter(register_time__month='01')
    print(res)
    res1= models.User.objects.filter(register_time__day='02')
    print(res1)
    res2= models.User.objects.filter(register_time__week_day='02')
    print(res2)
    res3 = models.User.objects.filter(register_time__year='2022')
    print(res3)
    res4 = models.User.objects.filter(register_time__year='2022',register_time__month='02')
    print(res4)

查看ORM底层SQL语句

# .query方法
 
.query方法可查看内部封装的sql语句
但是使用该方法查看sql语句的方式,只能用于queryset对象属性
只有返回结果为queryset对象才能够使用
 
eg:
    res1 = models.User.objects.filter()
    print(res1.query)
    res = models.User.objects.get(name='jack')
    print(res.query)

# 解决:所有的sql语句都能查看
# 将下述代码放到配置文件里
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参数

ORM多表操作

多表操作前期准备

models.py

class Book(models.Model):
    name = models.CharField(max_length=32,verbose_name='书名')
    price = models.DecimalField(max_digits=8,decimal_places=2,verbose_name='价格')
    publish_date = models.DateTimeField(auto_now_add=True,verbose_name='出版时间')
    publish = models.ForeignKey('Publish')  # 一对多
    authors = models.ManyToManyField('Author')   # 多对多
 
 
class Publish(models.Model):
    name = models.CharField(max_length=32,verbose_name='出版社名字')
    addr = models.CharField(max_length=32,verbose_name='出版社地址')
 
class Author(models.Model):
    name = models.CharField(max_length=32,verbose_name='作者名字')
    age = models.IntegerField(verbose_name='作者年龄')
    author_detail = models.OneToOneField('AuthorDetails')   # 一对一
 
class AuthorDetails(models.Model):
    phone = models.BigIntegerField(verbose_name='作者电话')
    addr = models.CharField(max_length=32,verbose_name='作者地址')

一对多外键增删改查

# 一对多外键增加数据
 
    # 方式一:直接写实际字段
    models.Book.objects.create(name='红楼梦',price=111.11,publish_id=1)
    # 方式二:虚拟字段
    publish_obj = models.Publish.objects.filter(pk=2).first()
    models.Book.objects.create(name='三国演义',price=22.5,publish=publish_obj)

# 一对多外键删除数据
 
models.Pulish.objects.filter(pk=1).delete()
 
# 删除记录是级联删除的,所以对应的外键字段一会直接删除,取消关联关系
# 一对多外键修改数据
 
    # 方式一:直接写实际字段
    models.Book.objects.filter(pk=1).update(publish_id=2)
 
    # 方式二:虚拟字段
    publist_obj = models.Publish.objects.filter(pk=3).first()
    models.Book.objects.filter(pk=2).update(publish=publist_obj)

多对多外键增删改查

# 多对多的增删改查其实就是在操作第三张虚拟表

# 先思考一个问题,如何添加作者
# 这张表不是我们自己创建的是系统帮助我们创建的,所以我们根本不能通过models的方法(.)到这张表
 
# 这里就要通过对象(.)外键的方式找到第三张表
# 多对多表关系的增加:
# 关键字:.add(主键值)
    # 方式一:
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.add(1)
   	book_obj.authors.add(2,3)   # 增加多个
    # 方式二:
    author_obj = models.Author.objects.filter(pk=1).first()
    author_obj1 = models.Author.objects.filter(pk=2).first()
    author_obj2 = models.Author.objects.filter(pk=3).first()
    book_obj.authors.add(author_obj)
    book_obj.authors.add(author_obj1,author_obj2)   # 增加多个

# 多对多表关系的删:
# 关键字:.remove(主键值)
    # 方式一:
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.remove(2,3)  # 同样支持多条数据同时删除
    # 方式二:对象
    book_obj1 = 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()
    author_obj3 = models.Author.objects.filter(pk=3).first()
    book_obj1.authors.remove(author_obj1,author_obj2)

# 多对多表关系的修改
# 关键字:set()
    # 方式一:
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.set([2,3])  # 同样支持多条数据同时修改
    # 方式二:对象
    book_obj1 = 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()
    author_obj3 = models.Author.objects.filter(pk=3).first()
    book_obj1.authors.set([author_obj1,author_obj2])

# 注意:set关键字括号内必须填写一个可迭代对象(列表或者元组)

# 多对多表关系的清空(清空在第三中某个书籍与作者的绑定关系)
# 关键字:clear()  #  括号内不要加任何参数

正反向的概念

正反向的概念核心就在于外键字段在谁手上

正向查询
	通过书查询出版社 外键字段在书表中
反向查询
	通过出版社查询书 外键字段不在出版社表中
 
ORM跨表查询口诀>>>:正向查询按外键字段 反向查询按表名小写

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

# 查找主键值为1的书的出版社名字和出版社地址(正向)
 
book_obj = models.Book.objects.filter(pk=1).first()  # 先拿到主键为1的书籍对象
res = book_obj.publish  # 拿到外键字段所对应关系表中的对象
print(res)   # 对应出版社的对象
print(res.name)      # 出版社名字
print(res.addr)      # 出版社地址

# 查询书籍主键为2的作者(正向)
    book_obj = models.Book.objects.filter(pk=2).first()
    res = book_obj.authors    # 
    print(res)

# 我们发现返回了一个:app01.Author.None
# 注意这个返回结果是一个标志性的问题:在当返回结果可能为多个的时候(一本书可以由多名作者编写(多对多的表关系)必须加关键字.all())
 
 # # 查询书籍主键为2的作者(正向)
    book_obj = models.Book.objects.filter(pk=2).first()
    res = book_obj.authors.all()
    print(res)
    print(res[0].name)   # 因对象有多个所以要通过索引取值拿到单独的对象
    print(res[1].name)

# 查询作者gary的电话号码(正向)
    author_obj = models.Author.objects.filter(name='gary').first()
    print(author_obj)
    res = author_obj.author_detail
    print(res)
    print(res.phone)
    print(res.addr)

# 查询是南方出版社出版的书(无外键字段(反向))
    publish_obj = models.Publish.objects.filter(name='东方出版社').first()
    res = publish_obj.book
    print(res)

# 反向查询上边有提到需要加入_set
# 查询是南方出版社出版的书(无外键字段(反向))
    publish_obj = models.Publish.objects.filter(name='南方出版社').first()
    res = publish_obj.book_set.all()  # 并且使用到.all()方法
    print(res)

# 5.查询作者是jason写过的书
    author_obj = models.Author.objects.filter(name='jason').first()
    res = author_obj.book_set.all()
    print(res)

# 6.查询手机号是110的作者姓名
    authorsetails_obj = models.AuthorDetails.objects.filter(phone='110').first()
    res1 = authorsetails_obj.author
    print(res1)

总结:

# 基于对象 
反向查询的时候
    当你的查询结果可能有多个的时候 就必须加_set.all()
    当你的结果只能有一个的时候 不需要加_set.all()

基于双下划线的跨表查询(连表操作)

# 同样遵循
# 正向查询按字段
# 反向查询按表名小写
# 查询作者gary的手机号(必须用一行代码展示)
    res = models.Author.objects.filter(name='gary').values('author_detail__phone''name')
    print(res)
    
# 利用values方法查询
注意:此时Author为基表可通过values方法直接查到该表的属性值
 
 
# 反向:(不允许.Author)
    res = models.AuthorDetails.objects.filter(author__name='gary').values('phone','author__name')
    print(res)

# 查询书籍主键为1的出版社的名称和书的名称
    res = models.Book.objects.filter(pk=1).values('name','publish__book')
    print(res)
 
# 方式二:反向
    res = models.Publish.objects.filter(book__id='1').values('name','book__name')
    print(res)

# 3.查询书籍主键为1的作者姓名
res = models.Book.objects.filter(pk=1).values('authors__name')
print(res)
# 方式二:反向
    res = models.Author.objects.filter(book__id=1).values('name')
    print(res)

# 查询书籍主键是1的作者的手机号
# 注意:这道题涉及到三张表
# 思路:通过书籍查作者,再通过作者查作者详情
    res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')

posted @   dy12138  阅读(68)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示