inclusion_tag,模版继承,Django框架之模型层,单表操作必知必会N条,神奇的双下划线查询,多表查询
Ⅰ自定义过滤器标签/inclusion_tag
- 比如你有一小段的 HTML 代码 但是 架子不变然后总是在变的是一块数据
- 这段代码 要在不同的页面上使用
- 解决方案 复制代码到另一个页面上 ---> 冗余且复杂
- 类似于Python中的函数 只需要在函数的参数的位置给一个位置参数
- 在某个页面上用的时候直接传参数给 函数
【一】步骤
- 三步走
- 要在应用下创建一个名字必须是templatetags文件夹
- 在该文件夹内创建 任意 名称的py文件
- 在该文件内必须写下面的话
from django import template
register = template.Library()
# 解释
# 1.引入 模块
from django import template
# 2.创建一个注册对象
# template 模版层的模版对象
# Library 图书馆的意思
register = template.Library()
【1】urls.py
from django.urls import path
from user.views import index
urlpatterns = [
path('', index, name='index'),
]
【2】hope_index.py
from django import template
register = template.Library()
@register.inclusion_tag('left_index.html')
def index_one():
data = "这是 index_one 函数返回的Hello World!"
return locals()
# 自定义inclusion_tag
@register.inclusion_tag('right_menu.html')
def left(n):
data = ['第 {} 项'.format(n) for n in range(n)]
# 将data传递给 left_menu
return locals()
【3】left_index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<h1>这是注册好的 left_index 页面</h1>
{{ data }}
</body>
</html>
【4】right_menu.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>这是注册好的 right 页面</h1>
<ul>
{% for datum in data %}
<li>{{ datum }}</li>
{% endfor %}
</ul>
</body>
</html>
【5】index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>这是index页面</h1>
<p>使用注册好的标签</p>
{% load hope_index %}
{% index_one %}
{% left 8 %}
</body>
</html>
【6】页面展示
【二】总结
- 当html页面的某一个地方的页面需要传参数才能动态的渲染出来,并且在多个页面上都需要使用到的局部,那么就考虑将该局部页面做成 inclusion_tag 形式
# 场景
# 比如你看到的博客园 左边有一个分类的栏
# 我们不想重复的写某一部分 HTML 代码
# 于是就将这个部分代码做成 inclusion_tag
# 在需要使用的地方直接 load 加载即可
【三】总的模板步骤
# 【一】在应用下创建一个文件夹
# 文件夹名字必须叫 templatetags
# 【二】在文件夹内部创建一个 py 文件
# py文件的名字你可以自己随便定义
# 【三】在创建好的 py 文件内部
# 书写代码
'''
# 【1】引入 模块
from django import template
# 【2】创建一个注册对象
# template 模版层的模版对象
# Library 图书馆的意思
register = template.Library()
# 【3】创建一个函数 在函数的头上加上一个装饰器
@register.inclusion_tag('left_index.html')
def index_one():
data = "这是 index 函数的返回值"
return locals()
# 自定义inclusion_tag
@register.inclusion_tag('right_menu.html')
def left(n):
data = ['第 {} 项'.format(n) for n in range(n)]
# 将data传递给 left_menu
return locals()
'''
# 在 app 下的 templates 文件夹中创建一个 Html 页面
# 在html页面中写内容
# 【四】创建注册的页面名
# left_index.html
'''
<h1>这是注册好的 left_index 页面</h1>
{{ data }}
'''
# right_menu.html
'''
<ul>
{% for datum in data %}
<li>{{ datum }}</li>
{% endfor %}
</ul>
'''
# 【五】
# 将上面前端的展示数据,传递继承给下个前端页面
'''
<h1>这是index页面</h1>
<p>使用注册好的标签</p>
{% load hope_index %}
{% index_one %}
{% left 8 %}
'''
# 【六】应用场景
# 比如你看到的博客园 左边有一个分类的栏
# 我们不想重复的写某一部分 HTML 代码
# 于是就将这个部分代码做成 inclusion_tag
# 在需要使用的地方直接 load 加载即可
Ⅱ 模版继承
- 某些页面的整体大差不差,但是某一些局部在做变化
- 在另一个页面上直接将这一块的内容进行替换即可
【一】模板
【1】前端
- index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
{% load hope_index %}
</head>
<body>
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Brand</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<div class="container-fluid">
<div class="row">
<div class="col-md-2">
{% left 10 %}
</div>
<div class="col-md-8">
{% block main_content %}
主体内容
{% endblock %}
</div>
<div class="col-md-2">
{% left 10 %}
</div>
</div>
</div>
</body>
</html>
- left_index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<h1>这是注册好的 left_index 页面</h1>
{{ data }}
</body>
</html>
- right_menu.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>这是注册好的 right 页面</h1>
<ul>
{% for datum in data %}
<li>{{ datum }}</li>
{% endfor %}
</ul>
</body>
</html>
【2】路由
- urls.py
from django.urls import path
from user.views import index,home
urlpatterns = [
path('admin/', admin.site.urls),
path('', index, name='index'),
path('home/', home, name='home'),
]
【3】视图
- views.py
from django.shortcuts import render, HttpResponse
def index(request):
return render(request, 'index.html',locals())
def home(request):
return render(request, 'home.html',locals())
【4】页面展示
【二】继承方法
【1】继承母板
- 在子页面中在页面最上方使用下面的语法来继承母板。
{% extends '母板文件名' %}
# 如:
{% extends 'index.html' %}
【2】块(block)
- 通过在母板中使用{% block xxx %}来定义"块"。
- 在子页面中通过定义母板中的block名来对应替换母板中相应的内容。
{% block main_content %}
<!--放你要输入的内容-->
{% endblock %}
<!--例如:-->
{% block main_content %}
<div>
<h1>这是index页面</h1>
<p>使用注册好的 标签</p>
<p>第一步 先加载 标签名 自己创建的那个 py 文件名</p>
{% load my_tags %}
<p>第二步 加载你需要使用的那个函数名 </p>
{% index_one %}
<h1>使用二</h1>
{% load my_tags %}
{% left 10 %}
</div>
{% endblock %}
【3】组件
- 可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方按如下语法导入即可。
{% include 'navbar.html' %}
【4】静态文件加载
(1)
- 加载Django的静态文件
{% load static %}
<img src="{% static "images/hi.jpg" %}" alt="Hi!" />
(2)
- 相当于获取到了 static 文件夹的文件夹绝对路径,从绝对路径再往下找静态文件
{% load static %}
<img src="{% get_static_prefix %}images/hi.jpg" alt="Hi!" />
- 或者
{% load static %}
{% get_static_prefix as STATIC_PREFIX %}
<img src="{{ STATIC_PREFIX }}images/hi.jpg" alt="Hi!" />
<img src="{{ STATIC_PREFIX }}images/hi2.jpg" alt="Hello!" />
【三】继承展示
【1】路由
- urls.py
from django.urls import path
from user.views import index,home
urlpatterns = [
path('', index, name='index'),
path('home/', home, name='home'),
]
【2】视图
- views.py
from django.shortcuts import render, HttpResponse
def index(request):
return render(request, 'index.html',locals())
def home(request):
return render(request, 'home.html',locals())
【3】前端
- 模板index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
{% load hope_index %}
</head>
<body>
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Brand</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<div class="container-fluid">
<div class="row">
<div class="col-md-2">
{% left 10 %}
</div>
<div class="col-md-8">
{% block main_content %}
主体内容
{% endblock %}
</div>
<div class="col-md-2">
{% left 10 %}
</div>
</div>
</div>
</body>
</html>
- 继承index.html
{% extends 'index.html' %}
{% load static %}
{% block main_content %}
<div>
<h1>这是index页面</h1>
<p>使用注册好的 标签</p>
<p>第一步 先加载 标签名 自己创建的那个 py 文件名</p>
{% load hope_index %}
<p>第二步 加载你需要使用的那个函数名 </p>
{% index_one %}
<h1>使用二</h1>
{% load hope_index %}
{% left 10 %}
</div>
{% endblock %}
【4】页面展示
Ⅲ Django框架之模型层
【一】前言引入
- Django自带的sqlite3数据对日期格式不敏感,处理的时候容易出错
【1】测试脚本
- 测试脚本
- 当我们只想要测试Django中的某一个py文件的内容时,我们可以不需要书写前后端交互的形式,而是直接写一个测试脚本即可
- 测试环境的准备
- 在测试文件中书写下面内容
- 这内容其实就是最外部 manage.py 文件中的上面几句话
- 脚本代码无论是写在应用下的 tests.py文件还是自己新建文件,将内容写在新文件中,都会生效
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
# Django 的框架比较特殊
# Django的 orm 框架必须是在Django的启动状态下才能使用
# Django为我们提供了测试环境
# 1.创建main入口
'''
if __name__ == '__main__':
'''
# 2.在main入口下面复制 manage.py 文件中 main 入口下面的第一行代码
# 每一个Django项目都要自己去找 自己去复制
# os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DjangoProjectSeven.settings')
'''
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
'''
# 3.在下面的代码中继续加入两句话
# import django
# django.setup()
# 这种启动方式是临时启动而不是持久化启动
'''
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DjangoProjectSeven.settings')
import django
django.setup()
'''
【2】配置数据库文件(settings.py)
# 1.在settings.py 文件中修改数据库属性
# 链接MySQL数据库
DATABASES = {
'default': {
# 指定我们使用的引擎是 mysql 数据库的引擎
'ENGINE': 'django.db.backends.mysql',
# 我们需要配置MySQL数据库的参数
# NAME 就是你要链接的数据库名字
# 'NAME': BASE_DIR / 'db.sqlite3',
# MySQL服务器的IP - HOST
"HOST": "127.0.0.1",
# MySQL服务器的PORT
"PORT": 3306,
# MySQL服务器的USERNAME
"USER": "root",
# MySQL服务器的PASSWORD
"PASSWORD": "123456",
# MySQL服务器的 数据库名字 NAME
# create database django001;
"NAME": "six",
# MySQL服务器的CHARSET
"CHARSET": "utf8mb4"
}
}
# 2.启动项目会报错
# 报错的原因是 没有安装mysqlclient
# 方案一 : 猴子补丁
# 放在文件__init__.py 里面就行
'''
import pymysql
pymysql.install_as_MySQLdb()
'''
# 方案二 : 安装mysqlclient
'''
pip install mysqlclient
'''
【3】定义模型表
# 【三】在app下面的models 里面定义模型表
class UserInfo(models.Model):
name = models.CharField(max_length=32, verbose_name="名字")
age = models.IntegerField(verbose_name="年龄")
register_time = models.DateTimeField(
verbose_name="注册时间",
auto_now_add=True
)
update_time = models.DateTimeField(
verbose_name="更新时间",
auto_now=True,
)
# auto_now : 在创建数据库的时候会自动新增时间 在每一次修改的时候会自动刷新时间
# auto_now_add : 在创建数据库的时候会自动新增时间 在每一次修改的时候不会自动刷新时间
【4】迁移数据库
python manage.py makemigrations
python manage.py migrate
【二】单表操作必知必会N条
【1】数据的增加
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import UserInfo
# 在Django中pk = id
# (1)方式一 : 直接 create
UserInfo.objects.create(
name='silence',
age= 18
)
# (2)方式二 : 先生成对象然后提交事务
user_obj = UserInfo(name="mark", age=888)
# print(user_obj) # UserInfo object (None)
# 提交事务
user_obj.save()
【2】数据的查询
(1)按指定条件过滤:filter和get
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import UserInfo
# (1)方式一:直接 .get(筛选条件) 结果是 user对象
user_obj = UserInfo.objects.get(pk=1)
print(user_obj.register_time)
# 2024-06-25 15:01:00.074037+00:00
# (2)方式二:fileter过滤结果 结果是 queryset 对象
user_queryset = UserInfo.objects.filter(pk=1)
print(user_queryset)
# <QuerySet [<UserInfo: UserInfo object (1)>]>
# 获取 结果集 的第一个结果
user_first = user_queryset.first()
print(user_first)
# 获取结果集的最后一个结果
# UserInfo object (1)
user_last = user_queryset.last()
print(user_last)
# UserInfo object (1)
(2)查询全部:all
# 获取所有数据结果
user_obj = UserInfo.objects.all()
print(user_obj)
# <QuerySet [<UserInfo: UserInfo object (1)>, <UserInfo: UserInfo object (2)>]>
# 获取结果集中的所有结果
user_queryset = UserInfo.objects.filter(age=18)
user_all = user_queryset.all()
print(user_all)
# <QuerySet [<UserInfo: UserInfo object (1)>]>
(3)获取结果集中的对应字段对应的数据
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import UserInfo
# 在数据库表中增加新数据 原来的已经删除了
# for i in range(1,5):
#
# UserInfo.objects.create(
# name=f"silence{i}",
# age=18,
# )
# 获取结果集中的对应字段对应的数据
# values --- 能获取到键值对数据
user_queryset = UserInfo.objects.filter(age=18).values(
"name", "age"
)
print(user_queryset)
# <QuerySet [{'name': 'silence1', 'age': 18}, {'name': 'silence2', 'age': 18}, {'name': 'silence3', 'age': 18}, {'name': 'silence4', 'age': 18}]>
# values_list --- 获取到值数据没有键
user_queryset = UserInfo.objects.filter(age=18).values_list(
"name", "age"
)
print(user_queryset)
# <QuerySet [('silence1', 18), ('silence2', 18), ('silence3', 18), ('silence4', 18)]>
【3】数据的更改
(1)查询后直接修改
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import UserInfo
# 方式一 查完后直接修改
UserInfo.objects.filter(pk=1).update(
name="oppo"
)
(2)先查询再修改
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import UserInfo
# 方式二 先查到对象 对象.属性名该值
# 在 时间日期 字段 DateTimeField 字段 的 auto_now
# 只有获取到对象然后对象.属性名修改值的时候才会触发时间的更新
user_obj = UserInfo.objects.get(pk=2)
user_obj.name = "oppop"
user_obj.save()
【4】数据的删除
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import UserInfo
# 方案一 获取到结果集 对结果集进行删除
# 通过筛选结果获取到了两个结果 在两个结果的基础上进行 delete 两个都被删除
user_queryset = UserInfo.objects.filter(name="silence").delete()
# 方案二 直接对对象进行删除
# 直接删除掉指定的对象结果
UserInfo.objects.get(pk=3).delete()
【5】去重
- 去重(带有主键就意味着数据存在不一样的地方,所以一定要去除主键后再去重)
- distinct 方法在主键存在时,无法对含有不同主键的相同数据进行去重
- 但是我们可以通过拿到指定字段的数据后,对筛选出的数据进行去重
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import UserInfo
# 去重
user = UserInfo.objects.values("age").distinct().first()
print(user, type(user))
# {'age': 18} <class 'dict'>
【6】统计个数
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import UserInfo
# 知道数据的结果量
user = UserInfo.objects.count()
print(user)
# 4
【7】排序
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import UserInfo
# 排序
# 正序排 MySQL正序加 asc
user = UserInfo.objects.order_by("age")
print(user)
# <QuerySet [<UserInfo: UserInfo object (7)>, <UserInfo: UserInfo object (4)>, <UserInfo: UserInfo object (6)>, <UserInfo: UserInfo object (5)>]>
# 倒序排 MySQL倒序加 desc
user = UserInfo.objects.order_by("-age")
print(user)
# <QuerySet [<UserInfo: UserInfo object (5)>, <UserInfo: UserInfo object (6)>, <UserInfo: UserInfo object (4)>, <UserInfo: UserInfo object (7)>]>
# 将排序后的结果翻转
user = UserInfo.objects.order_by("age").reverse()
print(user)
# <QuerySet [<UserInfo: UserInfo object (5)>, <UserInfo: UserInfo object (6)>, <UserInfo: UserInfo object (4)>, <UserInfo: UserInfo object (7)>]>
# 在Django的ORM语句中只要不是确切的某个对象 就可以一直 . 触发其他方法
user = UserInfo.objects.order_by("age").count()
print(user)
# 4
【8】剔除
- 排出在外
- 将某个数据排出在结果之外
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import UserInfo
# 对某个条件以外的结果进行剔除
# 不会剔除掉你指定的这个条件的结果
user = UserInfo.objects.exclude(age=18)
print(user)
#<QuerySet [<UserInfo: UserInfo object (5)>, <UserInfo: UserInfo object (6)>, <UserInfo: UserInfo object (7)>]>
【9】是否存在
- 是否存在
- 返回布尔值
- 用处不大,因为数据本身就有布尔值的状态
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import UserInfo
# 判断当前筛选到的结果是否存在
user = UserInfo.objects.filter(name="silence_3").exists()
print(user)
# False
user = UserInfo.objects.filter(name="silence3").exists()
print(user)
# True
【总结】必知必会N条
# 【1】增加
(1)model.objects.create(filed=value)
(2)model(filed=value).save()
# 【2】删除
(3)model.objects.filter(filed=value).delete()
(4)model.objects.get(filed=value).delete()
# 【3】修改
(5)model.objects.filter(filed=value).update(filed=new_value)
(6)obj = model.objects.get(filed=value)
obj.filed_name = value
obj.save()
# 【4】查看
(7) model.objects.filter(field=value)
(8) model.objects.filter(field=value).first()
(9) model.objects.filter(field=value).last()
(10) model.objects.all()
(11) model.objects.get(filed=value)
# 【5】扩展方法
(12) model.objects.filter(field=value).count() 计数
(13) model.objects.filter(field=value).values() 获取键值对结果
(14) model.objects.filter(field=value).values_list() 获取值结果
(15) model.objects.values("field").distinct() 对结果进行去重
(16) model.objects.filter(field=value).order_by("-filed") 降序
(17) model.objects.filter(field=value).order_by("filed") 升序
(18) model.objects.filter(field=value).exists() 判断结果是否存在
(19) model.objects.exclude(filed=value) 排除指定条件的数据
# 补充:查看当前ORM语句的SQL查询语句
# 注意可以使用此方法的必须是 QuerySet 对象
.query
Ⅳ 神奇的双下划线查询
【一】条件大于等于,小于等于,或,两个条件之间
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import UserInfo
# 【一】大于
user = UserInfo.objects.filter(age__gt=18)
print(user)
# <QuerySet [<UserInfo: UserInfo object (5)>, <UserInfo: UserInfo object (6)>]>
# 【二】大于等于
user = UserInfo.objects.filter(age__gte=18)
print(user)
# <QuerySet [<UserInfo: UserInfo object (4)>, <UserInfo: UserInfo object (5)>, <UserInfo: UserInfo object (6)>]>
# 【三】小于
user = UserInfo.objects.filter(age__lt=18)
print(user)
# <QuerySet [<UserInfo: UserInfo object (7)>]>
# 【四】小于等于
user = UserInfo.objects.filter(age__lte=18)
print(user)
# <QuerySet [<UserInfo: UserInfo object (4)>, <UserInfo: UserInfo object (7)>]>
# 【五】或条件
# 年龄是 18 / 28
user = UserInfo.objects.filter(age__in=(18, 28))
print(user)
# <QuerySet [<UserInfo: UserInfo object (4)>, <UserInfo: UserInfo object (5)>]>
# 【六】两个条件之间 左右都是闭区间
user = UserInfo.objects.filter(age__range=(18, 28))
print(user)
# <QuerySet [<UserInfo: UserInfo object (4)>, <UserInfo: UserInfo object (5)>, <UserInfo: UserInfo object (6)>]>
【二】模糊查询,以指定条件开头/结尾,查询时间日期
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import UserInfo
# 【七】模糊查询
# 查人名中带有 X 的人的名字
# 强约束 区分大小写
user = UserInfo.objects.filter(name__contains="X")
print(user)
# <QuerySet [<UserInfo: UserInfo object (6)>]>
# 弱约束 不区分大小写
user = UserInfo.objects.filter(name__icontains="X")
print(user)
# <QuerySet [<UserInfo: UserInfo object (5)>, <UserInfo: UserInfo object (6)>]>
# 【八】以指定条件开头或结尾
user = UserInfo.objects.filter(name__startswith="s")
print(user)
# <QuerySet [<UserInfo: UserInfo object (4)>, <UserInfo: UserInfo object (5)>, <UserInfo: UserInfo object (6)>, <UserInfo: UserInfo object (7)>]>
user = UserInfo.objects.filter(name__endswith="4")
print(user)
# <QuerySet [<UserInfo: UserInfo object (7)>]>
# 【九】查询指定日期
user = UserInfo.objects.filter(register_time__day="25")
print(user)
# <QuerySet [<UserInfo: UserInfo object (5)>, <UserInfo: UserInfo object (6)>]>
user = UserInfo.objects.filter(register_time__year="2024")
print(user)
# <QuerySet [<UserInfo: UserInfo object (5)>]>
user = UserInfo.objects.filter(register_time__month="3")
print(user)
# <QuerySet [<UserInfo: UserInfo object (7)>]>
Ⅴ多表查询引入
【一】数据准备
【1】一对一,作者表和作者详情表
- 作者具有作者详情,所以作者和作者详情表是一对一关系
- 一个作者只能有一个详情表,建立外键关系为一对一
(1)创建作者表
# 1.创建作者表
class Author(models.Model):
# 作者名字
name = models.CharField(max_length=32)
# 作者年龄
age = models.IntegerField()
# 作者和作者详情进行关联 一对一关系 一个作者只能有一个详情
# 一个详情只能对应一个作者
# 我们在表模型中定义的字段名 叫 author_detail 而在数据库中叫 author_detail_id
author_detail = models.OneToOneField(
# 这个字段需要关联的那张表的表明
to="AuthorDetail",
on_delete=models.CASCADE
)
(2)创建作者详情表
# 2.作者详情表
class AuthorDetail(models.Model):
# 作者地址
addr = models.CharField(max_length=255)
# 作者电话
phone = models.CharField(max_length=11)
【2】一对多书籍表和出版社表
- 一本书只能有一个出版社,建立外键关系为一对一
- 出版社可以有多本书,一个出版社可以写多本书,建立外键关系为一对多
(1)创建书籍表
# 书籍表
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.CharField(max_length=5)
# 书籍要关联出版社
# 一对多关系
publish = models.ForeignKey(
# 目标关联表
to="Publish",
# 级联更新和级联删除
on_delete=models.CASCADE
)
# 不手动创建第三张表 由Django帮我们自动生成第三张表
# 直接写第三张表的名字 直接Django帮我们自动生成第三张表
author = models.ManyToManyField(to="Author")
(2)创建出版社表
- 出版社不需要额外的外键关系
# 出版社表
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
【3】多对多书籍和作者表
(1)多对多创建方式一:创建第三张表
# 3.多对多
# 书籍和作者表
# 在MySQL中多对多关系式创建第三张表
# 1.多对多创建方式一:创建第三张表
class Author(models.Model):
# 作者名字
name = models.CharField(max_length=32)
# 作者年龄
age = models.IntegerField()
# 作者和作者详情进行关联 一对一关系 一个作者只能有一个详情
# 一个详情只能对应一个作者
# 我们在表模型中定义的字段名 叫 author_detail 而在数据库中叫 author_detail_id
author_detail = models.OneToOneField(
# 这个字段需要关联的那张表的表明
to="AuthorDetail",
on_delete=models.CASCADE
)
# 指定使用第三张表
book = models.ManyToManyField(
# 跟那张表进行关联
to="Book",
# 通过那张表
through="BookToAuthor",
# 通过哪些字段
through_fields=("author", "book")
)
class BookToAuthor(models.Model):
# 字段关联到 作者表
author = models.ForeignKey(
to="Author",
on_delete=models.CASCADE
)
# 字段关联到 图书表
book = models.ForeignKey(
to="Book",
on_delete=models.CASCADE
)
(2)多对多创建方式二:直接在 字段中进行声明 Django帮我们自动创建
# 3.多对多
# 书籍和作者表
# 在MySQL中多对多关系式创建第三张表
# 2.多对多创建方式二:直接在 字段中进行声明 Django帮我们自动创建
# 书籍表
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.CharField(max_length=5)
# 书籍要关联出版社
# 一对多关系
publish = models.ForeignKey(
# 目标关联表
to="Publish",
# 级联更新和级联删除
on_delete=models.CASCADE
)
# 直接写第三张表的名字 直接Django帮我们自动生成第三张表
author = models.ManyToManyField(to="Author")
- django自动生成的和创建的多对多第三张表一样
【二】外键的增删改查
【1】一对多外键的增删改查
- 书籍表和出版社之间
(1) 增添数据
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
# 增加数据
# 数据和出版社式 一对多
Publish.objects.create(name="人民出版社", addr="北京")
Publish.objects.create(name="上海出版社", addr="上海")
Publish.objects.create(name="南京出版社", addr="南京")
Publish.objects.create(name="东京出版社", addr="东京")
(2)外键的增加
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
# 在创建图书数据的时候要进行出版社的关联
publish_obj = Publish.objects.get(pk=2)
# 方式一 : 直接在 字段 publish_id 值是指定出版社的id
Book.objects.create(title="西游记", price="99",publish_id=publish_obj.id)
# 方式二 : 在模型表中定义的字段是叫 publish 所以 直接将对象扔进去
Book.objects.create(title="红楼梦", price="88", publish=publish_obj)
(3)外键的删除
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
# 删除数据 --- 删除外键关系
# book 表中的 publish 字段 : on_delete=models.CASCADE
# CASCADE 级联更新和级联删除 ----> 删除出版社 我的图书会产生什么变化?
# 删除外键数据 出版社表中的数据 在图书表中 预支相关联的数据也会被删除
Publish.objects.filter(pk=2).delete()
# 外键字段分两种
# 逻辑外键 : 逻辑上成立 但是实际上没有关系
# 物理外键 : 逻辑上成立 并且有实际的关系
(4)外键的修改
- 删除后又新增了一些数据
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
Publish.objects.create(name="上海出版社", addr="上海")
publish_obj = Publish.objects.get(pk=3)
Book.objects.create(title="西游记", price="99", publish_id=publish_obj.id)
- 开始修改
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
# 【3】修改外键字段
# 不想要 西游记交给 南京出版社 而是交给上海出版社
# 方式一:外键
Book.objects.filter(pk=3).update(publish_id=5)
# 方式二:对象
publish_obj = Publish.objects.get(pk=4)
Book.objects.filter(pk=3).update(publish=publish_obj)
-
方式一展示:
-
方式二展示:
【2】多对多外键的增删改查
图书和作者表
- 多对多 增删改查 就是在操作第三张表
(1)作者详情和作者引入
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 创建一个作者详情关联上作者
detail_obj = AuthorDetail.objects.create(addr="上海", phone="110")
print(detail_obj) # AuthorDetail object (1)
Author.objects.create(name="silence", age=18, author_detail=detail_obj)
(2)添加书和作者数据
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 图书和作者表
for i in range(1, 6):
detail_obj = AuthorDetail.objects.create(addr=f"上海_{i}", phone=f"1{i}0")
print(detail_obj) # AuthorDetail object (1)
Author.objects.create(name=f"silence{i}", age=18 * i, author_detail=detail_obj)
for i in range(1, 6):
Book.objects.create(
title=f"第 {i} 本书",
price=str(60 * i),
publish_id=random.randint(2, 6)
)
(3)书跟作者进行关联方法
- 第一种方式 : 调用第三张表进行关联
- 如果是你自己创建的第三章模型表你就可以调用第三张表
- 第二种方式 :如果使用 的是Django提供的 ManyToManyField 自动创建的第三张表
- 模型表中是没有这个第三张表的 需要跨表建立联系
现在的场景是基于Django自动创建的第三张表
(4)增加多对多外键关系
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 现在的场景是基于Django自动创建的第三张表
# 1.获取到书籍对象
book_obj = Book.objects.get(pk=3)
# 2.添加多对多外键关系 add
# 给当前书籍添加一个作者
# 获取到当前书籍对象 书籍对象在跨到 作者表身上 加上作者的id
book_obj.author.add(1)
# 多个外键关系直接放ID即可
book_obj.author.add(2,3)
(5)删除多对多外键关系
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 删除多对多外键关系 remove
# 获取到当前书籍对象 书籍对象 在跨到 作者表身上 加上作者的id
# book_obj.author.remove(author_obj)
book_obj = Book.objects.get(pk=3)
book_obj.author.remove(2)
(6)修改外键关系
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 修改外键关系
# 1.方式一 借用 set 方法 弊端就是会清空其他的外键关系
# 使用 关键字 set 的时候 参数是一个列表
# 清空当前对象的所有对对多外键关系 再重新关联新的外键关系
book_obj = Book.objects.get(pk=3)
book_obj.author.set([2])
book_obj.author.set([author_obj]) # 也可以
# 2.方式二 先用 remove 移除外键关系 再用 add 添加外键关系
book_obj = Book.objects.get(pk=3)
author_obj = Author.objects.get(pk=1)
book_obj.author.remove(author_obj) # 先删除
book_obj.author.add(author_obj) # 再添加
- 方式一 借用 set 方法 弊端就是会清空其他的外键关系
- 方式二 先用 remove 移除外键关系 再用 add 添加外键关系
-
先移除
-
再添加
(7)清空
# 清空
# 在第三张表中清除某一本书和作者的绑定关系
book_obj = models.Book.objects.filter(pk=1).first()
# 不要加任何参数
book_obj.authors.clear()
【3】多表查询(正反向查询)
(1)正向
- 有外键关系的两行表 从有外检字段的表向另一张无外键字段的表查询数据的时候就是正向
- 外键字段在我手上,那么我查你就是正向
- book >>>> 外键字段在书这边(正向) >>>> 出版社
(2)反向
- 有外键关系的两行表 从无外键字段的表向另一张有外键字段表查询数据的时候就是反向
- 外键字段不在我手上,那么我查你就是反向
- 出版社>>>> 外键字段在书这边(反向) >>>> book
- 一对一和一对多的判断也是这样
(3)查询方法
- 如果是正向查询 直接按照字段查询
- 如果是反向查询 要使用关键字 _set
(4)子查询(基于对象的跨表查询)
[1]查询 书籍 id 为 3 的出版社的名字
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 查询 书籍 id 为 3 的出版社的名字
# 查询到 id 为 3 的书籍
book_obj = Book.objects.get(id=3)
# 根据查询到的书籍对象获取到关联的出版社 id
# 在根据出版社 ID 在出版社这张表中获取到出版社对象
# 在获取到出版社名字
publish_obj = Publish.objects.get(pk=book_obj.publish_id)
print(publish_obj.name)
# 东京出版社
[2]查询 ID 为8的作者的名字
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 首先拿到book里面id=8的对象
book_obj = Book.objects.get(id=8)
# 因为没有写书和作者多对多的第三张表 现在是django自动创建的第三张表
# 所以没有book_obj.author_id
print(book_obj.author)
# user.Author.None
# 在书和作者的第三张表里面拿到book里面id=8对应的所有对象
print(book_obj.author.all())
# <QuerySet [<Author: Author object (3)>, <Author: Author object (5)>]>
# 对象.属性名拿到对应的属性值
print(book_obj.author.all().values("name"))
# <QuerySet [{'name': 'silence2'}, {'name': 'silence4'}]>
[3]查询 作者 3 的电话号码
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 查询 作者 3 的电话号码
author_obj = Author.objects.get(id=3)
# 方式一 : 根据作者的详情id查到详情对象 再查到电话
detail_obj = AuthorDetail.objects.get(pk=author_obj.author_detail_id)
print(detail_obj.phone) # 120
# 方式二 : 直接根据外键字段获取到详情对象然后获取电话
print(author_obj.author_detail.phone) # 120
[4] 查询出版社是南京出版社出版的书
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 查询出版社是南京出版社出版的书
# 方式一 :
# 先获取到指定出版社的对象
publish_obj = Publish.objects.get(name='南京出版社')
print(publish_obj)
# Publish object (3)
# 再根据出版社id获取到指定的书籍对象 书籍对象提取 书籍名字
book_obj = Book.objects.filter(publish=publish_obj).values("title")
print(book_obj)
# < QuerySet[{'title': '第 2 本书'}] >
# 方式二:
publish_obj = Publish.objects.get(name='南京出版社')
book_obj = publish_obj.book_set
print(book_obj) # user.Book.None
print(book_obj.all().values("title"))
# <QuerySet [{'title': '第 2 本书'}]>
[5] 查询作者 silence写过的书
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 查询作者 silence 写过的书
# 作者表没有外键字段 -- 没有外键字段向有外键字段的查就是法反向要加 _set --> 图书表有外键字段
# 方式一 : 可以先插 silence 的作者对象
author_obj = Author.objects.get(name='silence')
book_obj = author_obj.book_set
print(book_obj) # user.Book.None
print(book_obj.all().values("title"))
# <QuerySet [{'title': '西游记'}, {'title': '第 4 本书'}]>
[6]查询手机号是 120 的 作者 的名字
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 查询手机号是 120 的 作者 的名字
# 详情表没有外键字段 作者表有外键字段
# 从没有外键字段 向 有外键字段 反向
# 一对一外键字段查询数据的时候不区分正反向都是 通过 .字段取值
detail_obj = AuthorDetail.objects.get(phone='120')
print(detail_obj.author.name)
# silence2
【4】小结
- 正向查询:有外键字段向没有外键字段的表查 查询方式是 .字段名
- 反向查询:没有外键字段向有外键字段的表查 查询方式是 有外键字段的表名_set
- 正向查询和反向查询对于 一对多和对多对表关系成立
- 一对一表关系不区分正反向 因为关系唯一
【5】方法补充 _set.all()
- 如果对应的结果是多个的时候 采用 .all()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY