Django web开发资料
一、基础概念
1、C/S(client/server)、B/S(browser/server)
client ------- request -----> server
browser <-------response ----- server
client(客户端,比如QQ,微信)/browser(浏览器,比如IE,chrome)向server(服务器)发起request请求,server服务器response响应。
2、URL (Uniform Resource Locator)
统一资源定位符
https://www.baidu.com/default.html
Scheme(协议): https http ftp file
domain(主体): www.baidu.com
path(路径): /default.html
URL的长度没有限定,最大长度与用户的浏览器有关,同时和服务器能够处理的最大长度URL有关。
3、请求报文:
请求行为前三行:(method path version )
例如:GET /default.html HTTP/1.1
图中:GET /HTTP/1.1
请求方法:GET ,请求路径:/,请求状态码:1.1
l Accept:请求的对象类型。如果是“/”表示任意类型,如果是指定的类型,则会变成“type/”。
l Accept-Language:使用的语言种类。
l Accept-Encording:页面编码种类。
l Accept-Charset:页面字符集。
l User-Agent:用户代理,提供了客户端浏览器的类型和版本。
l Host:连接的目标主机,如果连接的服务器是非标准端口,在这里会出现使用的非标准端口。
l Connection:对于HTTP连接的处理,keep-alive表示保持连接,如果是在响应报文中发送页面完毕就会关闭连接,状态变为close。
Cookie: session会话机制,在客户端记录信息确定用户身份
Content-Type:text/dict 内容类
比如:字典{“key”:value,”name”:’zhangsn’},图片,文本
请求方法补充:
GET:获取资源
POST:更新资源
DELETE:删除资源
PUT:创建资源
HEAD:获取资源的信息,但是不需要把资源返回
OPTION:对资源有哪些操作方法
4、响应报文:
当收到get或post等方法发来的请求后,服务器就要对报文进行响应。告诉客户端,服务器对客户端的请求做出的处理结果。
前两行称为状态行,状态行给出了服务器的http版本,以及一个响应代码。响应代码是服务器根据请求进行查找后得到的结果的一种反馈,共有5大类,分别以1、2、3、4、5开头。
1**表示接收到请求,继续进程,在发送post后可以收到该应答。
2**表示请求的操作成功,在发送get后返回。
3**表示重发,为了完成操作必须进一步动作。
4**表示客户端出现错误。
5**表示服务器出现错误。
其余部分称为应答实体。其中的server表示服务器软件版本,date标注了当前服务器的时间,connection标明连接关闭,cookie是在发送请求时将cookie放在请求首部中发送给服务器,服务器收到cookie后查找自己已有的cookie信息,确定客户端的身份,然后返回相应的页面,cookie的方便之处在于可以保持一种已登录的状态,例如:我们注册一个论坛,每次访问都需要进行填写用户名和密码然后登录。而使用了cookie后,如果cookie没有到达过期时间,那么我们只需在第一次登录时填写信息然后登录,以后的访问就可以省略这一步骤。
响应状态码补充:
5、请求,响应流程
6、模板(template)
tag : {% %}
var : {{ var }}
- {% for post in posts %} something … {% endfor %}
- {% if error %} {{ error }}
{% else %} ssssssss
{% end if %} - {% load static %}
{% load staticfiles %} #Djang2.0 废弃 - {% static “css path” %}
- {% url “name” %} # name urls.py url(re, veiw, name)
- {% block blockname %}
- {% extends “sometemplate.html” %}
- {% include “footer.html” %}
模板是可以继承的- 基模板中导入统一资源(Bootstrap,jQuery)
不同的区域可以挖坑(开启一个block),让子模板进行填坑
常用标签 - extends 继承
- block 块(坑),挖坑(填坑)
- 里面有内容就是填坑
- 没有内容就是挖坑
- 父模板挖的坑,子模板可以根据需求去实现
- 子模板可以在任意位置继续挖坑
- 挖坑可以嵌套
- include 包含
- 解耦,拆分
- 让代码更容易维护
- 基模板中导入统一资源(Bootstrap,jQuery)
7、反向解析
- reverse()
reverse(‘home’)
HttpResponse
HttpResponse 返回普通的页面,没有用到模板
render render(request,template,{})
JsonResponse 前后端分离 HTML5 Server 提供 API (json)
1.请求对象Request
- Request是Django为我们封装
- 包含字段
- path
- method
- POST
- GET
- FILES
- session
- COOKIES
- GET,POST是请求数据的封装,数据结构是类字典结构,key是可以重复的
2.响应对象Response
在处理一个Request时,我们可以使用重定向交给别的View去处理,也可以直接处理,处理完毕把处理
后的结果封装到Response对象中,并return Response对象。
3.参数
- 形参,我们声明时的参数
- 实参,我们在调用时的参数
- 可变参,*args (Arguments),元组或列表 (arg1,arg2)
- 关键字参数**kwargs,字典(key=value)
4.视图函数中的参数
- 位置参数,对应python中的不定长参数
- 根据位置去匹配的,在函数中的第几个参数就对应url中第几个括号
- 关键字参数,使用 ?P
8、静态资源配置
‘/static/’
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'common_static'),
]
hello_world_project/common_static/css/mycss.css
hello_world_project/templates/home.html
{% load static %}
{% static ‘css/mycss.css’ %}
9、会话技术及其应用
1.为什么需要会话技术?
- 登录: 登录QQ空间, 保存登录状态,
- 使用会话技术: cookie session
def 登录验证(request):
# 1. 从request中获取用户名、密码;
# 2. 调用User模型去数据库验证用户名、密码;
# 3. 输出验证结果
如果成功, 重定向到 成功后的页面;
如果失败, 提示用户名或密码错误;
2.关于会话(session)
多次会话?
Web中的会话可简单理解为:用户开一个浏览器,访问某一个Web站点,在这个站点点击多个超链接,访问服务器多个Web资源,然后关闭浏览器,整个过程称之为一个会话。
会话(session)是一个客户与服务器之间的不中断的请求响应序列。对客户的每个请求,服务器能够识别出请求来自于同一个客户。当一个未知的客户向Web应用程序发送第一个请求时就开始了一个会话。当客户明确结束会话或服务器在一个预定义的时限内不从客户接受任何请求时,会话就结束了。当会话结束后,服务器就忘记了客户以及客户的请求。
客户向Web应用服务器发送的首次请求可能不是客户与服务器的第一次交互。首次请求指的是需要创建会话的请求。我们称之为首次请求是因为该请求是对多个请求计数的开始(逻辑上),也是服务器开始记住客户的请求。例如,当用户登录或向购物车中添加一件商品时,就必须开始一个会话。
多次会话怎么办?答案是靠“会话追踪”
3.关于会话追踪
服务器靠会话追踪区别不同的用户
用户 A ,购物车
用户 B, 购物车
Cookie
客户端可以设置Cookie发送给服务器
Cookie是key:value格式,每一个客户端可以自定义key:value,服务器不好管理客户端上传的Cookie,服务器要求客户端保存一些Cookie方便管理。
服务器告诉客户端,必须存储一个sesssionid的cookie,并且值必须是服务器给出的。所以浏览器里面有一个sessionid的cookie通过response.set_cookie来告诉客户端保存服务器给出的cookie。这样每次客户端,把sessionid这个cookie发送给服务器,服务器就知道是哪一客户端了。
服务器把每一个客户端信息保存在数据库当中,数据库三个字段,
session_key:保存的是sessionid对应的值
session_data:保存的数据信息
expire_date:表示这条记录什么时候过期
django读取session的过程:
读取客户端请求中的Cookie—->取出sessionid—>从数据库中查询出session数据—>解码成一个字典
特性:
- 默认情况系,浏览器关闭后,cookie自动被删除
- cookie有生命周期
- max-age=0 关闭,就清除掉cookie
- max-age=None 永久有效
- max-age=整数 标识多少秒之后过期
- expires datetime对象,标识到具体的时间过期
4.会话跟踪
会话跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份
。django把session会话信息,保存在数据库中,并且使用了base64编码来做简单的加密。
5.cookie机制
在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。例如,用户A在超市购买的任何商品都应该放在A的购物车内,不论是用户A什么时间购买的,这都是属于同一个会话的,不能放入用户B或用户C的购物车内,这不属于同一个会话。
而Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。即用户A购买了一件商品放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户A的会话还是用户B的会话了。要跟踪该会话,必须引入一种机制——cookie机制。
Cookie是一种在远程浏览器端存储数据并以此来跟踪和识别用户的机制。它可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。
6.Cookie是不可跨域的
很多网站都会使用Cookie。例如,Google会向客户端颁发Cookie,Baidu也会向客户端颁发Cookie。那浏览器访问Google会不会也携带上Baidu颁发的Cookie呢?或者Google能不能修改Baidu颁发的Cookie呢?
答案是否定的。Cookie具有不可跨域名性。根据Cookie规范,浏览器访问Google只会携带Google的Cookie,而不会携带Baidu的Cookie。Google也只能操作Google的Cookie,而不能操作Baidu的Cookie。
Cookie在客户端是由浏览器来管理的。浏览器能够保证Google只会操作Google的Cookie而不会操作Baidu的Cookie,从而保证用户的隐私安全。浏览器判断一个网站是否能操作另一个网站Cookie的依据是域名。Google与Baidu的域名不一样,因此Google不能操作Baidu的Cookie。
7.Cookie是什么
Cookie意为“甜饼”,是由W3C组织提出,最早由Netscape社区发展的一种机制。目前Cookie已经成为标准,所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。
由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。
Cookie实际上是Web服务器暂时存储在用户硬盘上的一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
8.火狐浏览器的Cookie存在哪里
- 页面信息–> 安全 -->查看cookie
- /home/gavin/.mozilla/firefox/bigiywh0.default/cookies.sqlite
10、用户
-
用户注册
- 用户名 用户密码, 昵称 存到数据库 user表
-
登录
- 用户名 用户密码 login.html, 验证提交的用户名、密码 user表
-
用户信息
- 用户ID, 用户相关的数据
-
Django中怎么做登录验证(会话追踪的应用)
uer表 ----- Use
home.html # /home/所有人都能看到
detail.html # /detail/ 登录后才能看到
login.html # /login/ 进入login.html
注册码:限制用户注册
明文密码的缺陷:
不安全,数据库用户信息被盗的话,可以直接使用用户名+密码登录
加密:
使用简单的MD5在加上自定义的字符串来加密
md5((pwd+’askdjjflksjfdksf’).encode()).hexdigest()
注册:客户端—>明文密码——>服务器加密——>保存加密后的数据
登录:客户端—>明文密码——>计算加密后的密码——>匹配数据库加密数据
Django自带User注册登录
from django.contrib.auth.models import User
user = User.objects.create_user('john','lennon@thebeatles.com', 'johnpassword')
user.save()
登录
from django.contrib.auth import authenticate, login,logout
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username,
password=password)
if user is not None:
login(request, user)
# Redirect to a success page.
return HttpResponse(‘登录成功')
else:
# Return an 'invalid login' error message.
return HttpResponse(‘⽤户名或密码错误’)
def logout(request):
logout(request)
return HttpReponse(‘退出成功’)
二、Django是什么
django介绍: https://www.djangoproject.com/
Web开发通常使用MVC模式,MVC是一种思想,可以有各种各样的落地实现
MVC是什么:
model:封装数据的操作
view:视图,用于展示数据
controller:处理用户的请求,并且控制视图的展示
django使用的是MTV(MVT)模式,MVC的一种形式
model:封装数据的操作
template:视图,用于展示数据
views:处理用户的请求,并控制模板的展示
通常开发不用Template,视图一般通过接口数据展示,例如json格式,xml格式,即所谓的API接口。
三、配置并创建Django项目
1、VScode 安装
https://code.visualstudio.com/下载 tar.gz版本
解压出来,双击code 打开
安装扩展包python
可能出现的问题code软件没有执行权限,无法启动,通过chmod 来修改
2、创建Django应用步骤
- django-admin startproject 创建项目
- 新建app ./manage.py startapp app_name
- 在settings中INSTALLED_APPS添加新建的app_name
- 创建view
- 绑定url
- 创建files目录
- 绑定资源files路由以及处理函数
启动web服务器./manage.py runserver
3、创建虚拟环境
-
安装virtualenv并启用
sudo pip3 install virtualenv
#安装虚拟环境创建工具virtualenv testenv # 创建文件testenv,是一个文件夹,如果存在不会继续创建 #或者virtualenv -p python3 djangoenv,创建一个py3的 djangoenv source testenv/bin/activate # 启动虚拟环境,进入bin目录后直接activate一样能够启动 sudo pip install virtualenv sudo pip install virtualenvwrapper mkdir .virtualenvs #普通用户提升sudo权限,否则会报错 sudo vim .bashrc #文件末尾添加 export WORKON_HOME=$HOME/.virtualenvs source /usr/local/bin/virtualenvwrapper.sh source .bashrc # 软连接 /uer/bin目录下删除Python文件, ln -s python3.6 python (会报错,因为ubuntu自带Python2.7,,版本冲突) ls -all | grep python 查看软连接是否成功 mkvirtualenv py3 #创建py3虚拟环境,并进入 deactivate #退出 rmvirtualenv py3 #删除Python虚拟环境 workon py3 #进入 #所有的虚拟环境,都位于/home/.virtualenvs目录下,,,带点的是隐藏目录 sudo apt install virtualenv virtualenv -p python3 djangoenv source djangoenv/ pip list ls #查看是否安装成功 source djangoenv/bin/activate #进入 deactivate #退出
-
在虚拟环境中安装pymysql和django
pip install pymysql # 安装pymysql
pip install django==1.11 # 安装django(后面接版本)12345 -
新建文件夹test存储项目,进入test文件下,创建工程和app
sudo mkdir test
cd test
切换到绝对路径目录cd C:\Users\admin\Desktop\DjangoProject\project
注:所有路径不要有中文#创建,并进入文件夹 django-admin startproject axf # 新建名为axf的工程 python manage.py startapp app # 新建名为app的应用
-
使用pycharm打开项目文件,配置setting文件:
LANGUAGE_CODE = ‘zh-hans’ #设置中文
TIME_ZONE = ‘Asia/Shanghai’ # 设置时区
INSTALLED_APPS:‘app’ -
配置数据库
Django默认使用SQLite数据库
在settings.py文件中通过DATABASES选项进行数据库配置
配置MySQL ,Python3.x中安装的是PyMySQL
1,在__init__.py文件中写入两行代码:
import pymysql
pymysql.install_as_MySQLdb()
2,配置setting:
以数据库sunck为例进行示范:对settingspy中的DATABASES进行设置
DATABASES = {
‘default’: {
‘ENGINE’: ‘django.db.backends.mysql’,
‘NAME’: “sunck”,
‘USER’: “root”,
‘PASSWORD’: “admin123”,
‘HOST’: “localhost”,
‘PORT’: “3306”
}
} -
pycharm中配置
- 在pycharm中引入虚拟环境
file——settings——Project:helloworld——interpreter
Add Local——Existing environment - 设置debug
Run——Debug——’+’——Python——runserver 8080
4、创建Django项目
-
目录层刨析
project ----项目目录
–app ----应用目录
–middleware ----中间件文件夹
–migrations ----执行数据迁移后生成
admin.py 进行站点配置
models.py 创建模型
views.py 创建视图
urls.py 应用的具体路由
–static ----静态文件目录
–css ----CSS样式文件夹
–fonts ----字体设置文件夹
–img ----图片文件夹
–js ----js文件存放文件夹
–templates ----模板文件夹,存放html文件
init.py 一个空文件,它告诉Python这个目录应该被看做一个包
settings.py 项目的配置文件(主要处理文件)
urls.py 项目的url声明 (主要处理文件,跟路由)
manage.py 一个命令行工具,可以让我们用多种方式对Django项目进行交互
wsgi.py 项目与WSGI兼容的Web服务器入口 -
创建父类模型,models.py
class Main(models.Model):
img = models.CharField(max_length=200) # 图片
name = models.CharField(max_length=100) # 名称
trackid = models.CharField(max_length=16) # 通用idclass Meta: # 成为父类(抽象化) abstract = True12345678
-
创建轮播图、导航栏、必购栏、商店模型,models.py
class MainWheel(Main): # 轮播图
class Meta:
db_table = ‘axf_wheel’class MianDao(Main): # 导航 class Meta: class MainMustBuy(Main): # 必购 class Meta: db_table = 'axf_mustbuy' class MainShop(Main): # 商店 class Meta: db_table = 'axf_shop'1234567891011121314
-
创建商品展示、用户、ticket、购物车、订单、订单与商品关系模型,models.py
class Goods(models.Model): # 商品展示
productid = models.CharField(max_length=16) # 商品id
productimg = models.CharField(max_length=200) # 商品图片
productname = models.CharField(max_length=100) # 商品名称
productlongname = models.CharField(max_length=200) # 商品规格
isxf = models.IntegerField(default=1)
pmdesc = models.CharField(max_length=100)
specifics = models.CharField(max_length=100) # 规格
price = models.IntegerField(default=0) # 打折价格
marketprice = models.FloatField(default=1) # 原价
categoryid = models.CharField(max_length=16) # 分类id
childcid = models.CharField(max_length=16) # 子分类id
childcidname = models.CharField(max_length=100) # 名称
dealerid = models.CharField(max_length=16)
storenums = models.IntegerField(default=1) # 排序
productnum = models.IntegerField(default=1) # 销量排序class Meta: db_table = 'axf_goods' 1234567891011121314151617181920 class UserModel(models.Model): # 用户 username = models.CharField(max_length=32, unique=True) # 用户名 password = models.CharField(max_length=256) # 密码 email = models.CharField(max_length=64, unique=True) # 邮箱 sex = models.BooleanField(default=False) # 性别 False代表女 icon = models.ImageField(upload_to='icon') # 头像 is_delete = models.BooleanField(default=False) # 是否删除 class Meta: db_table = 'axf_users' 1234567891011 class UserTicketModel(models.Model): # 创建ticket表 user = models.ForeignKey(UserModel) ticket = models.CharField(max_length=256) out_time = models.DateTimeField() class Meta: db_table = 'axf_user_ticket'1234567 class CartModel(models.Model): # 购物车 user = models.ForeignKey(UserModel) # 关联用户 goods = models.ForeignKey(Goods) # 关联商品 c_num = models.IntegerField(default=1) # 商品个数 is_select = models.BooleanField(default=True) # 是否选择 class Meta: db_table = 'axf_cart'12345678 class OrderModel(models.Model): # 订单 user = models.ForeignKey(UserModel) # 关联用户 o_num = models.CharField(max_length=64) # 数量 # 0 代表已下单未付款; 1 代表已付款未发货; 2 代表已付款已发货 o_status = models.IntegerField(default=0) # o_create = models.DateTimeField(auto_now_add=True) # 创建时间 class Meta: db_table = 'axf_order'1234567891011 class OrderGoodsModel(models.Model): # 订单和商品的联系 goods = models.ForeignKey(Goods) # 关联商品 order = models.ForeignKey(OrderModel) # 关联订单 goods_num = models.IntegerField(default=1) # 商品个数 class Meta: db_table = 'axf_order_goods'1234567
-
迁移文件,数据库生成表
python manage.py makemigrations
在migrations目录下生成一个迁移文件,此时数据库中还没有生成数据表python manage.py migrate12 相当于执行MySQL语句创建了数据表
-
插入数据
打开Navcat,使用sql语句插入表数据。 -
激活应用
在settings.py文件中,将myApp应用加入到INSTALLED_APPS选项中
INSTALLED_APPS = [
‘django.contrib.admin’,
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.messages’,
‘django.contrib.staticfiles’,
‘myApp’, ----我的应用
]
] -
视图设置,app/views.py
概述:
在Django中,视图是对web请求进行的回应,视图就是一个python函数,在views.py文件中定义。
from django.shortcuts import render
# Create your views here.
from django.http import HttpResponse
def index(request):
return HttpResponse(“Sunck is a good man”)
配置url: -
路由配置
方法一(path方法):
修改project目录下的urls.py文件:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path(‘admin/’, admin.site.urls),
path(’’, include(‘myApp.urls’)),
]
在myApp应用目录下创建urls.py文件:
from django.urls import path, include
from . import views
urlpatterns = [
path(’’,views.index),
]
推荐方法二(url方法):
修改project目录下的urls.py文件:
from django.contrib import admin
from django.conf.urls import url,include
urlpatterns = [
url(r’^admin/’, admin.site.urls),
url(r’^’, include(‘myApp.urls’)),
]
在myApp应用目录下创建urls.py文件:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r’^$’, views.index),
] -
模板基本使用
概述:模板是HTML页面,可以根据视图中传递过来的数据进行填充
创建模板:
创建与app同级的templates目录,在目录下创建对应项目的模板目录(多个应用的情况下)与文件配置模板路径: 修改settings.py文件下的TEMPLATE的'DIRS' 'DIRS': [os.path.join(BASE_DIR, 'templates')], 定义grades.html与students.html模板: 在templates\myApp\目录下创建grades.html与students.html模板文件 模板语法: {{输出值,可以是变量,也可以是对象,属性}} {%执行代码段%} 访问路由:http://127.0.0.1:8000/students 写grades.html模板: <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>班级信息</title> </head> <body> <h1>班级信息列表</h1> <ul> <!--[python04, python05, python06]--> {%for grade in grades%} <li> <a href="#">{{grade.gname}}</a> </li> {%endfor%} </ul> </body> </html> 定义视图:myApp\views.py from .models import Grades def grades(request): # 去模板里取数据 gradesList = Grades.objects.all() # 将数据传递给模板,模板再渲染页面,将渲染好的页面返回给浏览器 return render(request, 'myApp/grades.html', {"grades": gradesList}) 配置url:myApp\urls.py urlpatterns = [ url(r'^$', views.index), url(r'^(\d+)/(\d+)$', views.detail), url(r'^grades/', views.grades) ] 访问路由:http://127.0.0.1:8000/students 写students.html模板 <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>学生页面</title> </head> <body> <h1>学生信息列表</h1> <ul> {%for student in students%} <li> {{student.sname}}--{{student.scontend}} </li> {%endfor%} </ul> </body> </html> 定义视图:myApp\views.py from .models import Students def students(request): studentsList = Students.objects.all() return render(request, 'myApp/students.html', {"students": studentsList}) 配置url:myApp\urls.py urlpatterns = [ url(r'^$', views.index), url(r'^(\d+)/(\d+)$', views.detail), url(r'^grades/', views.grades), url(r'^students/', views.students), ]
-
静态文件设置
静态文件指css,js,图片,json文件,字体文件等
1,app同级别目录下创建static目录,在目录下创建对应项目的静态文件目录(多个应用的情况下)与文件2,配置settings.py STATIC_URL = '/static' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static') ]
-
启动服务器
注意:ip可以不写,不写代表本机ip;端口号默认是8000
说明:这是一个纯python编写的轻量级web服务器,仅仅在开发测试中使用这个
python manage.py runserver ip:port
python manage.py runserver
四、Django补充
1、定义模型
概述:有一个数据表就对应有一个模型
在models.py文件中定义模型
引入:from django.db import models
模型类要继承models.Model类
示例:
class Grades(models.Model):
gname = models.CharField(max_length=20)
gdate = models.DateTimeField()
ggirlnum = models.IntegerField()
gboynum = models.IntegerField()
isDelete = models.BooleanField(default=False)
说明:
不需要定义主键,在生成时自动添加,并且值为自动增加
2、测试数据操作
进入到python shell
执行 python manage.py shell
引入包
from myApp.models import Grades, Students
from django.utils import timezone
from datetime import *
查询所有数据
类名.objects.all()
示例: Grades.objects.all()
添加数据
本质:创建一个模型类的对象实例
示例:CMD窗口下:
grade1 = Grades()
grade1.gname = "python04"
grade1.gdate = datetime(year=2017, month=7, day=17)
grade1.ggirlnum = 3
grade1.gboynum = 70
grade1.save()
查看某个对象
类名.objects(pk=索引号)
示例:
Grades.objects.get(pk=2)
Grades.objects.all()
修改某个数据
模型对象属性 = 新值
示例:
grade2.gboynum = 60
grade2.save()
删除数据
模型对象.delete()
grade2.delete()
注意:这是物理删除,数据库中的相应数据被永久删除
3、关联对象
示例:
stu = Students()
stu.sname = "Xue Yanmei"
stu.sgender = False
stu.sage = 20
stu.scontend = "I am Xue Yanmei"
stu.sgrade = grade1
stu.save()
获得关联对象的集合
需求:猎取python04班级的所有学生
对象名.关联的类名小写_set.all()
示例:grade1.students_set.all()
需求:创建曾志伟,属于python04班级
示例:
stu3 = grade1.students_set.create(sname=u'Zhen Zhiwei',sgender=True,scontend=u"I am Zhen Zhiwei",sage=45)
注意:这样创建的数据直接被添加到了数据库当中。
4、Admin站点管理
概述:
内容发布:负责添加,修改,删除内容的
公告访问
配置Admin应用:
在settings.py文件中的INSTALLED_APPS中添加'django.contrib.admin',
这条默认是添加好的。
创建管理员用户:
在项目目录下执行 python manage.py createsuperuser
依次输入账号名,邮箱,密码即可完成用户创建
登陆:
http://127.0.0.1:8000/admin/
汉化:
把project\settings.py
中作如下设定:LANGUAGE_CODE = 'zh-Hans'
TIME_ZONE = 'Asia/Shanghai'
5、管理数据表
修改 myAPP\admin.py 如下:
from django.contrib import admin
# Register your models here.
from .models import Grades, Students
# 注册
admin.site.register(Grades)
admin.site.register(Students)
自定义管理页面:
属性说明
# 列表页属性
list_display = [] # 显示字段设置
list_filter = [] # 过滤字段设置
search_fields = [] # 搜索字段设置
list_per_page = [] # 分页设置
# 添加,修改页属性
fields = [] # 规定属性的先后顺序
fieldsets = [] # 给属性分组 注意:fields与fieldsets不能同时使用
属性示例:
# 列表页属性
list_display = ['pk', 'gname', 'gdate', 'ggirlnum', 'gboynum', 'isDelete']
list_filter = ['gname']
search_fields = ['gname']
list_per_page = 5
# 添加,修改页属性
# fields = ['ggirlnum', 'gboynum', 'gname', 'gdate', 'isDelete']
fieldsets = [
("num",{"fields":['ggirlnum', 'gboynum']}),
("base", {"fields":["gname", "gdate", "isDelete"]}),
]
关联对象:需求:在创建一个班级时可以直接添加几个学生
class StudentsInfo(admin.TabularInline):# 可选参数admin.StackedInline
model = Students
extra = 2
class GradesAdmin(admin.ModelAdmin):
inlines = [StudentsInfo]
布尔值显示问题示例:
class StudentsAdmin(admin.ModelAdmin):
def gender(self):
if self.sgender:
return "男"
else:
return "女"
# 设置页面列的名称
gender.short_description = "性别"
list_display = ['pk', 'sname', 'sage', gender,
'scontend', 'sgrade', 'isDelete']
list_per_page = 10
admin.site.register(Students, StudentsAdmin)
执行按钮位置:
class StudentsAdmin(admin.ModelAdmin):
...snip...
actions_on_top = False
actions_on_bottom = True
admin.site.register(Students, StudentsAdmin)
使用装饰器完成注册:
@admin.register(Students)
class StudentsAdmin(admin.ModelAdmin):
def gender(self):
...snip...
actions_on_top = False
actions_on_bottom = True
6、Django流程梳理
创建工程:执行 django-admin startproject 工程名
创建项目:执行 python manage.py startapp 项目名称
激活项目:修改 settings.py中的INSTALLED_APPS
配置数据库:修改__init__.py文件
修改settings.py文件中的DATABASES
创建模型类:在项目目录下的models.py文件中创建
生成迁移文件:执行python manage.py makemigrations
执行迁移:执行python manage.py migrate
配置站点:略
创建模板目录/项目模板目录
在settings.py中的TEMPLATES添加templates路径
在工程目录下(project)修改urls.py
在项目目录下创建urls.py
7、使用他人的Django
1.在settings.py中修改数据库名
2.在settings.py中修改数据库密码
3.删除由内向外文件(在对应目录里鼠标右键删除)
4.在数据库中创建对应第一步的数据库(自己在SQL中创建)
5.执行生成迁移文件
6.执行迁移
7.启动服务
8.浏览器测试
8、ORM
概述:对象-关系-映射
任务:
根据对象的类型生成表结构
将对象,列表的操作转换成SQL语句
将SQL语句查询到的结果转换为对象,列表
优点:
极大的减轻了开发人员的工作量,不需要面对因数据库的变更而修改代码的问题
定义模型
模型,属性,表,字段之间的关系
一个模型类在数据库中对应一张表,在模型类中定义的属性,对应该模型对照表中的一个字段
定义属性:见下文
创建模型类
元选项
在模型类中定义Meta类,用于设置元信息
示例:
class Meta:
db_table = "students"
ordering = ['id']
db_table
定义数据表名,推荐用小写字母,数据表名默认为项目名小写_类名小写
ordering
对象的默认排序字段,获取对象的列表时使用
示例:
ordering['id'] id按升序排列
ordering['-id'] id按降序排列
注意:排序会增加数据库开销
模型成员
类属性
隐藏类属性objects:
是Manager类型的一个对象,作用是与数据库进行交互
当定义模型类时没有指定管理器,则Django为模型创建一个名为objects的管理器
自定义管理器示例:
定义stuObj管理器:
stuObj = models.Manager()
当为模型指定模型管理器,Django就不再为模型类生成objects模型管理器了。
自定义管理器Manager类
模型管理器是Django的模型进行与数据库交互的窗口,一个模型可以有多个模型管理器
作用:
向管理器类中添加额外的方法
修改管理器返回的原始查询集
通常会重写get_queryset()方法
代码示例:
class StudentsManager(models.Manager):
def get_queryset(self):
return super(StudentsManger, self).get_queryset().filter(isDelete=False)
class Students(model.Moder):
# 自定义模型管理器
# 当自定义模型管理器,objects就不存在了
stuObj = models.Manger()
stuObj2 = StudentsManager()
创建对象
目的:向数据库中添加数据
当创建对象时,django不会对数据库进行读写操作,当调用save()方法时才与数据库交互,将对象保存在数据库表中。
注意:
__init__方法已经在父类models.Model中使用,在自定义的模型中无法使用。
方法:
在模型类中增加一个类方法,示例如下:
class Students(model.Moder):
...snip...
@classmethod
def createStudent(cls, name, age, gender, contend,
grade,lastT, createT, isD=False):
stu = cls(sname=name, sage=age, sgender=gender,
scontend=contend, sgrade=grade, lastTime=lastT, createTime=createT,
isDelete=isD)
return stu
在自定义管理器中添加一个方法,示例如下:
class StudentsManager(models.Manager):
def get_queryset(self):
return super(StudentsManager, self).get_queryset().filter(isDelete=False)
def createStudent(self, name, age, gender, contend, grade, lastT, createT, isD=False):
stu = self.model()
# print(type(grade))
stu.sname = name
stu.sage = age
stu.sgender = gender
stu.scontend = contend
stu.sgrade = grade
stu.lastTime = lastT
stu.createTime = createT
return stu
模型查询
概述
查询集表示从数据库获取的对象的集合
查询集可以有多个过滤器
过滤器就是一个函数,基于所给的参数限制查询集结果
从SQL角度来说,查询集和select语句等价,过滤器就像where条件
查询集
在管理器上调用过滤器方法返回查询集
查询集经过过滤器筛选后返回新的查询集,所以可以写成链式调用
惰性执行
创建查询集不会带来任何数据库的访问,直到调用数据库时,才会访问数据
直接访问数据的情况:
迭代
序列化
与if合用
返回查询集的方法称为过滤器
all():返回查询集中的所有数据
filter():保留符合条件的数据
filter(键=值)
filter(键=值,键=值)
filter(键=值).filter(键=值) 且的关系
exclude():过滤掉符合条件的
order_by():排序
values():一条数据就是一个字典,返回一个列表
get()
返回一个满足条件的对象
注意:
如果没有找到符合条件的对象,会引发模型类.DoesNotExist异常
如果找到多个对象,会引发模型类MultipleObjectsReturned异常
count():返回查询集中对象的个数
first():返回查询集中第一个对象
last():返回查询集中最后一个对象
exits():判断查询集中是否有数据,如果有数据返回 True,否则返回 False.
限制查询集
查询集返回列表,可以使用下标的方法进行限制,等同于sql中的limit语句
注意:下标不能是负数
示例:studentsList = Students.stuObj2.all()[0:5]
查询集的缓存
概述:
每个查询集都包含一个缓存,来最小化对数据库的访问
在新建的查询集中,缓存首次为空,第一次对查询集求值,会发生数据缓存,Django会将查询出来的数据做一个缓存,并返回查询结果。
以后的查询直接使用查询集的缓存
字段查询
概述
实现了sql中的where语句,作为方法filter(),exclude(),get()的参数
语法:属性名称__比较运算符=值
外键:属性名称_id
转义:类似sql中的like语句
like有关情况看我哥他%是为了匹配点位,匹配数据中的%使用(where like "\%")
filter(sname__contains="%")
比较运算符
exact:判断,大小写敏感
filter(isDelete=False)
contains:是否包含,大小写敏感
studentsList = Students.stuObj2.filter(sname__contains="孙")
startswith,endswith:以value开头或结尾,大小写敏感
以上四个在前面加上i,就表示不区分大小写iexact,icontains,istartswith,iendswith
isnull,isnotnull
是否为空
filter(sname__isnull=False)
in:是否包含在范围内
gt大于,gte大于等于,lt小于,lte小于等于
year,month,day,week_day,hour,minute,second
studentsList = Students.stuObj2.filter(lastTime__year=2017)
跨关联查询
处理join查询
语法:
模型类名__属性名__比较运算符
# 描述中带有‘薛延美’这三个字的数据是属于哪个班级的
grade = Grades.objects.filter(students__scontend__contains='薛延美')
print(grade)
查询快捷pk代表的主键
聚合函数
使用aggregate函数返回聚合函数的值
Avg
Count
Max
maxAge = Student.stuObj2.aggregate(Max('sage'))
maxAge为最大的sage。
Min
Sum
F对象
可以使用模型的A属性与B属性进行比较
from django.db.models import F,Q
def grades1(request):
g = Grades.objects.filter(ggirlnum__gt=F('gboynum'))
print(g)
# [<Grades: python02>,<Grades: python03>]
return HttpResponse("OOOOOOOo")
支持F对象的算术运算
g = Grades.objects.filter(ggirlnum__gt=F('gboynum')+20)
Q对象
概述:过滤器的方法的关键字参数,条件为And模式
需求:进行or查询
解决:使用Q对象
def students4(request):
studentsList = Students.stuObj2.filter(Q(pk__lte=3) | Q(sage__gt=50))
return render(request, 'myApp/students.html', {"students": studentsList})
只有一个Q对象的时候,就是用于正常匹配条件
studentsList = Students.stuObj2.filter(~Q(pk__lte=3))
~Q是取反
9、定义属性
概述:
django根据属性的类型确定以下信息:
当前选择的数据库支持字段的类型
渲染管理表单时使用的默认html控件
在管理站点最低限度的验证
django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后,则django不会再生成默认的主键列
属性命名限制
遵循标识符规则,且变量不能与Python保留字相同
由于django的查询方式,不允许使用连续的下划线
库
定义属性时,需要字段类型,字段类型被定义在django.db.models.fields目录下,
为了方便使用,被导入到django.db.models中
使用方式
导入: from django.db import models
通过 models.Field创建字段类型的对象,赋值给属性
逻辑删除
对于重要类型都做逻辑删除,不做物理删除,实现方法是定义idDelete属性,
类型为BooleanField,默认值为False
字段类型
autoField
一个根据实际ID自动增长的IntegerField,通常不指定,
如果不指定,一个主键字段将自动添加到模型中
CharField(max_length=字符长度)
字符串,默认的表彰样式是TextInput
TextField
大文本字段,一般超过4000时使用,默认的表单控件是Textarea
IntegerField
整数
DecimalField(max_digits=None, decimal_places=None)
使用Python的Decimal实例表示的十进制浮点数
参数说明
DecimalField.max_digits
位数总数
DecimalField.decimal_places
小数点后的数字位置
FloatField
使用Python的float实例来表示的浮点数
BooleanField
True/False 字段,此字段的默认表彰控制是CheckboxInput
NullBooleanField
支持 Null, True, False 三种值
DateField([auto_now=False, auto_now_add=False])
使用Python的datetime.date实例表示的日期
参数说明:
DateField.auto_now
每次保存对象时,自动设置该字段为当前时间,用于“最后一次修改”
的时间戳,它总是使用当前日期,默认为 False
DateField.auto_now_add
当前对象第一次被创建时自动设置当前时间,用于创建的时间戳,
它总是使用当前日期,默认为 False
说明
该字段默认对应的表单控件是一个TextInput.在管理员站点添加了一个
JavaScript写的日历控件,和一个“Today”的快捷按钮,包含了一个额外
的invalid_date错误消息键
注意
auto_now_add, auto_now, and default 这些设置是相互排斥的,他们之间
的任何组合将会发生错误的结果
TimeField
使用Python的datetime.time实例表示的时间,参数同DateField
DateTimeField
使用Python的datetime
datetime实例表示的日期和时间,参数同DateField
FileField
一个上传文件的字段
ImageField
继承了FileField的所有属性和方法,但对上传的对象进行校验,
确保它是一个有效的image
字段选项
概述
通过字段选项,可以实现对字段的约束
在字段对象中通过关键字参数指定
null
如果为True,Django将空值以NULL存储在数据库中,默认值为 False
blanke
如果为True,则该字段允许为空白,默认值为 False
注意
null是数据库范畴的概念,blank是表彰验证范畴的概念
db_column
字段的名称,如果未指定,则使用属性的名称
db_index
若值为 True,则在表中会为此字段创建索引
default
默认值
primary_key
若为 True,则该字段会成为模型的主键字段
unique
如果为 True,这个字段在表中必须有唯一值
关系
分类
ForeignKey:一对多,将字段定义在多的端中
ManyToManyField:多对多,将字段定义在两端中
OneToOneField:一对一,将字段定义在任意一端中
用一访问多
格式
对象.模型类小写_set
示例
grade.students_set
用一访问一
格式
对象.模型类小写
示例
grade.studnets
访问id
格式
对象.属性_id
示例
student.sgrade_id
-
视图补充
响应:
响应过程:
用户在浏览器中输入网址www.sunck.wang/sunck/index.html
—网址—>
django获取网址信息,去掉IP与端口号,网址变成:sunck/index.html
—虚拟路径与文件名—>
url管理器逐个匹配urlconf,记录视图函数
—视图函数名—>
视图管理,找到对应的视图去执行,返回结果给浏览器
—响应的数据—>
返回第一步:用户在浏览器中输入网址网页重定向、错误视图:
404视图:找不到网页(url匹配不成功时返回)时返回
在templates目录下定义404.html<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <h1>页面丢失</h1> <h2>{{request_path}}</h2> </body> </html> request_path:导致错误的网址 配置settings.py DEBUG 如果为 True,永远不会调用404页面,需要调整为 False 才会显示 ALLOWED_HOSTS = ['*'] 500视图:在视图代码中出现错误(服务器代码错误) 400视图:错误出现在客户的操作
JSON数据
url配置配置流程:
制定根级url配置文件
settings.py文件中的ROOT_URLCONF
ROOT_URLCONF = ‘project.urls’
默认实现了
urlpatterns
一个url实例的列表
url对象
正则表达式
视图名称
名称
url匹配正则的注意事项
如果想要从url中获取一个值,需要对正则加小括号
匹配正则前方不需要加’/’
正则前需要加’r’表示字符串不转义引入其他url配置
在应用中创建urls.py文件,定义本应用的url配置,在工程urls.py中使用include方法
project\urls.py
from django.contrib import admin
from django.conf.urls import url,include
urlpatterns = [
url(r’^admin/’, admin.site.urls),
url(r’^’, include(‘myApp.urls’, namespace=“myAPP”)),
]
myApp\urls.py
from django.urls import path, include
from django.conf.urls import url
from . import views
urlpatterns = [
url(r’^$’, views.index, name=“index”),
]url的反向解析
概述:如果在视图,模板中使用了硬编码链接,在url配置发生改变时,动态生成链接的地址
解决:在使用链接时,通过url配置的名称,动态生成url地址
作用:使用url模板视图函数
定义视图:
本质:一个函数
视图参数:
一个HttpRequest的实例
通过正则表达式获取的参数
位置:一般在views.py文件下定义HttpRequest对象
概述:
服务器接收http请求后,会根据报文创建HttpRequest对象
视图的第一个参数就是HttpRequest对象
django创建的,之后调用视图时传递给视图
属性
path:请求的完整路径(不包括域名和端口)
method:表示请求的方式,常用的有GET,POST
encoding:表示浏览器提交的数据的编码方式,一般为utf-8
GET:类似于字典的对象,包含了get请求的所有参数
POST:类似于字典的对象,包含了post请求的所有参数
FILES:类似字典的对象,包含了所有上传的文件
COOKIES:字典,包含所有的cookie
session:类似字典的对象,表示当前会话
方法
is_ajax():如果是通过XMLHttpRequest发起的,返回 True
QueryDict对象
request对象中的GET,POST都属于QueryDict对象
方法:
get():
根据键获取值,只能获取一个值
www.sunck.wang/abc?a=1&b=2&c=3
getlist()
将键的值以列表的形式返回
可以获取多个值
www.sunck.wang/abc?a=1&b=2&c=3
GET属性
获取浏览器传递过来数据
www.sunck.wang/abc?a=1&b=2&c=3
urls.py
url(r’^get1’, views.get1), #结尾不能加$,否则无法匹配
views.py
def get1(request):
a = request.GET.get(‘a’)
b = request.GET.get(‘b’)
c = request.GET.get(‘c’)
return HttpResponse(a + " " + b + " " + c)www.sunck.wang/abc?a=1&a=2&c=3 urls.py url(r'^get2', views.get2), views.py def get2(request): a = request.GET.getlist('a') a1 = a[0] a2 = a[1] c = request.GET.get('c') return HttpResponse(a1 + " " + a2 + " " + c) POST属性 使用表单模拟POST请求 关闭CSRF:project\project\settings.py 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', ] 示例: def showregist(request): return render(request, 'myApp/regist.html',) def regist(request): name = request.POST.get("name") gender = request.POST.get("gender") age = request.POST.get("age") hobby = request.POST.getlist("hobby") print(name) print(gender) print(age) print(hobby) return HttpResponse("regist") 路径: url(r'^showregist/$', views.showregist), url(r'^showregist/regist/$', views.regist), 页面: <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>注册</title> </head> <body> <form action="regist/" method="post"> 姓名:<input type="text" name="name" value=""/> <hr> 性别:<input type="radio" name="gender" value="1">男<input type="radio" name="gender" value="0">女 <hr> 爱好:<input type="checkbox" name="hobby" value="power"/>权利<input type="checkbox" name="hobby" value="money">金钱<input type="checkbox" name="hobby" value="beauty">美女<input type="checkbox" name="hobby" value="Tesla">Tesla <hr> <input type="submit" value="注册"> </form> </body> </html>
HttpResponse对象
概述:
作用:给浏览器返回数据
HttpRequest对象是由Django创建的,HttpResponse对象是由程序员创建
用法:
不用模板,直接返回数据
语句示例:return HttpResponse(“Sunck is a good man”)
调用模板
使用render方法
原型:render(request, templateName[, context])
作用:结合数据和模板,返回一个完整的HTML页面
参数:
request:请求体对象
templateName:模板路径
context:传递给需要渲染在模板上的数据
属性
content:表示返回内容
charset:编码格式
status_code:响应状态码
304
400
content-type:指定输出的MIME类型
方法
init:使用页面内容实例化HttpResponse对象
write(content):以文件的形式写入
flush():以文件的形式输出缓冲区
set_cookie(key, value, maxAge=None, exprise=None)
delete_cookie(key):
删除cookie
如果删除一个不存在的cookie,就当什么都没发生
子类HttpResponseRedirect
功能:重定向,服务器端的跳转
简写
redirect(to)
to推荐使用反向解析
示例:
from django.http import HttpResponseRedirect
from django.shortcuts import redirect
def redirect1(request):
# return HttpResponseRedirect(’/redirect2’)
return redirect(’/redirect2’)
def redirect2(request):
return HttpResponse(“我是重定向后的视图”)
子类JsonResponse
返回Json数据,一般用于异步请求
init(self.data)
data 字典
注意:Content-type类型为application/json状态保持
http协议是无状态的,每次请求都是一次新的请求,它不记得之前的请求。
客户端与服务器的一次通信就是一次会话
实现状态的保持,在客户端或服务端存储有关会话的数据
存储的方式
cookie:所有数据存储在客户端,不要存储敏感的数据
session:所有的数据存储在服务端,在客户端用cookie存储session_id
状态保持的目的:
在一段时间内跟踪请求者的状态,可以实现跨页面访问当前的请求者的数据
注意:不同的请求者之间不会共享这个数据,与请求者一一对应
启用session:project\project\settings.py
INSTALLED_APPS ‘django.contrib.sessions’,
MIDDLEWARE ‘django.contrib.sessions.middleware.SessionMiddleware’,
使用session
启用session后,每个httpRequest对象都有一个session属性
get[key, default=None] 根据键获取session值
clear() 清空所有会话
flush() 删除当前会话并删除会话的cookie
示例:
# session
def main(request):
# 取session
username = request.session.get(‘name’, ‘游客’)
print(username)
return render(request, ‘myApp/main.html’, {‘username’: username})def login(request): return render(request, 'myApp/login.html') def showmain(request): print("*****************") username = request.POST.get('username') # 存储session request.session['name'] = username return redirect('/main/') from django.contrib.auth import logout def quit(request): # 清除session logout(request) # 方法1,推荐 # request.session.clear() # 方法2 request.session.flush() # 方法3 return redirect('/main/') 设置session过期时间 set_expiry(value) request.session.set_expiry(10) 设置为10秒后过期 如果不设置,2个星期后过期 value设置为0代表关闭浏览器时过期 value设置为None代表设置永不过期,不推荐
模板
定义模板
变量
变量传递给模板的数据
要遵守标识符规则
语法 {{ var }}
注意:如果使用的变量不存在,则插入的是空字符串
在模板中使用点语法
字典查询
属性或者方法
数字索引
在模板中调用对象的方法
注意:在模板里定义的函数不能传递self以外的参数
标签:语法 {% tag %}
作用
在输出中创建文本
控制逻辑和循环
标签示例:
if 格式
{% if 表达式 %}
语句
{% endif %}
if-else 格式
{% if 表达式 %}
语句1
{% else %}
语句else
{% endif %}
if-elif-else 格式
{% if 表达式 %}
语句1
{% elif 表达式 %}
语句2
...
{% else %}
语句else
{% endif %}
for 格式
{% for 变量 in 列表 %}
语句
{% endfor %}
格式2
{% for 变量 in 列表 %}
语句
{% empty %} # 注意:列表为空或者列表不存在时执行语句2
语句2
{% endfor %}
格式3
{{ forloop.counter }}
示例:
<ul>
{% for stu in students %}
<li>
{{forloop.counter}}--{{stu.sname}}--{{stu.sgrade}}
</li>
{% empty %}
<li>目前没有学生</li>
{% endfor %}
commnet 格式
{% commnet %}
被注释的内容
{% endcomment %}
作用:相当于多行注释,被注释的内容不再执行
ifequal/ifnotequal 作用 判断是否相等或者不相等
格式
{% ifequal 值1 值2 %}
语句1
{% endifequal %} # 如果值1等于值2,执行语句1,否则不执行语句1
include
作用:加载模板并以标签内的参数渲染
格式:{% include '模板目录' 参数1 参数2 %}
url
作用:反射解析
格式:{% url 'namespace: name' p1 p2 %}
csrf_token
作用:用于跨站请求伪造保护
格式:{% csrf_token %}
block, extends
作用:用于模板的继承
autoescape
作用:用于HTML转义
过滤器
语法 {{ var|过滤器 }}
作用:在变量被显示前修改它,只是加一个效果,对变量不会造成影响
示例:
lower
upper
过滤器可以传递参数,参数用引号引起来
join 格式 列表|join:"#"
示例:{{list1|join:"#"}}
如果一个变量没有被提供,或者值为false,空,我们可以通过 default 语法使用默认值
格式: {{str1|default:"没有"}}
根据给定格式转换日期为字符串:date
格式: {{dateVal|date:'y-m-d'}}
HTML转义:escape
加减乘除示例:
<h1>num = {{num|add:10}}</h1>
<h1>num = {{num|add:-10}}</h1>
<h1>num = {% num widthratio num 1 5%}</h1>
<h1>num = {% num widthratio num 5 1%}</h1>
注释
单行注释:语法: {# 被注释的内容 #}
多行注释
{% commnet %}
被注释的内容
{% endcomment %}
反射解析
示例:
project/project/urls.py
url(r'^', include('myApp.urls', namespace='app')),
project/myApp/urls.py
url(r'^good/(\d+)$', views.good, name="good")
templates/good.html
<a href={% url 'app:good' 1 %}>链接</a>
模板继承
作用:模板继承可以减少页面的重复定义,实现页面的重用
block标签:在父模板中预留区域 ,子模板去填充
语法 : {% block 标签名 %}
{% endblock 标签名 %}
extends标签:继承模板,需要写在模板文件的第一行
语法 : {% extends 'myApp/base.html' %}
{% block main %}
内容
{% endblock 标签名 %}
示例:
定义父模板
body标签中
{% block main %}
{% endblock main %}
{% block main %}
{% endblock main2 %}
定义子模板
{% extends 'myApp/base.html' %}
{% block main %}
<h1>sunck is a good man</h1>
{% endblock main %}
{% block main2 %}
<h1>kaige is a good man</h1>
{% endblock main2 %}
HTML转义
问题:return render(request, 'myApp/index.html', {"code": "<h1>sunck is a very good man</h1>"})中的{{code}}
{{code}}里的code被当作<h1>sunck is a very good man</h1>显示,未经过渲染
解决方法:
{{code|safe}}
或 {% autoescape off %}
{{code}}
{% endautoescape %} # 这个可以一口气解决一堆
CSRF:
跨站请求伪造
某些恶意网站包含链接,表单,按钮,js,利用登录用户在浏览器中认证,从而攻击服务
防止CSRF
在settings.py文件的MIDDLEWARE增加'django.middleware.csrf.CsrfViewMiddleware'
{% csrf_token %}
验证码
作用
在用户注册,登录页面的时候使用,为了防止暴力请求,减轻服务器的压力
是防止CSRF的一种方式
验证码代码示例:
五、Django高级扩展
1、验证码
def verifycode(request):
# 引入绘图模块
from PIL import Image, ImageDraw, ImageFont
# 引入随机函数模块
import random
# 定义变量,用于画面的背景色,宽,高
bgcolor = (random.randrange(20, 100), random.randrange(20, 100), random.randrange(20, 100))
width = 100
height = 50
# 创建画面对象
im = Image.new('RGB', (width, height), bgcolor)
# 创建画面对象
draw = ImageDraw.Draw(im)
# 调用画笔的point()函数绘制噪点
for i in range(0, 100):
xy = (random.randrange(0, width), random.randrange(0, height))
fill = (random.randrange(0, 255), 255, random.randrange(0, 255))
draw.point(xy, fill=fill)
# 定义验证码的备选值
str = '1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm'
# 随机选取4个值作为验证码
rand_str = ''
for i in range(0, 4):
rand_str += str[random.randrange(0, len(str))]
# 构造字体对象
font = ImageFont.truetype(r'C:\Windows\Fonts\AdobeArabic-Bold.otf', 40)
# 构造字体颜色
fontcolor1 = (255, random.randrange(0, 255), random.randrange(0, 255))
fontcolor2 = (255, random.randrange(0, 255), random.randrange(0, 255))
fontcolor3 = (255, random.randrange(0, 255), random.randrange(0, 255))
fontcolor4 = (255, random.randrange(0, 255), random.randrange(0, 255))
# 绘制4个字
draw.text((5, 2), rand_str[0], font=font, fill=fontcolor1)
draw.text((25, 2), rand_str[1], font=font, fill=fontcolor2)
draw.text((50, 2), rand_str[2], font=font, fill=fontcolor3)
draw.text((75, 2), rand_str[3], font=font, fill=fontcolor4)
# 释放画笔
del draw
# 存入session,用于做进一步的验证
request.session['verifycode'] = rand_str
# 内存文件操作
import io
buf = io.BytesIO()
# 将图片保存在内存中,文件类型为png
im.save(buf, 'png')
# 将内存中的图片数据返回给客户端,MIME类型为图片png
return HttpResponse(buf.getvalue(), 'image/png')
from django.shortcuts import render, redirect
def verifycodefile(request):
f = request.session["falg"]
str = ""
if f == False:
str = "请重新输入!"
request.session.clear()
return render(request, 'myApp/verifycodefile.html', {"flag":str})
def verifycodecheck(request):
code1 = request.POST.get("verifycode").upper()
code2 = request.session["verify"].upper()
if code1 == code2:
return render(request, 'myApp/success.html')
else:
request.session["flag"] = False
return redirect('/verifycodefile')
写在verifycodefile.html的标签中
<form method="post" action="/verifycodecheck/">
{%csrf_token%}
<input type="text" name="verifycode"/>
<img src="/verifycode">
<input type="submit" name="登录">
<span>{{flag}}</span>
</form>
2、中间件
概述:一个轻量级,底层的插件,可以介入Django的请求和响应。
本质:一个Python类
方法:
__init__
不需要传参数,服务器响应第一个请求的时候自动调用,用于确定是否启用该中间件
客户端请求———>[对request做一些操作]———>处理函数———>[对响应response一些其他操作]———返回给客户端
settings中可以看到django默认开启的中间件,Session就是使用了中间件,还有之前POST请求验证的CSRF验证
常见应用:
1. 统计
2. 黑白名单
多个中间件执行过程 中间件1—>中间件2—>中间件3…
process_request(self, request)
在执行视图之前被调用(分配url匹配视图之前),每个请求都会调用,返回None或者HttpResponse对象
process_view(self, request, view_func. view_args, view_kwargs)
调用视图之前执行,每个请求都会调用,返回None或者HttpResponse对象
process_template_response(self, request, response)
在视图刚好执行完后调用,每个请求都会调用,返回None或者HttpResponse对象
使用render
process_response(self, request, response)
所有响应返回浏览器之前调用,每个请求都会调用,返回HttpResponse对象
process_exception(self, request, exception)
当视图抛出异常时调用,返回HttpResponse对象
执行过程:
__init__ --> process_request--> url --> process_view --> view --> process_template_response --> template --> process_response -->返回开头部分
执行位置:
自定义中间件
在工程目录下的middleware目录下创建myApp
创建一个python文件
from django.utils.deprecation import middlewareMixin
class MyMiddle(middlewareMixin):
def process_request(self, request):
print("get参数为: ", request.GET.get("a"))
def process_response(self, request, response):
return response
使用自定义中间件
配置settings.py文件 在MIDDLEWARE中添加 'middleware.myApp.MyMiddle.MyMiddle',
3、文件上传
概述:
文件上传时,文件数据request.FILES属性中.
注意:form表单要上传文件需要加enctype="multipart/form-data"
注意:上传文件必须用post请求
存储路径:
在static目录下创建upfile目录用于存储上传的文件
配置settings.py文件 MDEIA_ROOT = os.path.join(BASE_DIR, r'static\upfile')
import os
from django.conf import settings
def upfile(request):
return render(request, 'myApp/upfile.html')
def savefile(request):
if request.method == "POST":
f = request.FILES["file"]
# 文件在服务器端的路径
filePath = os.pasth.join(settings.MDEIA_ROOT, f.name)
with open(filePath, 'wb') as fp:
for info in f.chunks():
fp.write(info)
return HttpResponse("上传成功。")
else:
return HttpResponse("上传失败。")
upfile.html中里的内容
<form method="post" action="/savefile" enctype="multipart/form-data">
{%csrf_token%}
<input type="file" name="file"/>
<input type="submit" value="上传"/>
</form>
4、分页
数据库中包含含量的数据,每一次返回一部分给客户端。
数据库当中分页使用limit和offset
django中使用queryset[start:end]来实现
class PageCuter(object):
def __init__(self, model, limit=5):
self.current_page = 1
self.limit = limit
self.model = model
def has_next_page(self):
pass
def has_pre_page(self):
pass
def get_page(self, page=None):
pass
def next_page(self):
pass
def pre_page(self):
pass
def last_page(self):
pass
def first_page(self):
pass
Paginator对象
创建对象
格式 Paginator(列表,整数)
返回值 返回的分页对象
属性
count 对象总数
num_pages 页面总数
page_range
页码列表
[1,2,3,4,5]
页码从1开始
方法
page(num) 获得一个Page对象,如果提供的页码不存在会抛出"InvalidPage"异常
异常
InvalidPage:当向 page()传递的是一个无效的页码时抛出
PageNotAnInteger:当向 page()传递的不是一个整数时抛出
EmptyPage:当向 page()传递一个有效值,但是该页面里没有数据时抛出
Page对象
创建对象
Paginator对象的 page()方法返回得到Page对象
不需要手动创建
属性
object_list:当前页上所有数据(对象)列表
number:当前页面的页码值
paginator:当前page对象关联的paginator对象
方法
has_next() 判断是否有下一页,如果有返回 True
has_previous() 判断是否有上一页,如果有返回 True
has_other_pages() 判断是否有上一页或者下一页,如果有返回 True
next_page_number() 返回下一页的页码,如果下一页不存在抛出InvalidPage异常
previous_page_number() 返回上一页的页码,如果上一页不存在,抛出InvalidPage异常
len() 返回当前页的数据(对象)个数
Paginator与Page对象关系(略)
代码示例:
配置路由:url(r'^studentpage/(\d+)/$', views.studentpage),
配置视图:
from .models import Students
from django.core.paginator import Paginator
def studentpage(request, pageid):
# 所有学生列表
allList = Students.objects.all()
paginator = Paginator(allList, 6)
page = paginator.page(pageid)
return render(request, 'myApp/studentpage.html', {"students": page})
配置html
studentpage.html中body标签中的内容:
<body>
<ul>
{% for stu in students %}
<li>
{{stu.sname}}--{{stu.sgrade}}
</li>
{% endfor %}
</ul>
<ul>
{% for index in students.paginator.page_range %}
{% if index == students.number %}
<li>
{{index}}
</li>
{% else %}
<li>
<a href="/sunck/studentpage/{{index}}">{{index}}</a>
</li>
{% endif %}
{% endif%}
</ul>
</body>
5、Ajax
ajax需要动态生成请求JSON数据
代码示例
ajaxstudents.html页面示例
<script type="text/javascript" src="/static/myApp/js/jquery-3.1.1.min.js"></script>
<body>
<h1>学生信息列表</h1>
<button id="btn">显示学生信息</button>
<script type="text/javascript" src="/static/myApp/js/sunck.js"></script>
</body>
sunck.js代码示例
$(document).ready(function (){
document.getElementById("btn").onclick = function (){
$.ajax({
type:"get",
url:"/studentsinfo/",
dataType:"json",
success:function(data, status){
console.log(data)
var d = data["data"]
for(var i=0; i<d.length; i++){
document.write('<p>' + d[i][0] + '</p>')
}
}
})
}
})
views.py代码示例
def ajaxstudents(request):
return render(request, 'myApp/ajaxstudents.html')
from django.http import JsonResponse
def studentsinfo(request):
stus = Students.objects.all()
list = []
for stu in stus:
list.append([stu.sname, stu.sage])
return JsonResponse({"data":list})
6、富文本
pip install django-tinymce
在站点中使用
配置settings.py文件
INSTALLED_APPS 列表中添加 'tinymce',
增加
# 富文本
TINYMCE_DEFAULT_CONFIG = {
'theme':'advanced',
'width':600,
'height':400,
}
创建一个模型类:
在models.py文件中增加
from tinymce.models import HTMLField
class Text(models.Model):
str = HTMLField()
配置站点:
from .models import Text
admin.site.register(Text)
自定义视图使用
<head>
<meta charset="UTF-8">
<title>富文本</title>
<script type="text/javascript" src="/static/tiny_mce/tiny_mce.js"></script>
<script type="text/javascript">
tinyMCE.init({
'mode':'textareas',
'theme':'advanced',
'width':'800',
'height':'600',
})
</script>
</head>
<body>
<form action="/saveedit/" method="post">
<textarea name="str">sunck is a good man</textarea>
<input type="submit" value="提交"/>
</form>
</body>
Celery
http://docs.jinkan.org/docs/celery/
问题:
用户发起request,并且要等待response返回,但在视图中有一些耗时的操作,
导致用户可能会等待很长时间才能接收response,这样用户体验很差
网站每隔一段时间要同步一次数据,但是http请求是需要触发的
解决:
celery来解决
将耗时的操作放在celery中执行
使用celery定时执行
celery:
任务task
本质是一个Python函数,将耗时的操作封装成一个函数
队列queue
将要执行的任务放在队列里
工人worker
负责执行对列中的任务
代理broker
负责高度,在部署环境中使用redis
安装:
pip install celery
pip install celery-with-redis
pip install django-celery
配置settings.py
在INSTALLED_APPS 列表中添加 'djcelery',
# Celery
import djcelery
djcelery.setup_loader() # 初始化
BROKER_URL='redis://:sunck@127.0.0.1:6379/0'
CELERY_IMPORTS=('myApp.task')
在应用目录下创建task.py文件
迁移生成celery需要的数据库表:python manage.py migrate
在工程目录下的project目录下创建celery.py文件
celery.py文件全部内容
from __future__ import absolute_import
import os
from celery import Celery
from django.conf import settings
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'whthas_home.settings')
app = Celery('portal')
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
@app.task(bind=True)
def debug_task(self):
print('request: {0!r}'.format(self.request))
在工程目录下的 project目录下的 __init__.py文件中添加
7、ORM练习
1.数据库中的ER图
E-R图也称实体-联系图(Entity Relationship Diagram)。
一对一关系举例:一个人有仅有一个身份证(有唯一约束的);一个餐馆有一个地址,同时一个地址对应一个餐馆。
一对多关系举例:一个user可以绑定多个社交账号,一个社交账号只能被一个用户绑定;,一个服务员服务于一个餐馆,一个餐馆有多个服务员;
多对多关系举例:一部电影有多个演员,一个演员演过多个电影;一个学生可以选学多门课,一门课可以被多个学生选学;
在Django中,使用models.ForeignKey类 来定义一对多的关系;使用models.ManyToManyField类 定义多对多;使用models.OneToOneField类 来定义一对一的关系。
2.练习
1)创建一个项目 project_book,在project_book中创建一个book应用。
gavin@x:~/sunwenquan$ source venv/bin/activate
(venv) gavin@x:~/sunwenquan$ ls
django_todos venv
(venv) gavin@x:~/sunwenquan$ ls
django_todos venv
(venv) gavin@x:~/sunwenquan$ pip list
Package Version
---------- -------
Django 1.11
pip 10.0.1
pytz 2018.4
setuptools 39.0.1
wheel 0.31.0
(venv) gavin@x:~/sunwenquan$ django-admin startproject project_book
(venv) gavin@x:~/sunwenquan$ cd project_book/
(venv) gavin@x:~/sunwenquan/project_book$ python manage.py startapp book
(venv) gavin@x:~/sunwenquan/project_book$ tree
.
├── book # book中默认是没有urls.py的
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py # 模型,是数据的一种抽象,可以通过它提供的API操作数据
│ ├── tests.py
│ └── views.py # 视图,处理业务逻辑
├── manage.py
└── project_book
├── __init__.py
├── __pycache__
│ ├── __init__.cpython-35.pyc
│ └── settings.cpython-35.pyc
├── settings.py
├── urls.py # 跟路由
└── wsgi.py
4 directories, 14 files
(venv) gavin@x:~/sunwenquan/project_book$
- 写book/models.py
在models.py中设计我们的model,针对每一个表写一个类,每一个类都是django.db.models.Model的子类,django.db.models.Model中提供了丰富的API,我们可以直接使用API对数据库进行CURD操作。
class Publisher(models.Model):
"""
出版社模型
"""
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
class Author(models.Model):
"""
图书作者模型
"""
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
"""
图书模型
"""
class Book(models.Model):
title = models.CharField(max_length=100)
# 一本书可能有多个作者,一个作者可能写过多本书,所以图书和作者是多对多关系
authors = models.ManyToManyField(Author)
# 一般来说,一本书只能在一个出版社出版,而一个出版社可以出版多本书,所以是1对多关系
publisher = models.ForeignKey(Publisher) # 出版社
-
修改project_book/settings.py
33 INSTALLED_APPS = [
34 ‘django.contrib.admin’,
35 ‘django.contrib.auth’,
36 ‘django.contrib.contenttypes’,
37 ‘django.contrib.sessions’,
38 ‘django.contrib.messages’,
39 ‘django.contrib.staticfiles’,
40 ‘book’, # 把book应用注册到INSTALLED_APPS中
]
4)把模型映射到数据库
(venv) gavin@x:~/sunwenquan/project_book$ python manage.py makemigrations
Migrations for 'book':
book/migrations/0001_initial.py
- Create model Author
- Create model Book
- Create model Publisher
- Add field publisher to book
(venv) gavin@x:~/sunwenquan/project_book$
(venv) gavin@x:~/sunwenquan/project_book$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, book, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying book.0001_initial... OK
Applying sessions.0001_initial... OK
(venv) gavin@x:~/sunwenquan/project_book$
-
我们可以通过sqlmigrate命令查看book/migrations/0001_initial.py对应的SQL语句
–
CREATE TABLE “book_author” (“id” integer NOT NULL PRIMARY KEY AUTOINCREMENT, “first_name” varchar(30) NOT NULL, “last_name” varchar(40) NOT NULL);– Create model Book
CREATE TABLE “book_book” (“id” integer NOT NULL PRIMARY KEY AUTOINCREMENT, “title” varchar(100) NOT NULL);
CREATE TABLE “book_book_authors” (“id” integer NOT NULL PRIMARY KEY AUTOINCREMENT, “book_id” integer NOT NULL REFERENCES “book_book” (“id”), “author_id” integer NOT NULL REFERENCES “book_author” (“id”));– Create model Publisher
CREATE TABLE “book_publisher” (“id” integer NOT NULL PRIMARY KEY AUTOINCREMENT, “name” varchar(30) NOT NULL, “address” varchar(50) NOT NULL);
– Add field publisher to book
ALTER TABLE “book_book” RENAME TO “book_book__old”;
CREATE TABLE “book_book” (“id” integer NOT NULL PRIMARY KEY AUTOINCREMENT, “title” varchar(100) NOT NULL, “publisher_id” integer NOT NULL REFERENCES “book_publisher” (“id”));
INSERT INTO “book_book” (“id”, “title”, “publisher_id”) SELECT “id”, “title”, NULL FROM “book_book__old”;
DROP TABLE “book_book__old”;
CREATE INDEX “book_book_publisher_id_7f77c06a” ON “book_book” (“publisher_id”);
COMMIT;
以下是格式化后的SQL语句:
BEGIN;
--
-- Create model Author
--
CREATE TABLE "book_author" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "first_name" varchar(30) NOT NULL, "last_name" varchar(40) NOT NULL);
--
-- Create model Book
--
CREATE TABLE "book_book" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(100) NOT NULL);
CREATE TABLE "book_book_authors" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "book_id" integer NOT NULL REFERENCES "book_book" ("id"), "author_id" integer NOT NULL REFERENCES "book_author" ("id"));
--
-- Create model Publisher
--
CREATE TABLE "book_publisher" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(30) NOT NULL, "address" varchar(50) NOT NULL);
--
-- Add field publisher to book
--
ALTER TABLE "book_book" RENAME TO "book_book__old";
CREATE TABLE "book_book" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(100) NOT NULL, "publisher_id" integer NOT NULL REFERENCES "book_publisher" ("id"));
INSERT INTO "book_book" ("publisher_id", "title", "id") SELECT NULL, "title", "id" FROM "book_book__old";
DROP TABLE "book_book__old";
CREATE INDEX "book_book_publisher_id_7f77c06a" ON "book_book" ("publisher_id");
COMMIT;
提示:
-
自动生成的表名是默认是app名称( book )和模型的小写名称 ( publisher , book , author )的组合;
-
Django为每个表格自动添加加了一个 id 主键;
6)我们可以通过Django Shell练习如何使用Django的API操作数据库from book.models import Publisher
p1 = Publisher(name=‘p111111’, address=‘xxxxxxxxxxxxxxxx’)
p1.save()
p2 = Publisher(name=“p222222”, address=‘yyyyyyyyyyyyyyyyyy’)
p2.save()
p3 = Publisher(name=“p333333”, address=‘zzzzzzzzzzzzzzzzz’)
p3.save()
publisher_list = Publisher.objects.all()
publisher_list
<QuerySet [<Publisher: Publisher object>]>for p in publisher_list:
… print(p.name)
…
p111111
p222222
p333333p = Publisher.objects.get(name=“p333333”)
p.address
‘zzzzzzzzzzzzzzzzz’p.address = ‘oooooooooooooooo’
p.save()
publisher_list = Publisher.objects.all()
for p in publisher_list:
… print(p.name)
…
p111111
p222222
p333333for p in publisher_list:
… print(p.name,p.address)
…
p111111 xxxxxxxxxxxxxxxx
p222222 yyyyyyyyyyyyyyyyyy
p333333 oooooooooooooooo
3.OneToOne、ManyToMany
from django.db import models
class Box(models.Model):
name = models.CharField(max_length=32)
width = models.IntegerField()
height = models.IntegerField()
length = models.IntegerField()
desk = models.OneToOneField('Desk')
class Desk(models.Model):
name = models.CharField(max_length=32)
color_choice = [('red', "红"), ('blue', "蓝"), ('green', '绿')]
color = models.CharField(choices=color_choice, max_length=8)
class Fish(models.Model):
fly = models.BooleanField(default=False)
fname = models.CharField(max_length=20)
fishbox = models.ForeignKey('Box')
#category = models.CharField(max_length=20)
fishcolor_choice = [('red','红'),('blue','蓝'),('green','绿')]
category = models.CharField(choices=fishcolor_choice,max_length=8)
fishimgae = models.ManyToManyField('Image')
class Image(models.Model):
ilong = models.IntegerField()
ileight = models.IntegerField()
iheight = models.IntegerField()
size = models.IntegerField()
增加
1:1: box.desk = desk (obj.related_field_name= obj2)
M:1: fish.fishbox = Box.objects.filter(id=1)[0] (obj.related_field_name= obj2)
M:N fish.fishimgae.add(Image.objects.get(pk=1)) (obj.related_field_name.add(obj2))
更新
1:1: box.desk = desk (obj.related_field_name= obj2)
M:1: fish.fishbox = Box.objects.filter(id=1)[0] (obj.related_field_name= obj2)
M:N fish.fishimgae.add(Image.objects.get(pk=1)) (obj.related_field_name.add(obj2))
读取
1:1 box.desk.name (正写) (obj1.related_field_name.obj2_field_name)
desk.box.name或者desk.box.width等 (反写) (obj2.obj1类名小写.obj1_filed_name)
M:1 fish.fishbox.name (obj.related_field_name.obj2_field_name)
1:M box.fish_set.查询函数 (obj2.关联类名小写_set.查询函数)
N:M fish.fishimgae.查询方法 (obj1.related_field_name.查询方法)
M:N image.fish_set.查询函数 (obj2.关联类名小写_set.查询函数)
8、Django中的模板继承
我们可以按照下述方式组着模板结构:
gavinsun:django_todos gavinsun$ tree templates/
templates/
└── todos
├── home.html # 通过继承,实现基于master.html定制home.html页面;
├── layouts
│ └── master.html # 总体布局文件,把公共部分的html 通过include包含进来
├── list.html # 通过继承,实现基于master.html定制list.html页面;
└── partials
├── footer.html # 页面footer的公共部署
└── navbar.html # 页面导航的功能部分
3 directories, 5 files
gavinsun:django_todos gavinsun$
footer.html完整代码如下:
<!-- ************* footer **********************-->
<hr/>
<div class="container">
©2018, <a href="mailto:gavisun@qq.com">Gavin</a>
<br/>
</div>
navbar.html完整代码如下:
<!-- ********* header ******************-->
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<!-- 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="#navbar-collapse-1">
<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="#">TodoList</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li><a href="/user/create">Register</a></li>
<li><a href="'/login">Sign In</a></li>
</ul>
</div>
</div>
</nav>
master.html完整代码如下:
{% load static %}
<!DOCTYPE html>
<html>
<head>
<title>To Do List</title>
<meta charset="utf-8">
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
{% include 'todos/partials/navbar.html' %}
<!-- *********** main container **************** -->
<div class="container">
{% block container %}
{% endblock %}
</div>
{% include 'todos/partials/footer.html' %}
<script type="text/javascript" src="{% static 'js/jquery.min.js' %}"></script>
<script type="text/javascript" src="{% static 'js/bootstrap.min.js' %}"></script>
<script type="text/javascript" src="{% static 'js/script.js' %}"></script>
</body>
</html>
home.html完整代码如下:
{% extends "todos/layouts/master.html" %}
{% block container %}
<div class="text-center">
<h1>欢迎光临!</h1>
<hr/>
<p>有任何建议,请联系</p>
<h3>Gavin</h3>
<h4><a href="mailto:gavinsun@qq.com">gavinsun@qq.com</a></h4>
</div>
{% endblock %}
list.html完整代码如下:
{% extends "todos/layouts/master.html" %}
{% block container %}
<div class="text-center">
<h1>任务列表</h1>
<ul>
<li>sssss</li>
<li>asdfadfaf</li>
<li>sdfasdfasf</li>
</ul>
<h3>Gavin</h3>
<h4><a href="mailto:gavinsun@qq.com">gavinsun@qq.com</a></h4>
</div>
{% endblock %}
静态文件加载配置说明
STATIC_URL = '/static/' # 虚拟目录 http://127.0.0.1:8000/static/
STATIC_ROOT = 'mystatic/' # 存放collectstatic命令收集到的静态资源
# 该选项目开发阶段,用不到,到部署上线的时候才会用到。
# 例如,当访问 http://localhost:8000/static/css/bootstrap.min.css
#Django 将遍历STATICFILES_DIRS中每个目录,把每个目录当成static,从中查找
# css/bootstrap.min.css,如果找不到,报404
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'public_static'),
os.path.join(BASE_DIR, 'test_staticfiles')
]
送给想学习Django的朋友
Django 千锋培训视频