后端:
import socket
server=socket.socket()
server.bind(("127.0.0.1",8080))
server.listen()
while True:
conn,addr=server.accept()
data=conn.recv(1024)
#对字符进行处理
data=data.decode("utf-8")
#获取网址后缀名
conn.send(b"HTTP/1.1 200 ok\r\n\r\n")
current_path=data.split("")[1]
if current_path=='/index':
conn.send(b"byebye")
#忽略favicon.ico文件
conn.send(b"hello") #加入http相关的头
conn.close()
后端:
from wsgiref.simple_server import make_server
def run(env,response):
#相关参数作用
#param env:请求相关的所有数据 #大字典里面有各式各样的数据 wsgiref模块帮你处理好http格式的数据
#param response:响应相关的所有数据
#return :返回给浏览器的数据
#从env中获取后缀
response("200 ok", []) # 响应收行,响应头 括号内加入字典
current_path=env.get("PATH_INFO")
if current_path=='/index':
return [b'index']
#路径不存在返回404错误
return [b'404error']
if __name__ == '__main__':
server=make_server('127.0.0.1',8080,run)
#会实时监听127.0。0.1:8080地址,只要有客户端来了都会交给run函数运行
#flask启动源码 后面加类
server.serve_forever() #启动服务端
打印的env字典数据:
url.py 路由与视图函数对应关系
views.py 视图函数(后端业务逻辑)
templates 专门用来储存html文件
动态网页:
页面上的数据是直接写死的 万年不变
动态网页:
数据实时获取
eg:
1·后端获取当前时间展示到html页面上
2·数据是从数据库中获得的展示在html页面上
动态网页制作
from wsgiref.simple_server import make_server
import datetime
def run(env,response):
#相关参数作用
#param env:请求相关的所有数据 #大字典里面有各式各样的数据 wsgiref模块帮你处理好http格式的数据
#param response:响应相关的所有数据
#return :返回给浏览器的数据
#从env中获取后缀
response("200 ok", []) # 响应收行,响应头 括号内加入字典
print(env)
current_path=env.get("PATH_INFO")
if current_path=='/index':
with open(r"一个html文件.html","r",encoding="utf-8") as f:
file=f.read()
file=file.replace("这一步在html页面上设个flag然后替换即可", str(datetime.datetime.now()))
return [file.encode('utf-8')]
#路径不存在返回404错误
return [b'404error']
if __name__ == '__main__':
server=make_server('127.0.0.1',8080,run)
#会实时监听127.0。0.1:8080地址,只要有客户端来了都会交给run函数运行
#flask启动源码 后面加类
server.serve_forever() #启动服务端
html页面中传入字典
from jinja2 import Template
tmp=Template(data) #data是文件.read()后的值
res=tmp.render(user=user_dic)
页面拿值同上replace方法
{{ user }}
python三大主流web框架:
django:
特点: 大而全, 自带的功能特别特别特别的多, 类似于航空母舰
不足之处: 有时候过于笨重
flask:
特点: 小而精, 自带的功能特别特别特别的少, 类似于游骑兵
第三方的模块特别特别特别的多, 如果将flask第三方的模块加起来完全可以盖过django,并且也越来越像django
不足之处: 比较依赖于第三方的开发者
tornado:
特点:异步非阻塞, 支持高并发
牛逼到甚至可以开发游戏服务器
#####################################################
A : socket部分 B: 路由与视图函数对应关系(路由匹配) C: 模版语法
django 别人的, wsgiref模块 自己写 自己的(没有jinja2好用 但是也很方便)
flask 别人的 werkzeug(内部还是wsgiref模块) 自己写 别人的(jinja2)
tornado 自己写 自己写 自己写
django安装:
pip install django==1.11.11
#如果装了其他版本无需卸载直接装即可
#django项目启动
命令行版:
#创建django项目
#可以先cd到一个盘然后再创建
django-admin startproject 项目名
mysite文件夹
——mange.py
——mysite文件夹
————setting.py
————urls.py
————wsgi.py
#启动django项目
一定要先切换到项目目录下
python3 mange.py runserver
#3.创建应用:
django是一款专门用来开发app的web框架
python manage.py startapp app名字
#创建应用一定要在配置文件中注册
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app02',
#或者
#'app02.apps.App02Config'
]
#1.命令行创建不会自动有templatew文件夹 需要你自己手动配置创建而pycharm会自动帮你创建
#并且还会自动在配置文件中帮你配置路径
pycharm创建:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
命令行创建的:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': []
#命令行创建的django项目的时候不单单需要创建templates文件夹还需要去配置文件中的路径
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
-mysite项目文件夹
–mysite文件夹
—setting.py 配置文件
—urls .py 路由与视图函数对应关系
—wsgi.py wsgiref模块
–mange .py django的入口文件
–db.sqlite3 django自带的sqlite3数据库(小型数据库 功能少 bug)
–app01文件夹
—admin.py django后台管理
—apps.py 注册使用
—migrations 数据库迁移记录
—models .py 数据库相关的 模型类
—test .py 测试文件
—views.py 视图函数
setting详细:
"""
Django settings for untitled10 project.
Generated by 'django-admin startproject' using Django 1.11.11.
For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'k-emmcy4-0(zf14&vz)hplvv3+xff)w&j(*)w*!oo)3^w+(4$j'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True #上线后改为flase 就是打印很多信息
ALLOWED_HOSTS = [] #允许访问的主机 用*代表全部
# Application definition
#注册的app (app就是功能模块)
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
#'app02',
#或者
'app02.apps.App02Config',
]
#django中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'untitled10.urls'
#html文件路径配置
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'untitled10.wsgi.application'
#数据库 默认sqlite3
# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/
STATIC_URL = '/static/'
在templates的同级文件夹下创建一个static文件
#静态文件夹
前端已经写好了 能够直接调用使用的文件
网站写好的js文件
网站写好的css文件
网站用到的图片文件
第三方前端框架
在setting中的操作:
#STATIC_URL就是页面导入令牌
STATIC_URL = '/static/'
#/static/为一个令牌取列表中的路径依次向下查找
#静态文件配置
STATICFILES_DIRS=[
os.path.join(BASE_DIR,"static"),
#注意这个是从这几个文件夹中找
]
#当你在写django项目的时候 可能会出现后端代码修改但是前端页面没有变化的情况
1.同时在run两个django项目
2.浏览器缓存问题
静态文件的动态解析static_url
{% load static %} #类似于导模块
<a href="{ % static'加入导入静态模块的路径' % }">a>
form表单action参数
1.不写 默认朝当前所在的url提交数据
2.全写
3.只写后缀
提交表单的时候会遇见这个问题:
解决:
###在前期我们使用django提交post请求的时候 需要取配置文件中注释掉一行代码
#django中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
request.method
返回method的类型:post或get
#返回请求的方式 并且是全大写的字符串
from django.shortcuts import render,HttpResponse
# Create your views here.
def login(request):
#返回登录界面
#get请求和post请求应该有不同的处理机制
#:param request:
#:return:
print(request.method)
#返回请求的方式 并且是全大写的字符串
if request.method=="POST":
return render(request,"debug_login.html")
return render(request,'login.html')
#这里的login.html和debug_login.html借用了河南某211高校的打卡界面进行分析
获取用户数据
request.post
输入用户名和密码:
返回以下字典
返回一个字典(字典里面是一个列表形式的字符串):
#且只能返回列表元素的最后一个
检验代码:
uid=request.POST.get("uid") #获取uid
print(type(uid)) #打印uid发现形式为列表形式的字符串
upw=request.POST.get("upw") #获取upw
request.POST.getlist
代码:
from django.shortcuts import render,HttpResponse
# Create your views here.
def login(request):
#返回登录界面
#get请求和post请求应该有不同的处理机制
#:param request:
#:return:
print(request.method)
#返回请求的方式 并且是全大写的字符串
if request.method=="POST":
print(request.POST) # 获取用户提交的post请求
#uid=request.POST.get("uid") #获取uid
uid=request.POST.getlist("uid") #获取uid对应的列表(get方法只能获得字符串类型的uid数据)
print(type(uid)) #打印uid发现形式为列表形式的字符串
#upw=request.POST.get("upw") #获取upw
upw=request.POST.getlist("upw")
return render(request,"debug_login.html")
return render(request, 'login.html')
获得get方法返回的值
get方法返回的和post方法一样
如下:
request.GET
request.GET.get #获取的数据同post
request.GET.getlist #获取的数据同post
注意:get方法获取的数据较小只有4kb左右
而post方法没有限制
pycahrm使用mysql
pycharm的右侧有一个:
pycharm支持的数据库:
安装对应的驱动:
在navicat中创建表和填入数据:
在pycharm中添加连接即可
#django默认连接sqkite3
1.第一步配置文件修改:
# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
# }
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "username",
'USER':"root",
"HOST":"127.0.0.1",
"PORT":3306,
"PASSWORD":"*************",
"CHARSET":"UTF8",
}
}
2.代码声明:
django默认用的是mysqldb模块连接mysql
但是mysqldb模块兼容型差 需要手动改为mysql模块
#在项目名中的init.py或者任意的应用名下的init文件中书写以下代码:
(这个我的项目启动时候没有报错可能是因为我已经按照的mysqldb)
import pymysql
pymysql.install_as_MySQLdb()
DJANGO ORM
orm,对象关系映射
作用:能够让一个不会mysql的人通过python 面向对象的代码简单快捷的操作数据库:
不足之处:有时候sql语句效率偏低 需要你自己写sql语句
应用models.py文件
from django.db import models
# Create your models here.
class User(models.Model):
#等价于id int primary_key auto_increment
id =models.AutoField(primary_key=True)
#username varchar(32)
#charfield必须指定max_length 不然会报错
#verbose_name该参数是所以字段都有的 就是用来对字段的解释
username = models.CharField(max_length=32)
#password int
password= models.IntegerField()
###########数据库迁移命令#################
#linux系统上用(windows系统把python3换成python即可)
python3 manage.py makemigrations #将操作记录转移到migrations文件夹
python3 manage.py migrate #将操作真正的同步到数据库中
在python3 manage.py migrate命令后的结果
python3 manage.py makemigrations命令运行的结果:
#只要你修改了model.py中跟数据库相关的代码 就必须重新执行上述两条命令
注意:
class Author(models.Model):
#由于一张表中必须有一个主建字段 并且一般就叫id
#所以当你不定义主键字段时候 orm会自动帮你创建一个名为id的字段
username =models.CharField(max_length=32)
password =models.IntegerField()
字段的增加:
1.可以直接在终端给出默认值
2.该字段可以为空
3.直接设置默认值
inf=models.CharField(max_length=32,verbose_name="students inf",null=True,default='study')
#字段的增加过程中如果遇到问题:
django.db.utils.InternalError: (1050, "Table 'tb_books' already exists")
字段的修改:
直接修改即可 然后执行两条数据库迁移命令
字段删除:
直接修改即可 然后执行两条数据库迁移命令
查
#这个语句等价于select * from Users where name="";
##这个语句可以加入多个参数 默认用and连接多参
res=models.Users.objects.filter(userlist=uid)
#在userlist表中查询uid的值 返回值是列表套数据的格式
它也支持索引取值 切片取值 但是不支持负数索引
它也不推荐用索引的方法取值
可以用
.first() # 取列表里面第一个值
res=models.Users.objects.filter(userlist=uid).first()
一个简单的登录功能的实现
if res:
if upw==res.password:
return HttpResponse("登录成功")
else:
return HttpResponse("密码错误")
else:
return render(request,"debug_login.html")
数据的增加
第一种方法:
res=models.userlist.objects.create(username=username,password=password)
#返回的是当前被创建对象的本身
#对数据库进行增加
具体代码:
def reg(request):
#给用户返回一个注册界面
if request.method=='POST':
#获得uid所对应的input标签返回的post请求
username=request.POST.get("uid")
password=request.POST.get("upw")
#将请求返回数据库 res=models.userlist.objects.create(username=username,password=password)
print(res)
return render(request,"reg.html")
#利用类的方法实例化对象
res=models.userlist(username=username,password=password)
#进行保存
res.save()
数据的查询
查询所有数据:
data=models.userlist.objects.filter()
#或者
data=models.userlist.objects.all()
具体代码:
def userlist(request):
#查询出用户表里面所有的数据
data=models.userlist.objects.filter()
print(data)
return HttpResponse(data)
def userlist(request):
#查询出用户表里面所有的数据
data=models.userlist.objects.filter()
print(data)
#local()就是把这个函数所返回的数据全部导入render()函数中
return render(request,'userlist.html',locals())
后端用for循环展示对象并且用{{user_obj.id}}方法 来获得后端返回的值
前端代码:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>$Title$title>
head>
<body>
{{ data }}
<h1 class="text-center">数据展示h1>
<div class="container">
<div class="row1">
<div class="collapse-toggle">
<table>
<thead>
<tr>
<th>IDth>
<th>usernameth>
<th>passwordth>
<th>actionth>
tr>
thead>
<tbody>
{% for user_obj in data %}
<tr>
<td>{{ user_obj.id }}td>
<td>{{ user_obj.username}}td>
<td>{{ user_obj.password }}td>
<td>
<a href="/edit_user/?user_id={{ user_obj.id }}">编 辑a>
<a href="">删 除a>
td>
tr>
{% endfor %}
tbody>
table>
div>
div>
div>
body>
html>
for循环处理数据:
{% for user_obj in data %}
<tr>
<td>{{ user_obj.id }}td>
<td>{{ user_obj.username}}td>
<td>{{ user_obj.password }}td>
<td>
<a href="/edit_user/?user_id={{ user_obj.id }}">编 辑a>
<a href="">删 除a>
td>
tr>
{% endfor %}
结果:
数据的修改
#如何将修改那一行的主键值返回给后端?
前端:
<a href="/edit_user/?user_id={{ user_obj.id }}">编 辑a>
#“?”后面的数据在网页中不匹配 可以用来返回主键
后端:
#获取url问号后面的参数
edit_id=request.GET.get("user_id")
#修改数据的两个方法:
#用filter筛选出来所有id=edit_id的数据进行批量更新
models.userlist.objects.filter(id=edit_id).update(username=username,password=password)
#使用edit_obj返回一个类然后在对数据进行处理
#但字段特别多的时候效率比较低(从头到尾全部修改一下 无论字段是否被修改)
#修改数据方法二
edit_obj=models.userlist.objects.filter(id=edit_id).first()
edit_obj.username=username
edit_obj.password=password
edit_obj.save()
一个简单的编辑页面的代码:
后端:
def edit_user(request):
# 获取url问号后面的参数
edit_id = request.GET.get("user_id")
if request.method=="POST":
#获取数据库中的应用
username = request.POST.get("username")
password = request.POST.get("password")
print(username,password)
#取数据库中修改对应的数据
#修改数据方式一
models.userlist.objects.filter(id=edit_id).update(username=username,password=password)
#用filter筛选出来所有id=edit_id的数据进行批量更新
#返回数据展示页面
return redirect('/userlist/')
#查询当前数据想要编辑的数据
edit_obj=models.userlist.objects.filter(id=edit_id).first()
#将数据展示到页面上
return render(request,"edit_userlist.html",locals())
前端:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>$Title$title>
head>
<body>
{{ data }}
<h1 class="text-center">数据展示h1>
<div class="container">
<div class="row1">
<div class="collapse-toggle">
<table>
<thead>
<tr>
<th>IDth>
<th>usernameth>
<th>passwordth>
<th>actionth>
tr>
thead>
<tbody>
{% for user_obj in data %}
<tr>
<td>{{ user_obj.id }}td>
<td>{{ user_obj.username}}td>
<td>{{ user_obj.password }}td>
<td>
<a href="/edit_user/?user_id={{ user_obj.id }}">编 辑a>
<a href="">删 除a>
td>
tr>
{% endfor %}
tbody>
table>
div>
div>
div>
body>
html>
数据的删除
delete_obj.delete()
后端:
def delete_user(request):
delete_id = request.GET.get("user_id")
delete_obj = models.userlist.objects.filter(id=delete_id)
#二次确认 学了ajxs之后在考虑
#删除数据
delete_obj.delete()
return redirect('/userlist/')
#删除数据内部不是真正的删除 我们会把数据添加一个标识字段来表示数据是否被删除 如果被删除只是修改一下它的状态
#外键要建到查询频率较高的地方
一对一
一对多
多对多
一个很好的讲表关系的博客
API:
一对多关系:
publish=models.ForeighKey(to="Publish")
#创建的字段 会自动的在字段后面加上_id 如:publish_id
#默认以表的主键字段当外键关联
多对多关系:
authors = models.ManyToManyField(to="Author")
#authors是一个虚拟字段 主要是用来告诉orm 书籍表和作者表是多对多关系
#让orm自动帮你创建第三张表
一对一关系:
author_detail = models.OneToOneField(to = "AuthorDetail")
#创建的字段 会自动的在字段后面加上_id
class book(request):
title = models.CharField(max_length=32)
#小数总共八位 小数点后面占两位
price = models.DecimalField(max_digits=8,decimal_places=2)
class Publish(request):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
class Author(models.Model):
phone = models.CharField(max_length=32)
age = models.IntegerField()
author_detail = models.OneToOneField(to = "AuthorDetail")
class AuthorDetail(models.Model):
phone = models.BigIntegerField()
addr = models.CharField(max_length=32)
#django1.x版本中外键默认都是级联更新删除的
#多对多的表关系还有很多的创建方式 这里是其中一种
#扩展知识点
缓存数据库:
提取已经将你想要的数据准备好了 你直接拿就可以了
提高效率和响应时间
urls.py:
url(r'test',views_01.test),
url(r'testadd',views_01.testadd)
views.py:
from django.shortcuts import render,HttpResponse
# Create your views here.
def test(request):
return HttpResponse("test")
def testadd(request):
return HttpResponse("testadd")
因为url方法的第一个参数是代表的是正则表达式,只要第一个参数正则能够匹配到内容 那么就会立刻停止往下匹配 所以,test所对的路由,和testadd所对应的路由是一样
#你在输入url的时候会默认加入斜杠
django内部帮你做到重定向
一次匹配不行
url后面加斜杠在来一次
取消这个功能的方法:
setting.py中加入这个参数
#取消自动加斜杠的功能
APP_SLASH=False
有时候匹配的时候在后面加入$号表示
严格以t开头以t结尾
url(r'^test/$',views_01.test),
url(r'^testadd/$',views_01.testadd)
匹配首页
url(r'^$',views.home)
匹配尾页:
#这行代码要加到最后一行
url(r'',views.error)
分组:给某一段正则表达式加入一个小括号进行分组
urls.py
无名分组:
url(r'^test/(/d+)/',views_01.test),
views.py
def test(request,either):
print(xx)
return HttpResponse("test")
#无名分组就是将括号内的正则表达式的内容获取当成位置参数,传递给后面的视图函数
有名分组:
#可以给正则表达式起一个别名
#?P给括号内的正则表达式起一个别名year
#有名匹配
#?P给括号内的正则表达式起一个别名year
url(r'^testadd/(?P\d+)' ,views_01.testadd),
views.py函数:
def testadd(request,year):
print(year)
return HttpResponse("testadd")
#有名参数就是将括号内的正则表达式匹配到的内容当作关键字参数传递给后面的视图函数
无名有名函数混用
#不能混用 但是同一个分组可以加多个有名分组 或者可以加多个无名分组(推荐使用有名分组)
#通过一些方法得到一个结果 该结果可以直接访问对应的url触发视图函数
1.先给路由和视图函数起一个别名
2.反向解析
#后端反向解析
#反向解析记得导入模块
from django.shortcuts import render,HttpResponse,reverse
views.py
reverse("func")
urls.py
url(r"^func/$",views_01.func,name='func'),
#前端反向解析
home.html
<a href="{% url 'func' %}">111a>
urls.py
url(r"^func/$",views_01.func,name='func'),
无名分组反向解析:
url(r"^index/(\d+)/",views.index,name="index"),
#前端:这个123表示的是 他的args={1,2,3,}
{% url "index" 123 %}
#后端
reverse("index",args={1,})
#数字一般情况下放的是数据的主键值 数据的编辑和删除
url(r"^edit/(\d+)/",views.edit_id,name='edit')
def edit(request,edit):
reverse("edit",args={edit,})
{{% for use_obj in user_queryset %}}
<a href="{{% url "edit" user_obj.id %}}
{{%endfor%}}
django每一个应用都可以有自己的templates文件夹,urls.py ,static文件夹 正是基于上述特点,django能够非常好的做到分组开发(每个人只写自己的app)。
如果app中没有urls,py文件自己创建即可
一个基本的urls.py文件
"""untitled10 URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
urlpatterns = [
]
#利用路由分发之后 总路由不在干路由与视图函数的直接对应关系而是做一个分发处理
#识别当前url是属于哪个应用下的 直接分发给对应的应用去处理
#给urls起别名的原因是防止多个app中的url出现重名
from app01 import urls as app01_urls
urlpatterns=[
#路由分发
#只要url前缀是app01开头的 全部交给app01处理
url(r'app01/',include(app01_urls))
]
#或者可以不导模块
url(r"^app01/",include("app01.urls"))
#当多个应用出现了相同的别名 我们研究反向解析会不会自动识别应用前缀
##正常情况下的反向解析是没有办法自动识别前缀的##
url(r"^app01/",include("app01.urls",namespace='app01'))
名称空间解析:
后端:
def reg(request):
reverse("app01:reg")
前端:
{% url "app01:reg" %}
#一般情况下有多个app的时候 我们在起别名的时候会加上app的前缀
#这样一般情况下就能保证多个app之间名字不冲突
将一个动态网页位置成静态网页
伪装的目的在于增大本网站的seo查询力度
并且增大搜索引擎收藏本网上的概率
搜索引擎本质就是一个巨大的爬虫程序
#无论你怎么优化怎么处理
还是不胜人家冲点钱
#伪静态实现直接在app01后面加上.html即可
url(r"^app01。html",include("app01.urls",namespace='app01'))
虚拟环境就类似于python解释器环境
#每创建一个虚拟环境就类似于你重新下载一个python解释器#
#虚拟环境不要下载太多 很占磁盘环境#
#开发中我们会配置一个requirement.txt文件
里面书写了该项目所有的模块和版本
#直接输入
pip install -r requirements.txt
一个很好的博客
即可安装
虚拟环境创建
pip install virtualenv
virtualenv test #test为虚拟环境名字
#默认创建在本目录下 需要cd到该文件下运行该命令
路由层
1.X用的是url
2.X、3.X用的是path
url第一个参数是一个正则表达式
而path第一个参数不支持正则表达式 写什么就匹配什么
如果你觉得path不好用 2.x、3.x给你提供了一个跟url一样的功能
re_path 等价于1.x里面的url功能
虽然path不支持正则表达式 但是它给你提供了五种默认的转换器
str:匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int:匹配正整数,包含0。
slug:匹配字母、数字以及横杠、下划线组成的字符串。
uuid:匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path:匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
path('login//' ,login)
除了默认的五种转换器之外 还支持你自定义转换器
自定义转换器
class MonthConverter:
regex=’\d{2}’ # 属性名必须为regex
def to_python(self, value):
return int(value)
def to_url(self, value):
return value # 匹配的regex是两个数字,返回的结果也必须是两个数字
#这里引用了一个博客
https://www.cnblogs.com/csic716/p/12158457.html
4.模型层里面1.x外键默认都是级联更新和删除的
但是在2.x和3.x中需要手动加参数
models.ForeignKey(on_delete=models.CASCADE,to="PUSH")
这一段笔记电脑突然关机了QAQ
只剩下代码:
def ab_json(request):
# import json
from django.http import JsonResponse
#user_dict={"username":"mzy你好","password":"123","hobby":"study"}
# #先转化为json格式字符串
# json_str=json.dumps(user_dict,ensure_ascii=False)
# #f返回到前端
# return HttpResponse(json_str)
from django.http import JsonResponse
user_dict = {"username": "mzy你好", "password": "123", "hobby": "study"}
return JsonResponse(user_dict)
return JsonResponse(user_dict,json_dumps_params={"ensure_ascii":False})
#结局乱码问题#
jsonresponse数据返回非json串数据
l=[111,222,333]
return JsonResponse(l,safe=False)
前端序列化:
JSON.stringify() json.dumps()
json.parse() json.loads()
from表单上传文件类型数据
1.method必须指定成post
2.enctype必须换成formdata
##获取数据时候不能使用request.POST方法应该使用request.FILES方法获取文件数据
保存文件的方法:
with open(file_obj.name,"wb") as f:
for line in file_obj:
f.write(line)
总和代码:
##这里可以在templates文件夹里面建一个file_get文件夹然后with方法保存数据
def ab_file(request):
if request.method=="POST":
print(request.POST) #request.POST只能获得普通的键值对的数据 文件不行
print(request.FILES) #获取文件数据
file_obj=request.FILES.get("file") #文件对象
print(file_obj.name) #获取文件名字
#保存文件
path='C:/Users/mzy/Desktop/pycharmproject/untitled10/templates/file_get/'
with open(path+file_obj.name,"wb") as f:
for line in file_obj:
f.write(line)
print("end")
return render(request,"ab_file.html")
request.method #获得请求类型
request.POST #获得post请求对象 不能获得文件
request.GET #获得get请求对象
request.FILES #获得post请求的文件
request.path #获取路由
request.path_inf #获取路由
request.get_full_path() #获取路由和后面完整参数
request.body #原生的浏览器发送的二进制数据
#视图函数可以是函数也可以是类
def index(request):
return HttpResponse("index")
CBV
urls.py
url(r"^login_my/",views_03.Mylogin.as_view())
views.py
from django.views import View
class Mylogin(View):
def get(self,request):
return render(request,"ab_file.html")
def post(self,request):
return HttpResponse("Post")
#函数名/方法名 加括号表示执行优先级最高
urls.py
url(r"^login/",views_04.Mylogin.as_view())
as_views()#是被@classonlymethod修饰的类方法:
源码:
@classonlymethod
def as_view(cls, **initkwargs):
"""
Main entry point for a request-response process.
"""
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError("You tried to pass in the %s method name as a "
"keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key))
def view(request, *args, **kwargs):
self = cls(**initkwargs) #cls是我们自己写的类
#self = Mylogin(**initkwargs) 产生我们写的类对象
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs)
#以后会经常看源码 一定要时刻提醒自己面向对象属性方法查找顺序
#先去对象自己找
#再去产生对象的类里面找
#之后在去父类找
view.view_class = cls
view.view_initkwargs = initkwargs
# take name and docstring from class
update_wrapper(view, cls, updated=())
# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
return view
#dispatch方法
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
#获取当前请求的小写格式 然后比对当前请求是否合法
if request.method.lower() in self.http_method_names:
#八个默认的请求
# http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head','options','trace']
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
#反射:通过字符串来操作对象的属性或者方法
#getattr(自己写的类产生的对象,“get”,当找不到get属性或者方法的时候就会用第三个参数)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
#自动调用get方法
因为这个方法是启动as_view函数并且返回view,且加括号表示执行优先级最高
#所以上述代码在启动django的时候就会立刻执行as_view方法
所以该代码等价于:url(r"^login/",views.view) 和FBV一样
#CBV和FBV在路由匹配上本质是一样的 都是路由 对应 函数内存地址
views.py
from django.shortcuts import render,HttpResponse
from django.views import View
# Create your views here.
class Mylogin(View):
def get(self,request):
return render(request,"login.html")
def post(self,request):
return HttpResponse("post")
locals()
locals 函数更新并以字典形式返回当前全部局部变量
return render(request,"index.html",{}) #{}内加入要返回的函数值
{{}}:变量相关
{%%}:逻辑相关
##传递函数名会自动加括号调用 但是模板语法不支持给函数传递额外的参数:{{ func }}
##函数中传递给前端的数是函数的返回值
##传递类名的时候也会自动加括号调用(实例化)
##内部会自动判读当前的变量名是否可以加括号调用 如果可以就会自动执行 针对的是函数名和类名
##对象展示到html页面上就类似于print,将结果展示在html
##django模板语法的取值 是固定的格式 只能采用“句点符”
##即可以点建也可以点索引 还可以两者混用
过滤器就相当于模板语法内置的内置方法
#django内置有六十个模板语法
#基本语法:
{{数据|过滤器:参数}}
#统计长度:
#后端:
s="mzy"
#前端:
{{s|length}}
内部方法:
@register.filter(is_safe=False)
def length(value):
"""Returns the length of the value - useful for lists."""
try:
return len(value)
except (ValueError, TypeError):
return 0
#默认值
#后端
b=False
#前端
{{ b|default:"mzy" }}
#类似于异常捕获 如果前面有值就用前面的 如果前面没值就采用default方法
#内部源码:
@register.filter(is_safe=False)
def default(value, arg):
"""If value is unavailable, use given default."""
return value or arg
#文件大小:
#前端:
{{ file_size|filesizeformat }}
#内部源码:
def filesize_number_format(value):
return formats.number_format(round(value, 1), 1)
KB = 1 << 10
MB = 1 << 20
GB = 1 << 30
TB = 1 << 40
PB = 1 << 50
negative = bytes_ < 0
if negative:
bytes_ = -bytes_ # Allow formatting of negative numbers.
if bytes_ < KB:
value = ungettext("%(size)d byte", "%(size)d bytes", bytes_) % {'size': bytes_}
elif bytes_ < MB:
value = ugettext("%s KB") % filesize_number_format(bytes_ / KB)
elif bytes_ < GB:
value = ugettext("%s MB") % filesize_number_format(bytes_ / MB)
elif bytes_ < TB:
value = ugettext("%s GB") % filesize_number_format(bytes_ / GB)
elif bytes_ < PB:
value = ugettext("%s TB") % filesize_number_format(bytes_ / TB)
else:
value = ugettext("%s PB") % filesize_number_format(bytes_ / PB)
if negative:
value = "-%s" % value
return avoid_wrapping(value)
#日期格式化
{s|date:"Y-m-d H:i:s"}
#默认是utc时间
#内部源码:
@register.filter(expects_localtime=True, is_safe=False)
def date(value, arg=None):
"""Formats a date according to the given format."""
if value in (None, ''):
return ''
try:
return formats.date_format(value, arg)
except AttributeError:
try:
return format(value, arg)
except AttributeError:
return ''
#切片操作
{l|slice:"0:4:2"} #0代表起始位置 4代表末尾位置 2代表步长
#内部源码:
@register.filter("slice", is_safe=True)
def slice_filter(value, arg):
"""
Returns a slice of the list.
Uses the same syntax as Python's list slicing; see
http://www.diveintopython3.net/native-datatypes.html#slicinglists
for an introduction.
"""
try:
bits = []
for x in arg.split(':'):
if len(x) == 0:
bits.append(None)
else:
bits.append(int(x))
return value[slice(*bits)]
except (ValueError, TypeError):
return value # Fail silently.
#切取字符(摘要)
{{ inf|truncatechars:9 }}
#这里九个字符包括摘要后面的三个点
#内部源码:
register.filter(is_safe=True)
@stringfilter
def truncatechars(value, arg):
"""
Truncates a string after a certain number of characters.
Argument: Number of characters to truncate after.
"""
try:
length = int(arg)
except ValueError: # Invalid literal for int().
return value # Fail silently.
return Truncator(value).chars(length)
#切取单词
{{ l|truncatewords:9 }}
#这个切取是按照空格切取,且不包含后面三个点
#内部源码:
@register.filter(is_safe=True)
@stringfilter
def truncatewords(value, arg):
"""
Truncates a string after a certain number of words.
Argument: Number of words to truncate after.
Newlines within the string are removed.
"""
try:
length = int(arg)
except ValueError: # Invalid literal for int().
return value # Fail silently.
return Truncator(value).words(length, truncate=' ...')
#移除特定的字符
{{ msg|cut:"*" }} #*代表要切除字符串里面的*
#内部源码:
@register.filter
@stringfilter
def cut(value, arg):
"""
Removes all values of arg from the given string.
"""
safe = isinstance(value, SafeData)
value = value.replace(arg, '')
if safe and arg != ';':
return mark_safe(value)
return value
#字符串拼接:
{{ l|join:"$" }} #将列表以$拼接
#内部源码:
@register.filter(is_safe=True, needs_autoescape=True)
def join(value, arg, autoescape=True):
"""
Joins a list with a string, like Python's ``str.join(list)``.
"""
value = map(force_text, value)
if autoescape:
value = [conditional_escape(v) for v in value]
try:
data = conditional_escape(arg).join(value)
except AttributeError: # fail silently but nicely
return value
return mark_safe(data)
#拼接操作(加法):
{{ n|add:s }} #相当于“+”可以拼接字符串也可以数字相加
@register.filter(is_safe=False)
def add(value, arg):
"""Adds the arg to the value."""
try:
return int(value) + int(arg)
except (ValueError, TypeError):
try:
return value + arg
except Exception:
return ''
#转义:
{{ h|safe }} #这个可以让字符串型的标签在浏览器中进行转义(即以html形式在前端表示)
#内部源码:
@register.filter(is_safe=True)
@stringfilter
def safe(value):
"""
Marks the value as a string that should not be auto-escaped.
"""
return mark_safe(value)
#mark_safe函数:
def mark_safe(s):
"""
Explicitly mark a string as safe for (HTML) output purposes. The returned
object can be used everywhere a string or unicode object is appropriate.
If used on a method as a decorator, mark the returned data as safe.
Can be called multiple times on a single string.
"""
if hasattr(s, '__html__'):
return s
if isinstance(s, bytes) or (isinstance(s, Promise) and s._delegate_bytes):
return SafeBytes(s)
if isinstance(s, (six.text_type, Promise)):
return SafeText(s)
if callable(s):
return _safety_decorator(mark_safe, s)
return SafeString(str(s))
#后端转义
#函数里面放入:
from django.utils.safestring import mark_safe
h="**** "
res=mark_safe(h)
#在前端{{ h }} #浏览器直接显示“*****”
###以后你在全栈项目开发的时候 前端代码不一定非要在前端页面书写
###也可以在后端写好 然后在传递给前端
#for循环:
#后端
def index(request):
#模板语法可以传递的后端python数据类型
#{}里面可以加入想要返回后端的值但是local()方法也可以直接返回后端值
line=[1,2,3,4,5,6]
return render(request,"index.html",locals())
#前端{% for foo in line %}
<p>{{ forloop }}p>
{% endfor %}
#forloop简介:
#上述代码运行结果:
###用这个可以通过字典里的参数获得:位于for循环的正序(counter),倒序(recounter),第一个(first),最后一个(last),列表中的第几个(counter0)###
#if判断
{% if line %}
<p>sssp>
{% elif c%}
<p>cccp>
{% else %}
<p>bbbbp>
{% endif %}
##注意在for循环里面可以加if判断
{% for foo in line %}
{{ forloop.first }}
{% if forloop.first %}
<p>这是第一次for循环,他的值为 {{ foo }}p>
{% if forloop.last %}
<p>这是最后一次for循环,他的值为{{ foo }}p>
{% endif %}
{% elif foo %}
<p>这是第{{ forloop.counter }}次for循环,他的值为{{ foo }}p>
{% endif %}
{% empty %}
<p>for循环是空的不能循环p>
{% endfor %}
#这个{ %empty% }表示的是for循环对象为空时,采用以下{% empty %}相当于default,
#这个模板语法很贴近python后端
#with
with:使用一个简单地名字缓存一个复杂的变量,当你需要使用一个“昂贵的”方法(比如访问数据库)很多次的时候是非常有用的
{% with total=business.employees.count %}
{{ total }} employee{{ total|pluralize }}
{% endwith %}
<p>{{ person_list.2.name }}p>
{% with name=person_list.2.name %}
<p>{{ name }}p>
{% endwith %}
<#或者用更接近python语法的方法#>
{% with totals as to %}
{% endwith %}
#在应用下创建一个名字叫templatetags文件夹
#在该文件夹下创建任意名字的py文件
#在py文件中必须引用两个话
from django import template
register=template.Library()
#自定义过滤器
@register.filter(name="my_add")
def my_add(v1,v2):
try:
if int(v1) and int(v2):
return int(v1)+int(v2)
except:
#表示如果进行不了加和就返回0
return 0
#前端:
{% load mytag %}
<p>{{ n|my_add:666 }}p>
##自定义过滤器就相当于最多只有两个参数的的函数##(后面如果传字典或者列表也可以(#更狠的可以加入字符串然后通过切割操作来进入多参))##
#自定义标签(可加多个参数)(就像自定义函数)
{#标签多个参数要用空格隔开#}
<P>{% plug "jason" 1 2 3 %}P>
#后端:
#自定义标签
@register.simple_tag(name="plug")
def index(a,b,c,d):
return "%s-%s-%s-%s"%(a,b,c,d)
#自定义inclusion_tag
内部原理:
先定义一个方法
在页面上调用该方法 并且可以传值
该方法会生成一些数据然后传递给html页面
之后将渲染好的结果放到调用的位置
#后端:
#自定义inclusion_tag
@register.inclusion_tag("left.html")
def left(n):
data=["第{}项".format(i) for i in range(n)]
return locals()
#left.html页面
<ul>
{% for foo in data %}
<li>{{ foo }}li>
{% endfor %}
ul>
#前端
{% load mytag %}
{#这是inclusiontags#}
{% left 10 %}
#总结:当html页面需要传参数才能动态的渲染出来,并且在多个页面上都需要使用到该局部 那么就考虑将该局面页面做成inclusiontags形式
#母版基本不变 只有母版中某个部分进行改变
母版
主要功能是给其它模板继承的
会为其它模板预留一些自定义的区块
{% block 块名 %}
{% endblock 块名 %}
子版
可以继承母版
同时往母版预留的区域中插入内容
往区域中插入内容
{% block 块名 %}
{% endblock 块名 %}
注意:
如果你在模版中使用 {% extends %} 标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作。
#这是母版页面:
#这是子版页面:
#模板的继承 自己先选好一个想要继承的模板页面
#{% extends “home.html” %}
#继承了子页面跟模板页面长的一模一样 你需要在模板页面上提前划定可以被修改的区域
{% block 块名 %}
模板内容
{% endblock 块名 %}
#子页面就可以声明要修改哪一片划定的区域
{% block 块名 %}
子页面内容
{% endblock 块名 %}
#一般情况下,模板页面至少有三块可以被修改的区域
css区域
js区域
html区域
#这样可以使每一个子页面有不同的css
直接建立一个html文件
{% include "这个html文件" %}
#这样可以把这个html页面中所有代码导入该html
#django自带的sqlite3数据库对日期格式不是很敏感 处理时候容易出错
当你只是想测试django中某一个py文件内容 那么你可以不用书写前后端的形式 而是直接写一个测试脚本即可
#测试环境配置
#在测试环境前加入这几行代码即可##
import os
import sys
import django
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "untitled10.settings")
django.setup()
#测试models文件
from django.test import TestCase
# Create your tests here.
import os
import sys
import django
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "untitled10.settings")
django.setup()
from app05 import models
models.user.objects.all()
##脚本代码无论是写在应用下的test.py文件还是自己单独开设的py文件都可以##
##所有代码都必须等待环境准备完毕后才能书写##
#查询所有
#带有过滤对象的查询
#直接拿数据对象 但是条件不存在直接报错
#拿queryset里面的第一元素
#源码:
def first(self):
"""
Returns the first object of a query, returns None if no match is found.
"""
objects = list((self if self.ordered else self.order_by('pk'))[:1])
if objects:
return objects[0]
return None
#拿queryset里面的最后一个元素
#源码:
def last(self):
"""
Returns the last object of a query, returns None if no match is found.
"""
#取反然后再索引零
objects = list((self.reverse() if self.ordered else self.order_by('-pk'))[:1])
if objects:
return objects[0]
return None
#可以指定获取数据字段
#返回结果是列表套字典
res=models.user_app05.objects.values("name")
print(res)
#输出图片
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p0ICMVFs-1613568064111)(C:\Users\mzy\AppData\Roaming\Typora\typora-user-images\image-20210205223835887.png)]
#可以指定获取数据字段
#返回结果是列表套元组
res=models.user_app05.objects.values_list("name")
print(res)
#输出图片
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NshNwHoo-1613568064115)(C:\Users\mzy\AppData\Roaming\Typora\typora-user-images\image-20210205224149578.png)]
#去重
#去重一定是一模一样的数据#
#如果带有主键那么肯定不一样 查询的时候注意主键
#排序
#默认升序
res=models.user_app05.objects.order_by("name")
#降序
res = models.user_app05.objects.order_by("-name")
#反转的前提是 数据已经排过序了(否则报错)
#统计当前数据个数
res=models.user_app05.objects.count()
#排除什么在外
res=models.user_app05.objects.exclude()
#判断什么是否存在
#存在返回true否则返回false
res=models.user_app05.objects.filter(pk=10).exists()
#输出语句后面可以加入query可以查看内部封装的sql语句(只能是queryset对象才能用.query来查看sql语句)
res=models.user_app05.objects.values_list("name")
print(res.query)
#输出结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wq9uyFDD-1613568064117)(C:\Users\mzy\AppData\Roaming\Typora\typora-user-images\image-20210205224558462.png)]
#方式一:
如上
#方式二:(所有语句都可以查看)
#去配置文件中修改一下
再setting.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',
},
}
}
xx__lt:小于
from django.http import HttpResponse
from app import models
def test1(request):
# ① xx_lt:小于
person_lst = models.App.objects.filter(age__lt=13)
print(person_lst)
return HttpResponse("双下划线方法")
1234567
xx__lte:小于等于
def test1(request):
# ②xx_lte:小于等于
person_lst = models.App.objects.filter(age__lte=13)
print(person_lst)
return HttpResponse("双下划线方法")
12345
xx__gt:大于
def test1(request):
# ③xx_gte:大于
person_lst = models.App.objects.filter(age__gt=13)
print(person_lst)
return HttpResponse("双下划线方法")
12345
xx__gte:大于等于
def test1(request):
# ④xx_gte:大于等于
person_lst = models.App.objects.filter(age__gte=13)
print(person_lst)
return HttpResponse("双下划线方法")
12345
xx__in:包含某些值
def test1(request):
# ⑤xx_in:包含某些值
person_lst = models.App.objects.filter(age__in=[11,12])
print(person_lst)
return HttpResponse("双下划线方法")
123456
exclude和xx__in联合使用:不包含
def test1(request):
# ⑥exclude和xx_in联合使用:不包含
person_lst = models.App.objects.exclude(age__in=[11, 12])
print(person_lst)
return HttpResponse("双下划线方法")
123456
xx__contains():包含某些字符的
def test1(request):
# ⑦xx__contains():包含某些字符的
person_lst = models.App.objects.filter(name__contains='s')
print(person_lst)
return HttpResponse("双下划线方法")
12345
xx__icontains():包含某些字符的(忽略大小写),sqlite3不支持
def test1(request):
# ⑧xx__icontains():包含某些字符的(忽略大小写),sqlite3不支持
person_lst = models.App.objects.filter(name__icontains='s')
print(person_lst)
return HttpResponse("双下划线方法")
12345
xx__range():查找范围
def test1(request):
# ⑨xx_range():查找范围
person_lst = models.App.objects.filter(age__range=[10,15])
print(person_lst)
return HttpResponse("双下划线方法")
12345
xx__startwith:获取以 ‘ ’ 开头的记录
def test1(request):
# ⑩ xx_startwith:获取以‘’开头的记录
person_lst = models.App.objects.filter(age__startwith='z')
print(person_lst)
return HttpResponse("双下划线方法")
12345
xx__endwith:获取以 ‘ ’ 结尾的记录
def test1(request):
# ⑪xx_endwith:获取以‘’结尾的记录
person_lst = models.App.objects.filter(age__endwith='z')
print(person_lst)
return HttpResponse("双下划线方法")
12345
date 可以根据年月日进行过滤
def test1(request):
# ⑫date 可以根据年月日进行过滤
#按照找日来查找
person_lst = models.App.objects.filter(birthday__day=7)
#按照月来查找
person_lst = models.App.objects.filter(birthday__month=7)
#按照年来查找
person_lst = models.App.objects.filter(birthday__year=7)
print(person_lst)
return HttpResponse("双下划线方法")
email=models.EmailField() #本质是varchar(254) 该字段不是给models看的而是给校验型组件看的
phone=models.BigIntField() #电话号码用BigIntField或者直接用CharField
#一对多的外键的增删改查
#增
#1直接写实际字段
#2虚拟子段 对象
一、一对多(外键)
例子:一个作者对应多本书,一本书只有一个作者
model代码:
class Person(models.Model);
name = models.CharField('作者姓名', max_length=10)
age = models.IntegerField('作者年龄')
class Book(models.Model):
person = models.ForeignKey(Person, related_name='person_book')
title = models.CharField('书籍名称', max_length=10)
pubtime = models.DateField('出版时间')
(一) 获取对象方法:
1.从作者出发获取书籍
person = Person.objects.fiter(你的条件)
book = person.book_set.all()
2.从书籍出发获取作者
p = book.person
二、多对多
例子:一个作者对应多本书,一本书有多个作者
model代码:
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField()
class Book(models.Model):
title = models.CharField(max_length=200)
authors = models.ManyToManyField(Author)
(一)获取对象方法:
1.从书籍出发获取作者
b = Book.objects.get(id=50)
b.authors.all() #.authors表示你已经可以操作第三张关系表了
b.authors.filter(first_name='Adam')
2.从作者出发获取书籍
a = Author.objects.get(id=1)
a.book_set.all()
(二)添加对象方法:
a = Author.objects.get(id=1)
b = Book.objects.get(id=50)
b.authors.add(a)
(三)删除对象对象方法:
a = Author.objects.get(id=1)
b = Book.objects.get(id=50)
b.authors.remove(a) 或者 b.authors.filter(id=1).delete()
(四)修改
book_obj.author.set([1,3]) #括号内必须放一个可迭代对象(列表或字典)
#括号内必须传一个可迭代对象 该对象内即可以是数字也可以是对象 并且都支持多个
(五)清空某个书籍和作者的绑定关系
#在第三张关系表中清空某个书籍与作者的绑定关系
book_obj.authors.clear()
#clear括号内不加任何参数
转载于:https://www.cnblogs.com/nyist-xsk/p/9163721.html
#正向
看外键字段在哪里 哪里就是正向
外键字段不在手上 我查你是反向
#一对一和多对多正反向的判断也是如此
子查询:(基于对象的跨表查询)
连表查询:(基于双下划线的跨表查询)
#如果出现了
app01.Author.None
#则可以在orm语句后面加入.all 然后可以查询
#在查询数据时 orm语句应该像查sql语句时 一个一个查
#正向的什么时候加.all()
当你的结果可能有多个时候需要加.all()
如果是一个则直接拿到数据对象
反向查询:
反向查询:一查找多,是反向查找
无外键类的具体对象.有外键的小写类名_set
无外键类是一,有外键是多.
一的具体对象.多的类名小写_set 查到一的具体对象下的所有多的对象、
2 基于双下划线的跨表查询。
基于双下划线的跨表查询也分为正向查询和反向查询。
正向查询
这里面的正向查询表示:查询条件字段或者查询字段在主表中。由从表查主表。
# 查询条件字段在主表中,最终查询字段值还是在从表中。
UserDetail.objects.filter(user__pwd=123).values()
# 查询字段值在主表中,查询条件字段在从表中。
UserDetail.objects.filter(phonenum=110).values(‘user__pwd’)
反向查询
这里的反向查询表示:查询条件字段或者查询字段值在从表中,由主表查从表。
# 查询条件字段在从表中。
UserInfo.objects.filter(uuu__phonenum=110).values()
# 查询字段值在从表中。
UserInfo.objects.filter(username=‘xiao’).values(‘uuu__phonenum’)
注意:在反向查询中,优先级顺序:related_query_name > related_name > 表名
即:当related_query_name和related_name同时出现时,related_query_name或覆盖related_name,你再使用related_name会报错。当related_name出现时,而related_query_name未出现。你必须使用related_name,此时在使用表名的话会报错。
在反向查询时,在没有设置related_name的时候,基于双下划线只需使用表名,而基于对象的查询方式需要使用表名_set
#查询jason的手机号和作者姓名
res=models.Author.objects.filter(name="jason").values("author_detail__phone","name")
res=models.AuthorDwtail.object.filter(author__name="jason")
#这两个res是等价的
#第二个res是查询author表中名字为name
Max,Min,Sum,Count,Avg
#只要是跟数据库相关的模块 基本都在django.db.models里面
#aggregate里面可以加入多个参数
from django.db.models import Max,Min,Sum,Count,Avg
res=models.user_app05.objects.aggregate(Avg("price"),Max("price"))
#这里引用了一个很好的博客
公司员工表
按照部分分组求平均工资:
select dept,AVG(salary) from employee group by dept;1
from django.db.models import Avg
Employee.objects.values("dept").annotate(avg=Avg("salary").values(dept, "avg")
# 另一个案例:每本书的作者人数:
models.Book.objects.all().annotate(author_num=Count("author"))
# 语法 pk字段 == 主键primary key
模型.objects.values('分组字段').annotate(聚合函数)
模型.objects.values('pk').annotate(c=Count('article__title')).values('title','c')1234567891011
select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;1
from django.db.models import Avg
models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg"
用法:
Q(条件)
例如
Q(id__gt=12)
代表,id大于12的条件
Q对象通常会 与另一个Q对象进行比较,使用逻辑运算符来连接
1234567
用于查询条件之间的逻辑关系
not and or
可以对Q对象进行与或非的操作
&
|
~
123
使用前需要先导入
》与
》或
》非
模型类.objects.exclude(id=3)
用法:
F(字段)
1
用于模型类对象属性之间的比较
》使用前要先导入
》
查阅读量大于30
bread__gt=30
》
事务:
ACID
原子性
不可分割的最小单位
一致性
跟原子性是相辅相成
隔离性
事务之间互相不干扰
持久性
事务一旦确定永久有效
事务的回滚
rollback
事务的确认
commit
from django.db.models import Max,Min,Sum,Count,Avg
res=models.user_app05.objects.aggregate(Avg("age"))
print(res)
#事务
from django.db import transaction
try:
with transaction.atomic():
#sql1
#sql2
#在with代码块内书写的所有的orm操作都是属于同一个事务
pass
except Exception as e:
print(e)
print("执行其他操作")
int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。
一个整数类型,范围在 -2147483648 to 2147483647。
字符类型,必须提供max_length参数, max_length表示字符长度。
日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例。
日期时间字段,格式 YYYY-MM-DD HH:MM:ss,相当于Python中的datetime.datetime()实例
AutoField(Field)
- int自增列,必须填入参数 primary_key=True
BigAutoField(AutoField)
- bigint自增列,必须填入参数 primary_key=True
注:当model中如果没有自增列,则自动会创建一个列名为id的列
from django.db import models
class UserInfo(models.Model):
# 自动创建一个列名为id的且为自增的整数列
username = models.CharField(max_length=32)
class Group(models.Model):
# 自定义自增列
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
SmallIntegerField(IntegerField):
- 小整数 -32768 ~ 32767
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正小整数 0 ~ 32767
IntegerField(Field)
- 整数列(有符号的) -2147483648 ~ 2147483647
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正整数 0 ~ 2147483647
BigIntegerField(IntegerField):
- 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
BooleanField(Field)
- 布尔值类型
- 会存成一或者零
NullBooleanField(Field):
- 可以为空的布尔值
CharField(Field)
- 字符类型
- 必须提供max_length参数, max_length表示字符长度
-verbose_name 字段的注释
TextField(Field)
- 文本类型
- 该字段可以存大段文本(没有字数限制)
EmailField(CharField):
- 字符串类型,Django Admin以及ModelForm中提供验证机制
-等价于varchar(254)
IPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
GenericIPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
- 参数:
protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"
URLField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证 URL
SlugField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
CommaSeparatedIntegerField(CharField)
- 字符串类型,格式必须为逗号分割的数字
UUIDField(Field)
- 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
FilePathField(Field)
- 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
- 参数:
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
FileField(Field)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "/data"
#上传文件的保存路径 给该字段传一个文件对象,会自动将文件保存在/data目录下然后将文件路径保存在数据库里
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
ImageField(FileField)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
width_field=None, 上传图片的高度保存的数据库字段名(字符串)
height_field=None 上传图片的宽度保存的数据库字段名(字符串)
DateTimeField(DateField)
- 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
-auto_now:每次修改数据都会自动更新当前时间
-auto_now_add:只在创建数据的时候记录创建时间后不会自动修改
DateField(DateTimeCheckMixin, Field)
- 日期格式 YYYY-MM-DD
TimeField(DateTimeCheckMixin, Field)
- 时间格式 HH:MM[:ss[.uuuuuu]]
DurationField(Field)
- 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
FloatField(Field)
- 浮点型
DecimalField(Field)
- 10进制小数
- 参数:
max_digits,小数总长度
decimal_places,小数位长度
BinaryField(Field)
- 二进制类型
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
对应关系:
'AutoField': 'integer AUTO_INCREMENT',
'BigAutoField': 'bigint AUTO_INCREMENT',
'BinaryField': 'longblob',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'bigint',
'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision',
'IntegerField': 'integer',
'BigIntegerField': 'bigint',
'IPAddressField': 'char(15)',
'GenericIPAddressField': 'char(39)',
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PositiveIntegerField': 'integer UNSIGNED',
'PositiveSmallIntegerField': 'smallint UNSIGNED',
'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'longtext',
'TimeField': 'time',
'UUIDField': 'char(32)',
123456789101112131415161718192021222324252627
用于表示某个字段可以为空。
如果设置为unique=True 则该字段在此表中必须是唯一的 。
如果db_index=True 则代表着为此字段设置索引。
为该字段设置默认值。
配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
配置上auto_now=True,每次更新数据记录的时候会更新该字段。
了解
null 数据库中字段是否可以为空
db_column 数据库中字段的列名
db_tablespace
default 数据库中字段的默认值
primary_key 数据库中字段是否为主键
db_index 数据库中字段是否可以建立索引
unique 数据库中字段是否可以建立唯一索引
unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引
unique_for_month 数据库中字段【月】部分是否可以建立唯一索引
unique_for_year 数据库中字段【年】部分是否可以建立唯一索引
verbose_name Admin中显示的字段名称
blank Admin中是否允许用户输入为空
editable Admin中是否可以编辑
help_text Admin中该字段的提示信息
choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)
error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息;
字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
如:{'null': "不能为空.", 'invalid': '格式错误'}
validators 自定义错误验证(列表类型),从而定制想要的验证规则
from django.core.validators import RegexValidator
from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
如:
test = models.CharField(
max_length=32,
error_messages={
'c1': '优先错信息1',
'c2': '优先错信息2',
'c3': '优先错信息3',
},
validators=[
RegexValidator(regex='root_\d+', message='错误了', code='c1'),
RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
EmailValidator(message='又错误了', code='c3'), ]
)
1234567891011121314151617181920212223242526272829303132333435363738394041
外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多’中’多’的一方。ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。
to:设置要关联的表
to_field:设置要关联的表的字段
related_name:反向操作时,使用的字段名,用于代替原反向查询时的'表名_set'。但不建议使用
related_query_name:反向查询操作时,使用的连接前缀,用于替换表名。
on_delete:当删除关联表中的数据时,当前表与其关联的行的行为。
models.CASCADE
删除关联数据,与之关联也删除
models.DO_NOTHING
删除关联数据,引发错误IntegrityError
models.PROTECT
删除关联数据,引发错误ProtectedError
models.SET_NULL
删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
models.SET_DEFAULT
删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
models.SET
删除关联数据,
a. 与之关联的值设置为指定值,设置:models.SET(值)
b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
db_constraint:是否在数据库中创建外键约束,默认为True。可以设置为False。
1234567891011121314151617181920212223242526272829303132
一对一字段。通常一对一字段用来扩展已有字段。一对一的关联关系多用在当一张表的不同字段查询频次差距过大的情况下,将本可以存储在一张表的字段拆开放置在两张表中,然后将两张表建立一对一的关联关系。
to:设置要关联的表
to_field:设置要关联的表的字段
on_delete:同ForeignKey字段。
12345
to:设置要关联的表
to_field:设置要关联的表的字段
related_query_name:反向查询操作时,使用的连接前缀,用于替换表名。
symmetrical:仅用于多对多自关联时,指定内部是否创建反向操作的字段。默认为True。
through:设置关联的字段。
through_fields:设置关联的字段。
db_table:默认创建第三张表时,数据库中表的名称。
12345678910111213
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name="书名")
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name="作者姓名")
# 自己创建第三张表,分别通过外键关联书和作者
class Author2Book(models.Model):
author = models.ForeignKey(to="Author")
book = models.ForeignKey(to="Book")
class Meta:
unique_together = ("author", "book")
123456789101112131415
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name="书名")
# 通过ORM自带的ManyToManyField自动创建第三张表
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name="作者姓名")
books = models.ManyToManyField(to="Book", related_name="authors")
12345678
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name="书名")
# 自己创建第三张表,并通过ManyToManyField指定关联
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name="作者姓名")
books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book"))
# through_fields接受一个2元组('field1','field2'):
# 其中field1是定义ManyToManyField的模型外键的名(author),field2是关联目标模型(book)的外键名。
class Author2Book(models.Model):
author = models.ForeignKey(to="Author")
book = models.ForeignKey(to="Book")
class Meta:
unique_together = ("author", "book")
123456789101112131415161718
注意:
当我们需要在第三张关系表中存储额外的字段时,就要使用第三种方式。
但是当我们使用第三种方式创建多对多关联关系时,就无法使用set、add、remove、clear方法来管理多对多的关系了,需要通过第三张表的model来管理多对多关系。
ORM对应的类里面包含另一个Meta类,而Meta类封装了一些数据库的信息。主要字段如下:
ORM在数据库中的表名默认是 app_**类名,可以通过**db_table可以重写表名。
联合索引。
联合唯一索引。
指定默认按什么字段排序。
只有设置了该属性,我们查询到的结果才可以被reverse()。
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
class Meta:
# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = "table_name"
# 联合索引
index_together = [
("pub_date", "deadline"),
]
# 联合唯一索引
unique_together = (("driver", "restaurant"),)
ordering = ('name',)
# admin中显示的表名称
verbose_name='哈哈'
# verbose_name加s
verbose_name_plural=verbose_name
only和defer
only是只拿某一个字段的所有值,而defer是拿出除了某一个字段之外的所有值
select_related与prefetch_related
select_related内部直接将book与publish表连在一起 然后一次性将大表里面的所有数据全部封装给查询出来的对象 这时候无论点book还是点publish的数据都无需走数据库查询
##selcet_related只能放外键字段 一对一关系 和 一对多关系
##多对多不行
prefetch_related内部其实是子查询 将子查询查询出来的所有结果封装到对象中
orm语句特点:
惰性查询
如果你只是仅仅只是书写了orm语句 在后面根本没有用到该语句所查询出来的参数
那么orm会自动识别 直接不执行
res=models.user_app05.objects.only("register_time") #只拿register_time这一个字段的所有值
res=models.user_app05.objects.all() #拿出表中的所有值(较慢)
res=models.user_app05.objects.defer("register_time")
for i in res:
print(res.register_time)
print(res.name) #这一步会重新走数据库
略
针对一个可以列举完全的可能性字段,我们如何储存
gender_choices=(
(1,"male"),
(2,"female"),
)
gender=models.InterField(choices=gender_choices)
##该gender字段存的还是数字 但是如果存的数字在上面元组列举的范围之内
##那么可以非常轻松的获取到数字对应的真正内容
1.gender字段存的数字不在上述元组的列举范围内容
2.如果在 如何获取对应的中文信息
user_obj=models.user.objects.filter(pk=1).first() #获取主键值等于一的这一对象
#只要是choices参数的字段 如果想要获得对应信息 固定写法 get_字段名_display()
#如果没有对应关系会返回对应关系值
user_obj.get_gender_display()
#MTV:DJANO号称是HTV模型
M:models
T:templates
v:views
#HTV:其实django本质也是HVC
H:models
V:views
C:controller
#vue框架:HVVM框架
这里引用了一个博客
Django ORM多对多的三种模式
使用默认的ManyToManyField创建第三张表、
自己创建第三张关系表
3.自己创建第三张表,在ManyToManyField中通过through和through_fields指定表名和字段
books=models.ManyToManyField(to="book",
through="BOOK2AUTHOR", #表名
through_fields=("author","book") #关联字段
)
#半自动:可以使用orm的正反向查询 但无法使用add,set,remove,clear这四个方法
回到顶部
Django ORM多对多的三种模式
复制代码
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=32)
def __str__(self):
return self.title
12
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name=“作者姓名”)
books = models.ManyToManyField(to=‘Book’)
def __str__(self):
return self.name
12
复制代码
复制代码
#!/usr/bin/env python
import os
if name == ‘main’:
os.environ.setdefault(“DJANGO_SETTINGS_MODULE”, “manytomany_test.settings”)
import django
django.setup()
from app01 import models
author_obj = models.Author.objects.get(id=1)
ret = author_obj.books.all()
print(ret)
# from app02 import models
#
# author_obj = models.Author.objects.get(id=1)
# ret = author_obj.author2book_set.all().values_list("book__title")
# print(ret)
# from app03 import models
#
# author_obj = models.Author.objects.get(id=1)
# ret = author_obj.books.all()
# print(ret)
# 删除第一个作者关联的所有书籍,可以直接操作第三张关系表
# models.Author2Book.objects.filter(author=author_obj).delete()
12345678910111213141516171819
复制代码
\2. 自己创建第三张关系表
复制代码
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name=“书名”)
def __str__(self):
return self.title
12
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name=“作者姓名”)
def __str__(self):
return self.name
12
class Author2Book(models.Model):
book = models.ForeignKey(to=‘Book’)
author = models.ForeignKey(to=‘Author’)
class Meta:
unique_together = (('book', 'author'), )
12
复制代码
复制代码
#!/usr/bin/env python
import os
if name == ‘main’:
os.environ.setdefault(“DJANGO_SETTINGS_MODULE”, “manytomany_test.settings”)
import django
django.setup()
# from app01 import models
#
# author_obj = models.Author.objects.get(id=1)
# ret = author_obj.books.all()
# print(ret)
from app02 import models
author_obj = models.Author.objects.get(id=1)
ret = author_obj.author2book_set.all().values_list("book__title") # 先是外键反向查询, 在是外键正向查询
print(ret)
# from app03 import models
#
# author_obj = models.Author.objects.get(id=1)
# ret = author_obj.books.all()
# print(ret)
# 删除第一个作者关联的所有书籍,可以直接操作第三张关系表
# models.Author2Book.objects.filter(author=author_obj).delete()
12345678910111213141516171819
复制代码
3.自己创建第三张表,在ManyToManyField中通过through和through_fields指定表名和字段
复制代码
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name=“书名”)
def __str__(self):
return self.title
12
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name=“作者姓名”)
books = models.ManyToManyField(
to=‘Book’,
through=‘Author2Book’,
through_fields=(‘author’, ‘book’) # 这里是有顺序的,在那个表种写关联,那个字段就要写的前面
)
def __str__(self):
return self.name
12
class Author2Book(models.Model):
book = models.ForeignKey(to=‘Book’)
author = models.ForeignKey(to=‘Author’)
class Meta:
unique_together = (('book', 'author'),)
12
复制代码
复制代码
#!/usr/bin/env python
import os
if name == ‘main’:
os.environ.setdefault(“DJANGO_SETTINGS_MODULE”, “manytomany_test.settings”)
import django
django.setup()
# from app01 import models
#
# author_obj = models.Author.objects.get(id=1)
# ret = author_obj.books.all()
# print(ret)
# from app02 import models
#
# author_obj = models.Author.objects.get(id=1)
# ret = author_obj.author2book_set.all().values_list("book__title") # 先是外键反向查询, 在是外键正向查询
# print(ret)
from app03 import models
author_obj = models.Author.objects.get(id=1)
ret = author_obj.books.all() # 只可使用多对多关系种的all()方法
print(ret)
# 删除第一个作者关联的所有书籍,可以直接操作第三张关系表
models.Author2Book.objects.filter(author=author_obj).delete()
1234567891011121314151617181920
异步提交
局部更新
例子:github注册
动态获取用户名实时的跟后端确认并且实时展示到前端(局部刷新)
朝前端发送请求的方式:
1·浏览器地址栏直接输入url回车 GET请求
2·a标签的href属性 GET请求
3·form表单 GET请求/POST请求
4·ajax GET请求/POST请求
一个很好的博客
AJAX 不是新的编程语言 而是一种使用现有标准的新方法(比较装饰器)
AJAX 最大的有点式在不重新加载整个页面的情况下,可以与服务器交换数据并且更新部分网页内容。
AJAX我们只学习jQuery封装之后的版本(不学原装的 原生的复杂并且在实际项目中也一般不用)
ps:jQury只是实现ajax的一个框架 其他框架也可以
小例子:
一个ajax例子:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
{# //导入jquery模块(注意这个一定要导入) #}
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js">script>
head>
<body>
<input type="text" id="d1">+
<input type="text" id="d2">=
<input type="text" id="d3">
<p>
<button id="btn">点我button>
p>
<script>
//给按钮绑定点击事件
$('#btn').click(function () {
//绑定后发送ajax请求
$.ajax({
//1·指定朝那个后端发送ajax请求
url:"", //不写向当前地址提交
//2.请求方法
type:"post", //不指定默认就是get
//3.数据
{#拿到第一个和第二个i1和i2的值#}
data:{"i1":$('#d1').val(),"i2":$("#d2").val()},
dataType:true, //会字动帮你反序列化
//或者在后端用jsonresponse会回调函数会字动反序列化十分方便
//4.回调函数:当后端返回结果的时候会自动触发 args接收后端的返回结果
success:function (args) {
{#alert(args)#}
{#通过DOM操作动态渲染到第三个input里面#}
$("#d3").val(args)
Console.log(typeof args)
{# json.parse(args) 把字符串转换为字典 然后再用点操作获取值 #}
}
})
})
script>
body>
html>
后端:
from django.shortcuts import render,HttpResponse
import json
from django.http import JsonResponse
# Create your views here
def ab_ajax(request):
if request.method=="POST":
i1=request.POST.get("i1")
i2=request.POST.get("i2")
print(request.POST)
i3=int(i1)+int(i2)
print(i3)
#这里返回字典
d={"code":100,"msg":i3}
#return HttpResponse(json.dumps(d))
#jsonresponse可以直接在前端序列化
return JsonResponse(d)
return render(request,"index_ajax.html")
##django差个结尾,但觉得还有好多东西没学看来以后永远是一个咸鱼了QAQ##