Django框架基础
1、Django基本认知
Django是一个web后台框架
环境—> linux python3.6 pycharm mysql5.7
虚拟环境
参考:https://pythonguidecn.readthedocs.io/zh/latest/dev/virtualenvs.html
为什么要使用虚拟环境
,正常下,我们只能只用一个环境,当需要多个项目使用不同的版本时就出现了问题,虚拟环境可以解决这类问题,在虚拟环境中可以为你创建可供使用的不同的版本模块
虚拟环境的安装配置
# 安装虚拟环境包 (确保virtualenv已经安装)
pip3 install virtualenvwrapper
让当前用户可以在任意地方使用命令,将以下内容写入~/.bashrc
export WORKON_HOME=/usr/local/python-3.6.6/venve
source /usr/local/python-3.6.6/bin/virtualenvwrapper.sh
第一行:virtualenvwrapper存放虚拟环境目录
第二行:virtualenvwrapper会安装到python的bin目录下所以该路径为python安装目录下/bin/virtualenvwrapper.sh
# 执行下面代码,是配置生效
source ~/.bashrc
执行出现如下错误,是因为系统安装了两个python
/usr/bin/python: No module named virtualenvwrapper
virtualenvwrapper.sh: There was a problem running the initialization hooks.If Python could not import the module virtualenvwrapper.hook_loader,
check that virtualenvwrapper has been installed for
VIRTUALENVWRAPPER_PYTHON=/usr/bin/python and that PATH is
set properly.
解决方法:
在~/.bashrc中加入以下内容
export VIRTUALENVWRAPPER_PYTHON=/usr/local/python-3.6.6/bin/python3
virtualenvwrapper基本使用
1、创建虚拟环境 mkvirtualenv
mkvirtualenv venv
这样会在WORKON_HOME变量指定的目录下新建名为venv的虚拟环境。
若想指定python版本,可通过"–python"指定python解释器
mkvirtualenv -p /usr/local/python-3.6.6/bin/python3 venv
2、基本命令
查看当前虚拟环境目录
workon
切换虚拟环境
workon venv
退出虚拟环境
deactivate
删除虚拟环境
rmvirtualenv venv
安装Django
pip install django
# 安装其他版本
pip install django==1.11.7
新建项目
由于编辑器版本之间的一些差别,我们同一使用跟编辑器无关的通用方式创建项目,就是用命令行创建
django-admin startproject 项目名
(项目名最好不要用Django这类命名)
代码同步
pycharm里面同步设置
tool —> deployment —> confguration 左上角添加 自定义命名 —>添加各种东西
设置
开启服务
python manage.py runserver 0.0.0.0:8000
未安装sqlite 模块,说明系统未安装需要的sqlite;Django可以可以设置setting里面database,配置成mysql
# 安装 sqlite-devel;
yum install sqlite-devel
# 重新编译python
cd /usr/local/python3.6.4
./configure
make
make install
setting:database设置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
'NAME': 'test', #数据库名称
'USER': 'root', # 链接数据库的用户名
'PASSWORD': 'masicro', # 链接数据库的密码
'HOST': '127.0.0.1', # mysql服务器的域名和ip地址
'PORT': '3306', # mysql的一个端口号,默认是3306
}
}
# 在__init__文件中添加
import pymysql
pymysql.install_as_MySQLdb()
2、创建app
python manage.py startapp app_name
如果出现:django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.3 or newer is required; you have 0.7.11.None 这类问题,按下面教程解决
https://www.cnblogs.com/daidechong/p/10044783.html
MTV模型
M model --------------> 数据库
T template -----------> 静态文件(html、css、js)
V views -----> 逻辑处理 (请求和响应)
项目目录说明
manage.py django中的一个命令行工具,管理Django项目
init.py 空文件,告诉python这个目录是python包
setting.py 配置文件,包含数据库信息,调试标志,静态文件等。
***urls.py Django***项目中的URL声明
wsgi.py 部署项目用到
项目与app之间的关系
创建app
python manage.py startapp app_name
3、编写视图
创建好app后,里面会有一个view.py的文件
4、URL路由配置
URL(Uniform Resoure Locator)统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
URL路由就相当于你访问的网址,在配置URL时,需要先配置视图函数
配置path或者re_path
re_path(正则匹配配置)
path('admin/', admin.site.urls),
path('hello/', book_index),
path('music/', music),
# 获取path
path('test/<name>/<int:age>/', test),
re_path('hello/', re_test)
路由分配
当需要很多视图的时候,我们将所有路由写在一个文件里会很混乱,我们将在主路由将子路由包含,
path('book/', include('book.urls'))
kwargs 不定长参数 将字典数据传到视图函数中。视图函数用kwargs接收
path('book/', include('book.urls'), {key:value})
name的作用
给一个匹配的url地址取名,一般用于模版,也可以使用reverse进行页面重定向
给新的URL添加name属性,然后在老的视图里添加页面重定向使页面不论是新的URL还是老的URL都能访问到新的URL里面
配置:
# 在URL里添加name
path("article_new/", views.article_new, name="new_article")
# 在视图里面返回
def article(request):
# 通过url跳转
#return redirect("/book/article_new")
return redirect(reverse("new_article"))
5、模版渲染
模版的渲染在视图里面操作,
# 第一种 导入这个包
from django.template.loader import get_template
def index(request):
# t = get_template('index.html')
# html = t.render()
# return HttpResponse(html)
# 第二种直接操作
return render(request, 'book/index.html')
6、模版
模版路径配置
在配置文件setting.py中找到TEMPLATES设置来配置。
这是一个设置选项的列表,模板大都包含两项通用设置;两种方式配置模板:
第一种: DIRS 定义一个目录列表,模板引擎按列表顺序搜索这些目录以查找模板源文件。将templates放在主项目目录下.
第二种: APP_DIRS告诉模板引擎是否应该进入每个已安装的应用中查找模板,值为True则模板会去安装了的app下面的templates文件夹查找模板。。所以我们也可以在每个app的里面创建模板目录templates存放模板,这种方式需要将这个app添加到setting.py文件的INSTALLED_APPS列表中.
第一种,在setting里设置路径
# 在setting里的template中添加目录
'DIRS': [os.path.join(BASE_DIR, "templates")],
第二种,注册app,就相当于将app的目录添加了, 在setting里的installed_app里添加app名
模版变量
将视图里的变量传到网页页面
视图变量类型可以是多种的:
return render(request, 'book/index.html',context={'name': name},'这里的数据类型可以是多种的:函数,字典,方法。。。。')
网页页面接收数据:
1.语法: {{ 变量名 }}
2.命名由字母和数字以及下划线组成,不能有空格和标点符号
3.可以使用字典、模型、方法、函数、列表
4.不要和python或django关键字重名
5.变量和查找
注:
1.如果data是一个字典,那么访问data.items将会访问data这个字典的key名为items的值,而不会访问字典的items方法。
2.点在模板渲染时有特殊的含义。 变量名中点表示查找。
过滤器
作用:对变量进行过滤。在真正渲染出来之前,过滤器会根据功能出来好变量,然后得出结果后在替换掉原来的变量展示出来
语法: {{fruits|lower}}
管道符号进行莲师调用,比如实现一个功能,先把所有字符变成小写,把第一个字符转换成大写。
语法: {{fruits|lower|capfirst}}
使用参数:过滤器可以使用参数,在过滤器名称后面使用“:”再加上参数,比如要把一个字符串中所有的空格去掉,则可以使用cut过滤器
语法: {{fruits|cut:" "}}
常用的过滤器
date和time过滤器格式
在网页页面接收了时间
{{ss|date:'Y年m月d日 H'}}
什么是自动转义?
自动转义是将变量的一些特殊字符,比如左箭头(<)、右箭头(>)转义成html代码,这样做的目的是为了处理一些不安全的变量。
<:转义成<
:转义成>
‘:转义成'
“:转义成"
&:转义成&
静态文件引用
创建一个同templates级别的目录static,在setting里设置并引入static目录
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'static')
]
7、模版标签
将视图传入的参数进行操作(判断、循环等)
常用标签
例子:
if 的例子
{% if name == "jick"%}
this is a jick logging
{% elif name == "masicro"%}
this is a masicro logging
{% else %}
this is nothing
{% endif %}
for 的例子
{% for i in ls%}
{% if froloop.cunter == 1%}
<li> 这是第一个值{{i}}</li>
{% else %}
<li>{{i}}</li> # 变量都是必须两个“{}”
{% endif %}
{% endfor%}
页面转换
# urls里配置
path('/index5/',views.index5),
path('/article_new/',views.article_new,name='new_article'),
path('test/<int:t_id>',views.test,name="test"),
# 页面配置
<a href = "/book/index5/"> 到过滤器那个页面</a>
<a href = {% url 'new_article' %}> 新的文章的</a>
<a href = {% url 'test' 123 %}> url 加参数传递</a>
with的使用
# 如果传进来参数过长,我们可以将其简写
{% with test_name as tn %}
12423{{tn}}<br>
23523454{{tn}}
{% endwith %}
autoescape的使用
{# autoescape 是自动转义#}
{# html是视图里传来的页面参数 #}
原始的:{{html}} <br>
过滤器方式:{{html|safe}}<br>
标签方式:{% autoescape off %}
{{html}} <br>
{% endautoescape%}
注释标签
{# 注释标签,单行注释 #}
{% comment %}
被注释内容
多行注释
{% endcomment %}
8、模版的继承与引用
Django模版引擎中最强大的也是最复杂的部分就是模版的继承了。模版的继承可以让你穿件一个基本的“骨架”模版,它包含您站点中的全部元素,并且可以定义能够被子模版覆盖的blocks。
例子:
基础页面 base.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}默认标题{% endblock %}</title>
</head>
<body>
{% block content %}默认内容{% endblock %}
</body>
</html>
继承页面 jicheng.html:
{% extends 'base.html' %}
{% block title %}
继承
{% endblock %}
{% block content %}
继承的内容
{# 引用继承的模版内容#}
{{ block.super }}
{# 引用新的内容 将index.html的内容全部引入 #}
{% include 'index.html' %}
{% endblock %}
模版继承使用extends标签实现。通过使用block来给子模版开放接口。
1、extends必须是模版中的第一个出现的标签
2、子模版中的所有内容,必须出现在父模版定义好的block中,否则Django将不会渲染
3、如果出现重复代码,就应该考虑使用模版。
4、尽可能多的定义block,方便子模版实现更细的需求。
5、如果在某个block中,要使用父模版的内容,使用block.super获取
9、自定义过滤器标签
过滤器
创建一个最高级别的python文件包,在其中穿件templatetags文件
# 在上面的filter_test里
from django import template
register = template.Library() #名字是固定的
# 装饰器 注册
@register.filter
def my_lower(value):
return value.lower()
@register.filter
def my_cut(value, arg):
return value.split(arg)
# register.filter(my_lower)
标签
简单标签
TIME_ZONE = 'Asia/Shanghai' # 改时区
有两种方式:
例子一:
#定义简单标签 在文件夹templatetags里的标签文件
import datetime
@register.simple_tag
def current_time1(format_string):
return datetime.datetime.now().strftime(format_string)
# 在html页面使用 需要传参 使用需要导入写好的标签文件
{% current_time1 '%Y年-%m月-%d日 %H:%M:%S' %}
例子二: 在视图(views)里上下文传参
# views 里传参
def index(request):
return render(request, 'jicheng.html', context={
'name': 'hhh',
'li' : list1,
'format_string': '%Y年-%m月-%d日 %H:%M:%S',
})
# 在文件夹templatetags里的标签文件接收
@register.simple_tag(takes_context=True)
def current_time2(context):
format_string = context.get("format_string")
return datetime.datetime.now().strftime(format_string)
# 在页面使用 需要导入写好的标签文件
{% current_time2 %}
包含标签
两种方式:
方式一自定义参数:
添加一个新的模版文件
<ul>
{% for i in ss %}
<li>{{ i }}</li>
{% endfor %}
</ul>
修改包含标签
# 将模版注册到标签
@register.inclusion_tag('tag_model.html')
def show_tag():
xx = ['jick', 'masicro', 'taka']
return {'ss': xx}
引用
# 在新的页面(html)
{% show_tag %}
第二种方式:传参
添加一个新的模版文件
<ul>
{% for i in ss %}
<li>{{ i }}</li>
{% endfor %}
</ul>
修改包含标签
# 将模版注册到标签
@register.inclusion_tag('tag_model.html')
def show_tag2(xx):
return {'ss': xx}
引用
{# li是视图传来的参数#}
{% show_tag2 li %}<br>
10、Django模型
Django模型就是操控数据库
首先配置数据库
# 在setting里配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
'NAME': 'test', #数据库名称
'USER': 'root', # 链接数据库的用户名
'PASSWORD': 'masicro', # 链接数据库的密码
'HOST': '127.0.0.1', # mysql服务器的域名和ip地址
'PORT': '3306', # mysql的一个端口号,默认是3306
}
}
# 在__init__文件中添加
import pymysql
pymysql.install_as_MySQLdb()
创建models模型(数据库信息)
from django.db import models
# Create your models here.
class user(models.Model):
# 创建3个字段
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=30)
age = models.IntegerField()
将模型映射到数据库
1、创建映射文件
python manage.py makemigrations [appname]
# 不接appname表示执行所有的app
2、将映射文件中的映射数据提交到数据库中
python manage.py migrate [appname]
# 不接appname表示执行所有的app
打开数据库我们能看到创建的以app名_模型名的数据表,而其他的一些表格是django自动生成的.
注意:如果要删除表,那么可以去django模型中注释掉模型类,然后执行映射的命令,不要手动在命令行里面去删除.
模型类基本的增删改查
在视图函数中导入自己建好的模型类,然后使用下面方法增加数据、查找数据、删除数据、更新数据
from .models import user
def add_user(request):
# # 方法一
# taka = user(name='taka', age='18')
# taka.save()
#方式二
# moran = user()
# moran.name = '墨染'
# moran.age = 25
# moran.save()
#方法三
# user.objects.create(name='jick', age=27)
# 方法四 不允许重复
user.objects.get_or_create(name='masicro', age=25)
return HttpResponse("添加数据成功")
def search_user(request):
# 查找所有
# rs = user.objects.all()
# print(rs[2].name) #打印的是列表
# 查找某一个
# rs = user.objects.get(id=2) # get 后必须接一个确定的字段
# print(rs)
# 查找满足条件的值
rs = user.objects.filter(name='jick')
print(rs) # 打印的是列表
return HttpResponse("查询数据成功")
# 必须查找到才能删除
def delete_user(request):
# user.objects.all().delete()
user.objects.filter(name='jick').delete()
return HttpResponse("删除数据成功")
# 必须查找到才能修改
def update_user(request):
# user.objects.filter(name='masicro').update(name='jick')
rs = user.objects.get(id=1)
rs.name = 'hell0'
rs.save()
return HttpResponse("更新数据成功")
常用的查询及查询条件
数据的增删改查----------数据库相关的接口(QuerySet API)
1、从数据库中查询出来的结果一般是一个集合,这个集合叫做QuerySet
2、QuertSet是一个可迭代对象
3、QuertSet支持切片,不支持负索引
4、可以用list强行将QuerySet变成列表
常用的查询方法:
1、获取所有记录
rs = user.object.all()
2、获取第一条数据
rs = user.object.first()
3、获取最后一条数据
rs = user.object.last()
4、根据参数提供的条件获取过滤后的记录
注意: fliter(**kwargs)方法:根据参数提供的条件,获取过滤后的QuerySet
rs = user.object.filter(name = "jick")
5、排除name="jick"的记录
rs = user.object.exclude(name='jick')
6、获取一个记录对象
注意:get返回的对象具有唯一性质,如果查询的对象有多个则会报错
rs = user.object.get(name='jick')
7、对结果进行排序order_by
# 根据所选字段进行排序
rs = user.object.order_by('字段')
8、多项排序:
# 先按照字段排序,字段1中重复的按照字段2排序
rs = user.object.order_by('字段1','字段2')
9、逆向排序
rs = user.object.order_by('-字段')
10、将查询到的QuerySet中的Model转换为字典
rs = user.object.all().value()
11、获取当前查询到的数据的总数
rs = user.object.count()
常用的查询条件
1、exact 相当于等于号
rs = user.object.filter(字段__exact='jick')
2、contains 包含
rs = user.object.filter(字段__contains='jick')
3、startwith 以什么开始
rs = user.object.filter(字段__estartwith='jick')
4、istartwith:同startwith 忽略大小写
5、endwith :同startwith 以什么结尾
6、iendwith:同istartwith 以什么结尾 忽略大小写
7、 in 成员所属
rs = user.object.filter(字段__in=['jick','masicro'])
8、gt :大于 ; gte:大于等于; lt:小于; lte:小于等于
rs = user.object.filter(age__gt=18)
rs = user.object.filter(age__gte=18)
rs = user.object.filter(age__lt=18)
rs = user.object.filter(age__lte=18)
9、range 区间
rs = user.object.filter(age__range=(18,20)) #包含18,20
10、isnull 是否为空
rs = user.object.filter(age__isnull=True)
新增字段
在model里写好的模型中添加字段,必须注意的是:要添加一个默认为空的属性或者是添加默认属性,之后再更新
1、python manage.py makemigrations [appname]
2、python manage.py migrate [appname]
删除表
将写好的模型注释或者删除之后在更新,在执行
1、python manage.py makemigrations [appname]
2、python manage.py migrate [appname]
11、常见的字段类型及参数
- IntegerField : 整型,映射到数据库中的int类型。
- CharField: 字符类型,映射到数据库中的varchar类型,通过max_length指定最大长度。
- TextField: 文本类型,映射到数据库中的text类型。
- BooleanField: 布尔类型,映射到数据库中的tinyint类型,在使用的时候,传递True/False进去。如果要可以为空,则用NullBooleanField。
- DateField: 日期类型,没有时间。映射到数据库中是date类型,
在使用的时候,可以设置DateField.auto_now每次保存对象时,自动设置该字段为当前时间。设置DateField.auto_now_add当对象第一次被创建时自动设置当前时间。- DateTimeField: 日期时间类型。映射到数据库中的是datetime类型,
在使用的时候,传递datetime.datetime()进去。
常见参数
primary_key: 指定是否为主键。
unique: 指定是否唯一。
null: 指定是否为空,默认为False。
blank: 等于True时form表单验证时可以为空,默认为False。
default: 设置默认值。
DateField.auto_now: 每次修改都会将当前时间更新进去,只有调用,QuerySet.update方法将不会调用。这个参数只是Date和DateTime以及TimModel.save()方法才会调用e类才有的。
DateField.auto_now_add: 第一次添加进去,都会将当前时间设置进去。以后修改,不会修改这个值
表关系的实现
表结构
表关系
表关系实现
from django.db import models
# Create your models here.
class Department(models.Model):
d_id = models.AutoField(primary_key=True)
d_name = models.CharField(max_length=30)
class Student(models.Model):
s_id = models.AutoField(primary_key=True)
s_name = models.CharField(max_length=30)
# department 会关联Department的主键
department = models.ForeignKey('Department', on_delete=models.CASCADE)
class Course(models.Model):
c_id = models.AutoField(primary_key=True)
c_name = models.CharField(max_length=30)
# 帮我们自动生成关系表
stu = models.ManyToManyField('student')
class Stu_detail(models.Model):
stu = models.OneToOneField('Student', on_delete=models.CASCADE)
age = models.IntegerField()
gender = models.BooleanField(default=True)
addr = models.CharField(max_length=30,default="武汉")
12、 表关联对象及多表查询
1、一对多表——添加数据
from django.http import HttpResponse
from .models import *
# Create your views here.
def test(request):
# 第一种
d1 = Department(d_name='软件学院')
d1.save()
s1 = Student(s_name='jick', department_id=1)
s1.save()
return HttpResponse('xxx')
注意:.
1、第一种方式就是跟之前的一样,用传参的方法添加,需要注意的是外键的值必须是关联表中已经存在的值.
2、第二种方式是用的属性赋值的方式,因为我们在模型类有定义了一个department的属性,而这个属性的对象的类型必须是department表的类实例对象
2、表关联对象的访问
1、Student的模型类中我们有定义department的属性,所以当我们去访问的时候,可以直接通过student.department的形式去找到某个学生的所属学院是哪个.
那么如果我们也希望在在访问某个学院的实现对象的学生的时候改怎么访问呢???
from django.shortcuts import render
from django.http import HttpResponse
from .models import *
# Create your views here.
def test(request):
s1 = Student.objects.get(s_id=1)
d1 = Department.objects.get(d_id=1)
print(s1) # 一个学生的实例
print(s1.s_name) # 学生的名字
print(s1.department_id) # 学生的所属学院的id
print(s1.department) # 学生的所属学院,模型类定义的属性
return HttpResponse('xxx')
2、反向查询
如果模型I有一个ForeignKey,那么该ForeignKey 所指的模型II实例可以通过一个管理器回前面有ForeignKey的模型I的所有实例。默认情况下,这个管理器的名字为foo_set,其中foo 是源模型的小写名称。
from django.shortcuts import render
from django.http import HttpResponse
from .models import *
# Create your views here.
def test(request):
s1 = Student.objects.get(s_id=1)
d1 = Department.objects.get(d_id=2)
# 反向的时候的一种管理器,里面包含了方法
d1.student_set # 反向查询
print(d1.student_set.all()) # .all()拿到所有数据
d1.student_set.add(s1) # 给id为1的学生换到第二学院
# create()方法 新建数据 一对多 多对多
d1.student_set.create(s_name='mack')
return HttpResponse('xxx')
3、表关系查询
from django.shortcuts import render
from django.http import HttpResponse
from .models import *
# Create your views here.
def test(request):
# 建立实例对象
d1 = Department.objects.get(d_id=1)
s1 = Student.objects.get(s_id=1)
c1 = Course.objects.get(c_id=1)
stu_detail = Stu_detail.objects.get(id=1)
# 关于关联对象的访问
# 一对多
print(s1.department) # 学生的所属学院
print(d1.student_set.all()) # 一对多 多的那头 学院的所有学生
# 一对一
print(stu_detail.stu)
print(s1.stu_detail)
# 多对多
print(c1.stu) # 课程中的学生
# 学生报名了哪些课程 反向查询
print(s1.course_set.all())
return HttpResponse('xxx')
4、表关系数据的修改
**注意:**对于所有类型的关联字段,add()、create()、remove()和clear()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法
from django.shortcuts import render
from django.http import HttpResponse
from .models import *
# Create your views here.
def test(request):
# 建立实例对象
d1 = Department.objects.get(d_id=1)
s1 = Student.objects.get(s_id=1)
c1 = Course.objects.get(c_id=1)
stu_detail = Stu_detail.objects.get(id=1)
# 表关联对象方法
'''add(), 一对多,多对多 数据存在'''
d2 = Department.objects.get(d_id=2)
s2 = Student.objects.get(s_id=3)
# 数据修改 将学生id为3的学生,从原来的学院改为学院id2
d2.student_set.add(s2)
python = Course.objects.get(c_name='python')
java = Course.objects.get(c_name='java')
# 学生id为3的学生,添加两门选修课
s2.course_set.add(python, java)
''' create() 新建数据 一对多 多对多'''
# 在学院中添加学生
d2.student_set.create(s_name='jick')
d1.student_set.create(s_name='ock')
# python课程新加入了一个学生 同时将信息存入两张表里面
python.stu.create(s_name='hahah',department_id=2)
s1.course_set.create(c_name='日语')
''' remove() 多对多 '''
python = Course.objects.get(c_name='python')
s1 = Student.objects.get(s_id=3)
# 将python课程中的学生id为3的学生移除
python.stu.remove(s1)
''' clear() 清空'''
# 清空Python课程表
python.stu.clear()
return HttpResponse('xxx')
5、多表查询——跨关联关系查询
Django 提供一种强大而又直观的方式来“处理”查询中的关联关系,它在后台自动帮你处理JOIN。 若要跨越关联关系,只需使用关联的模型字段的名称,并使用双下划线分隔,直至你想要的字段:
# 查询学院名字为‘计算机学院’的学生的信息
rs = Student.objects.filter(department__d_name='软件学院')
# 查询学生名字中包含 'j' 的学生的学院信息
r=Department.objects.filter(student__s_name__contains='j')
# 查询学号为1的学生所有的课程
rs = Course.objects.filter(stu__s_id=1)
# 查询报了课程1的所有的学生
rs = Student.objects.filter(course__c_id=1)
# 查询报了'python'课程的的学生的所属学院的信息
rs=Department.objects.filter(student__course__c_name='python')
{% csrf_token %} 防止跨域攻击
6、聚合查询
在查找到东西后,我们使用aggregate(Ave(age),)
7、分组查询
annotate
13、请求与响应
0、HttpRequest对象
服务器接收到http协议的请求后,会根据报文创建HttpRequest对象视图函数的第一个参数是HttpRequest对象在django.http模块中定义了HttpRequest对象的API
属性:
**path:**一个字符串,表示请求的页面的完整路径,不包含域名
**method:**一个字符串,表示请求使用的HTTP方法,常用值包括:GET、POST
**encodeing:**一个字符串,表示提交的数据的编码方式
如果为None则表示浏览器的默认设置,一般为utf-8
这个属性是可写的,可以通过他来修改访问表单数据使用的编码,接下来对属性的任何访问都将使用新的encoding值
**GET:**一个类似于字典的对象,包括get请求方式的所有参数
**POST:**一个类似于字典的对象,包括post请求方式的所有参数
**FILES:**一个类似于字典的对象,包括所有的上传文件
**COOKIES:**一个标准的Python字典,包含所有的cookie,键和值都为字符串
session:一个即可读又可写的类似于字典的对象,表示当前的会话,只有当Django启动会话的支持时才可用,详细内容见“状态保持”
方法:
is_ajax():如果请求是通过XMLHttpRequest发起的,则返回True
1、form标签中的get和post
在HTML中,form表单的作用是收集标签中的内容,… 中间可以由访问者添加类似于文本,选择,或者一些控制模块等等.然后这些内容将会被送到服务端。
一个表单必须指定两样东西:
- form的method参数用于设置表单的提交方式,默认使用POST.
- action用于设置表单的提交url,如果不写或者保持空字符串,那么将使用当前的URL.
request对象的属性GET、POST都是QueryDict类型的对象
与python字典不同,QueryDict类型的对象用来处理同一个键带有多个值的情况
- 方法get():
根据键获取值,只能获取键的一个值
如果一个键同时拥有多个值,获取最后一值 - 方法getlist():
根据键获取值将键的值以列表返回
可以获取一个键的多个值
2、GET属性
- QueryDict类型的对象
- 包含get请求方式的所有参数
- 与url请求地址中的参数对应,位于?后面
- 参数的格式是键值对,如key1=value1
- 多个参数之间,使用&连接,如key1=value1&key2=value2
3、POST属性
- QueryDict类型的对象
- 包含post请求方式的所有参数
- 与form表单中的控件对应
- 表单中控件要有name属性,则name属性的值为键,value属性的值为值,构成键值对提交
- 对于checkbox控件,name属性一样为一组,当控件被选中后会被提交,存在一键多值的情况.
4、get和post请求方式总结
1、GET:GET如其名,是从服务器获取数据,不会更改服务器的状态和数据,在URL中携带参数发送给服务器。
2、POST则是将一定量的数据发送给服务器,一般会更改服务器的数据。
3、POST方法的参数不能在URL当中看到,他是通过body参数传递给服务器的,所以相对GET方法直接能在URL当中看到传递的参数,显得更加安全一些.当然,也不能简单的判定POST方法比GET方法更安全,要使网站保持安全,需要做更多的安全处理.
5、文件上传
将前端页面中的数据传入服务器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传文件</title>
</head>
<body>
<form action="" method="post" name="upload" enctype="multipart/form-data">{% csrf_token %}
<input type="file" name="file"> <br>
<button type="submit"> 上传</button>
</form>
</body>
</html>
配置好url及存储的路径
def upload_file(request):
if request.method == "GET":
return render(request, 'blog/demo_upload_file.html')
elif request.method == "POST":
f = request.FILES.get('file')
f_name = os.path.join(MEDIA_ROOT, f.name)
with open(f_name, 'wb') as ff:
for c in f.chunks():
ff.write(c)
return HttpResponse("hahha")
6、HttpResponse对象
HttpResponse的子类
返回数据的响应函数有:
HttpResponse(): 返回简单的字符串对象
render():渲染模版
redirect():重定向
JsonResponse():返回json数据
from django.http import JsonResponse
def res(request):
return JsonResponse({'ss':2356})
COOKIE
客户端和服务器都是怎么记录登陆的状态的呢?
服务器中设置cookie及获取cookie:
import datetime
def set_ck(request):
response = HttpResponse('设置cookie')
# response.set_cookie('name','taka') # 默认浏览关闭过期
# response.set_cookie('name','taka',max_age=200) # 多少秒
# response.set_cookie('name','taka',expires=datetime.datetime(2018,11,20)) #
return response
def get_ck(request):
cookie = request.COOKIES
print(cookie.get('name'))
return HttpResponse('获取cookie')
def delete_ck(request):
rs = HttpResponse('删除cookie')
rs.delete_cookie('name')
return rs
7、类视图
from django.views import View
from django.shortcuts import render, reverse, redirect
from .models import Blog
class Blog_add(View):
def get(self, request):
return render(request, 'blog/demo_add.html')
def post(self, request):
title = request.POST.get('title')
content = request.POST.get('content')
print(title, content)
blog = Blog(title=title, content=content)
blog.save()
return redirect(reverse('cls_add'))
# 配置url
path('cls_add/', cls_views.Blog_add.as_view(), name='cls_add')
类视图和函数视图的区别:
1、函数视图无法区分请求的方法,类视图可以直接调用
2、配置url 类视图必须要用as_view()
8、状态保持——cookie和session
1.http协议是无状态的:每次请求都是一次新的请求,不会记得之前通信的状态
2.客户端与服务器端的一次通信,就是一次会话实现状态保持的方式:在客户端或服务器端存储与会话有关的数据
3.存储方式包括cookie、session,会话一般指session对象
- 使用cookie,所有数据存储在客户端,注意不要存储敏感信息
5.使用sesison方式,所有数据存储在服务器端,在客户端cookie中存储session_id
6状态保持的目的是在一段时间内跟踪请求者的状态,可以实现跨页面访问当前请求者的数据
- 注意:不同的请求者之间不会共享这个数据,与请求者一一对应
启用session
在settings.py文件中,默认是都有启用的
注意:在使用session之前必须生成数据库表Django_session
使用session
启用会话后,每个HttpRequest对象将具有一个session属性,它是一个类字典对象
- get(key, default=None):根据键获取会话的值
- clear():清除所有会话
- flush():删除当前的会话数据并删除会话的Cookie
- del request.session[‘member_id’]-:删除
from django.shortcuts import render, redirect, reverse
# Create your views here.
def home(request):
# 显示谁登陆
#name = 'jick'
name = request.session.get('username', '游客')
return render(request, 'form/home.html', {'name': name})
def login_test(request):
if request.method == "GET":
return render(request, 'form/login.html')
elif request.method == 'POST':
username = request.POST.get('username')
# 状态保持
request.session['username'] = username
return redirect(reverse('home'))
1、一个既可读又可写的类似于字典的对象,表示当前的会话.
2、在登录中使用request.session设置一个登录的信息.
3、在主页面中获取设置的值,然后传给模板.
4、使用request.session.flush()清除会话数据.
登陆:
------------------urls.py--------------
from django.urls import path
from . import views
urlpatterns = [
path('home/', views.home, name='home'),
path('login', views.login_test, name='login'),
path('logout/', views.logout_test, name='logout'),
]
------------home--------
<body>
欢迎 {{ name }} 登陆 <br>
<a href="{% url 'login' %}">登陆</a>
<a href="{% url 'logout' %}">退出</a>
</body>
-------------login-------------
<form action="" method="post">{% csrf_token %}
<input type="text" name="username">
<button type="submit">登陆</button>
</form>
会话过期时间
-
set_expiry(value):设置会话的超时时间
-
如果没有指定,则两个星期后过期
-
如果value是一个整数,会话将在values秒没有活动后过期
-
若果value是一个imedelta对象,会话将在当前时间加上这个指定的日期/时间过期
-
如果value为0,那么用户会话的Cookie将在用户的浏览器关闭时过期
-
如果value为None,那么会话永不过期
settings文件中的配置:
# 是否关闭浏览器使得session过期,默认是False SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否每次请求都保存Sessio,默认是修改之后才保存 SESSION_SAVA_EVERY_REQUEST = False # Session的cookie失效日期,默认是2周 SESSION_COOKIE_AVG = 1209600
14、注册和登陆
注册
1、创建数据库并生成数据表,必须想好设计数据库
2、from表单引用
- 登录页面和注册页面都会用到form表单来提交数据
- 当数据提交到后台后,需要在视图函数中去验证数据的合法性.
- django中提供了一个form表单的功能,这个表单可以用来验证数据的合法性还可以用来生成HTML代码
- 今天的登录注册案例我们就来使用这个django自带的form来生成前端页面以及验证数据.
3、Django form表单调用
class RegisterFrom(forms.Form):
username = forms.CharField(max_length=20,min_length=6)
password = forms.CharField(max_length=20,min_length=6,
widget=forms.PasswordInput(attrs={'placeholder':'情输入密码'}),
error_messages={'min_length': '密码的长度小于6', 'max_length': '密码长度超过20',"required":"默认参数"})
password_repeat=forms.CharField(widget=forms.PasswordInput())
email = forms.EmailField()
- 创建一个forms.py的文件,放在指定的app当中,然后在里面写表单.
- 表单是通过类实现的,继承自forms.Form,然后在里面定义要验证的字段.
- 在表单中,创建字段跟模型是一模一样的,但是没有null=True或者blank=True等这几种参数了,有的参数是required=True/False.
- 使用is_valid()方法可以验证用户提交的数据是否合法,而且HTML表单元素的name必须和django中的表单的name保持一致,否则匹配不到.
- is_bound属性:用来表示form是否绑定了数据,如果绑定了,则返回True,否则返回False.
- cleaned_data:这个是在is_valid()返回True的时候,保存用户提交上来的数据.
4、form表单中的一些参数
- max_length 最大长度
- min_length 最小长度
- widget 负责渲染网页上HTML 表单的输入元素和提取提交的原始数据
- attrs 包含渲染后的Widget 将要设置的HTML 属性
- error_messages 报错信息
**注:**虽然form可以生成前端页面,但这个功能实际用的少。主要是使用form的验证功能
5、注册视图
from .forms import RegisterFrom
def register(request):
if request.method == "GET":
form = RegisterFrom()
return render(request, 'form/registe.html', context={'form': form})
elif request.method == "POST":
form =RegisterFrom(request.POST)
if form.is_valid():
username = form.cleaned_data.get("username")
password = form.cleaned_data.get("password")
password_repeat = form.cleaned_data.get("password_repeat")
email = form.cleaned_data.get("email")
if password == password_repeat:
UserModel.objects.create(username=username,password=password,email=email)
return HttpResponse("注册成功")
else:
return HttpResponse("注册失败")
else:
return HttpResponse("注册失败")
前端页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
<form action="" method="post">{% csrf_token %}
{{ form.as_p}}
<button type="submit">注册</button>
</form>
</body>
</html>
总结:
注册的流程:设计并建好数据库—> 写好前端页面并配好URL和视图----->编写视图函数
登陆
from .forms import LoginForm
from django.contrib.auth.hashers import make_password, check_password
def login_test(request):
if request.method == "GET":
form = LoginForm()
return render(request, 'form/user_login.html', context={'form':form})
elif request.method == 'POST':
# 获取表单数据,并将数据传到LoginForm里去验证
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get("username")
password = form.cleaned_data.get("password")
user = UserModel.objects.filter(username=username)
if user:
# 判断密码是否一致
if check_password(password,user[0].password):
request.session["username"] = username
return redirect(reverse('home'))
else:
return render(request,'form/user_login.html',{'error':form.errors})
else:
return redirect(reverse('register'))
else:
return redirect(reverse('login'))
15、自定义中间件
中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能
django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。
在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件.
中间件可以定义的5个方法
process_request(self,request) :
# 执行视图之前被调用,在每个请求上调用,返回None或HttpResponse对象
process_view(self, request, callback, callback_args, callback_kwargs):
# 调用视图之前被调用,在每个请求上调用,返回None或HttpResponse对象
process_template_response(self,request,response):
# 在视图刚好执行完毕之后被调用,在每个请求上调用,返回实现了render方法的响应对象
process_exception(self, request, exception)
# 当视图抛出异常时调用,在每个请求上调用,返回一个HttpResponse对象
process_response(self, request, response)
# 所有响应返回浏览器之前被调用,在每个请求上调用,返回HttpResponse对象