Django学习

基础

创建虚拟环境

项目开发时,由于不同的项目需要,可能会配置多个开发环境,不同开发环境之间的项目依赖包如果混合在一起,可能会引起意想不到的错误。
通过虚拟环境隔离不同开发环境,方便不同开发环境的共存
安装虚拟环境virtualenvvrtaulenvwrapper,virtualenvwrapper是virtualenv的扩展包,用于更方便管理虚拟环境。
sudo pip3 install virtualenv virtualenvwrapper

配置虚拟环境

cd ~/ & vi .bashrc
文件末尾加上

export WORKON_HOME=$HOME/.virtualenvs
#用来放虚拟环境的位置。
export VIRTUALENVWRAPPER_VIRTUALENV=/usr/local/bin/virtualenv
source /usr/local/bin/virtualenvwrapper.sh

运行source ~/.bashrc

命令介绍
workon:                 列出虚拟环境列表
lsvirtualenv:           列出虚拟环境列表
mkvirtualenv:           新建虚拟环境
workon [虚拟环境名称]:    切换/进入虚拟环境
rmvirtualenv :          删除虚拟环境
deactivate:             离开虚拟环境
创建虚拟环境
#创建虚拟环境 根据需要选择3和2
    mkvirtualenv -p python3  虚拟环境名称
    mkvirtualenv -p python  虚拟环境名称
#进入虚拟环境
    workon virtualenv 虚拟环境名称
#查看虚拟环境中已经安装的包
    pip list
    pip freeze
django介绍

Django是一款python的web开发框架
MVC

大部分开发语言中都有MVC框架
MVC框架的核心思想是:解耦
降低各功能模块之间的耦合性,方便变更,更容易重构代码,最大程度上实现代码的重用
m表示model,主要用于对数据库层的封装
v表示view,用于向用户展示结果
c表示controller,是核心,用于处理请求、获取数据、返回结果

MVT

与MVC有所不同,Django属于MVT框架
m表示model,负责与数据库交互
v表示view,是核心,负责接收请求、获取数据、返回结果
t表示template,负责呈现内容到浏览器

安装django

pip install django==1.8.2
说明:使用pip install django命令进行安装时,会自动删除旧版本,再安装新版本
查看版本:进入虚拟环境中python shell,运行如下代码
import django
django.get_version()

所有的虚拟环境,都位于/home/.virtualenvs目录下
进入虚拟环境前的提示:
在这里插入图片描述
进入虚拟环境后的提示:
在这里插入图片描述
创建项目
命令django-admin startproject project1

$ django-admin <command> [options]
$ manage.py <command> [options]
$ python -m django <command> [options]

目录结构如下:

$ tree .
.
└── project1
    ├── manage.py
    └── project1
        ├── asgi.py
        ├── __init__.py
        ├── settings.py
        ├── urls.py
        └── wsgi.py

2 directories, 6 files

目录说明
manage.py:一个命令行工具,可以使你用多种方式对Django项目进行交互
内层的目录:项目的真正的Python包
_init _.py:一个空文件,它告诉Python这个目录应该被看做一个Python包
settings.py:项目的配置
urls.py:项目的URL声明
wsgi.py:项目与WSGI兼容的Web服务器入口
asgi.py:ASGI是对于WSGI原有的模式的支持和WebSocket的扩展。

创建应用

在一个项目中可以创建一到多个应用,每个应用进行一种业务处理
创建应用的命令
cd project1
ls 查看此时目录:manage.py project1
python manage.py startapp app
ls 查看此时目录:app manage.py project1
app应用的目录结构如下图:

$ tree app
app
├── admin.py
├── apps.py
├── __init__.py
├── migrations
│   └── __init__.py
├── models.py
├── tests.py
└── views.py

1 directory, 7 files

定义模型类
有一个数据表,就有一个模型类与之对应
打开models.py文件,定义模型类
引入包from django.db import models
模型类继承自models.Model类
说明:不需要定义主键列,在生成时会自动添加,并且值为自动增长
当输出对象时,会调用对象的str方法

生成数据表
  • 激活模型:编辑settings.py文件,将app应用加入到installed_apps
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app',
  • 生成迁移文件:根据模型类生成sql语句
    python manage.py makemigrations
    迁移文件被生成到应用的migrations目录
  • 执行迁移:执行sql语句生成数据表
    python manage.py migrate
测试数据操作

进入python shell,进行简单的模型API练习
python manage.py shell

启动应用

python3 manage.py runserver ip:port
ip不写默认为8000,是只能在本地访问。
如果要远程访问需要修改vi project1/settings.py ALLOWED_HOSTS=[]添加ip,['*']表示允许任何人访问,不建议。
python3 manage.py runserver 0.0.0.0:8000
0 是 0.0.0.0 的简写
python3 manage.py runserver 0:8000

管理操作
  • 站点分为“内容发布”和“公共访问”两部分
  • “内容发布”的部分负责添加、修改、删除内容,开发这些重复的功能是一件单调乏味、缺乏创造力的工作。为此,Django会根据定义的模型类完全自动地生成管理模块
使用django的管理
  • 创建一个管理员用户
    python manage.py createsuperuser,按提示输入用户名、邮箱、密码
  • 启动服务器,通过“127.0.0.1:8000/admin”访问,输入上面创建的用户名、密码完成登录
  • 进入管理站点,默认可以对groups、users进行管理
管理界面本地化

编辑settings.py文件,设置编码、时区
LANGUAGE_CODE = 'zh-Hans'
django3.0会失败,需要在开头加

from django.utils.translation import gettext_lazy as _
LANGUAGES = [
    ('zh-Hans', _('Chinese')),
]

TIME_ZONE = 'Asia/Shanghai'

向admin注册test的模型

打开test/admin.py文件,注册模型
from django.contrib import admin
from models import testInfo
admin.site.register(testInfo)

  • 刷新管理页面,可以对testInfo的数据进行增删改查操作
  • 问题:如果在str方法中返回中文,在修改和添加时会报ascii的错误
  • 解决:在str()方法中,将字符串末尾添加“.encode(‘utf-8’)”

视图
  • 在django中,视图对WEB请求进行回应
  • 视图接收reqeust对象作为第一个参数,包含了请求的信息
  • 视图就是一个Python函数,被定义在views.py中
#coding:utf-8
from django.http import HttpResponse

def index(request):
    return HttpResponse("index")
def detail(request,id):
    return HttpResponse("detail %s" % id)
  • 定义完成视图后,需要配置urlconf,否则无法处理请求
URLconf
  • 在Django中,定义URLconf包括正则表达式、视图两部分
  • Django使用正则表达式匹配请求的URL,一旦匹配成功,则调用应用的视图
  • 注意:只匹配路径部分,即除去域名、参数后的字符串
  • 在test1/urls.py插入test,使主urlconf连接到test.urls模块
    url(r'^', include('test.urls')),
    在test中的urls.py中添加urlconf
from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^$', views.index),
    url(r'^([0-9]+)/$', views.detail),
]
模板
  • 模板是html页面,可以根据视图中传递的数据填充值
  • 创建模板的目录为templates。
  • 修改settings.py文件,设置TEMPLATES的DIRS值
    'DIRS': [os.path.join(BASE_DIR, 'templates')],
  • 在模板中访问视图传递的数据
    {{输出值,可以是变量,也可以是对象.属性}}
    {%执行代码段%}

模型

ORM简介
  • MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库
  • ORM是“对象-关系-映射”的简称,主要任务是:
    • 根据对象的类型生成表结构
    • 将对象、列表的操作,转换为sql语句
    • 将sql查询到的结果转换为对象、列表
  • 这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动
  • Django中的模型包含存储数据的字段和约束,对应着数据库中唯一的表

在这里插入图片描述

使用MySql数据库
  • 在虚拟环境中安装mysql包
    pip install mysql-python
  • 在mysql中创建数据库
    create databases test2 charset=utf8
  • 打开settings.py文件,修改DATABASES项
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'test2',
        'USER': '用户名',
        'PASSWORD': '密码',
        'HOST': '数据库服务器ip,本地可以使用localhost',
        'PORT': '端口,默认为3306',
    }
}
开发流程

1、在models.py中定义模型类,要求继承自models.Model
2、把应用加入settings.py文件的installed_app项
3、生成迁移文件
4、执行迁移生成表
5、使用模型类进行crud操作

使用数据库生成模型类

python manage.py inspectdb > test/models.py

定义模型
  • 在模型中定义属性,会生成表中的字段
  • django根据属性的类型确定以下信息:
    • 当前选择的数据库支持字段的类型
    • 渲染管理表单时使用的默认html控件
    • 在管理站点最低限度的验证
  • django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后,则django不会再生成默认的主键列
  • 属性命名限制
    • 不能是python的保留关键字
    • 由于django的查询方式,不允许使用连续的下划线
定义属性
  • 定义属性时,需要字段类型
  • 字段类型被定义在django.db.models.fields目录下,为了方便使用,被导入到django.db.models
  • 使用方式
    • 导入from django.db import models
    • 通过models.Field创建字段类型的对象,赋值给属性
  • 对于重要数据都做逻辑删除,不做物理删除,实现方法是定义isDelete属性,类型为BooleanField,默认值为False
字段类型
  • AutoField:一个根据实际ID自动增长的IntegerField,通常不指定。如果不指定,一个主键字段将自动添加到模型中
  • BooleanField:true/false 字段,此字段的默认表单控制是CheckboxInput
  • NullBooleanField:支持null、true、false三种值
  • 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实例来表示的浮点数
  • 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
  • blank:如果为True,则该字段允许为空白,默认值是 False
  • 对比:null是数据库范畴的概念,blank是表单验证证范畴的
  • db_column:字段的名称,如果未指定,则使用属性的名称
  • db_index:若值为 True, 则在表中会为此字段创建索引
  • default:默认值
  • primary_key:若为 True, 则该字段会成为模型的主键字段
  • unique:如果为 True, 这个字段在表中必须有唯一值
关系
  • 关系的类型包括
    • ForeignKey:一对多,将字段定义在多的端中
    • ManyToManyField:多对多,将字段定义在两端中
    • OneToOneField:一对一,将字段定义在任意一端中
  • 可以维护递归的关联关系,使用’self’指定,详见“自关联”
  • 用一访问多:对象.模型类小写_set
  • 用一访问一:对象.模型类小写
  • 访问id:对象.属性_id
元选项
  • 在模型类中定义类Meta,用于设置元信息
  • 元信息db_table:定义数据表名称,推荐使用小写字母,数据表的默认名称
    <app_name>_<model_name>
  • ordering:对象的默认排序字段,获取对象的列表时使用,接收属性构成的列表
class testInfo(models.Model):
    ...
    class Meta():
        ordering = ['id']
  • 字符串前加-表示倒序,不加-表示正序
class testInfo(models.Model):
    ...
    class Meta():
        ordering = ['-id']
  • 排序会增加数据库的开销
模型成员
类的属性
  • objects:是Manager类型的对象,用于与数据库进行交互
  • 当定义模型类时没有指定管理器,则Django会为模型类提供一个名为objects的管理器
  • 支持明确指定模型类的管理器
class testInfo(models.Model):
    ...
    test= models.Manager()
  • 当为模型类指定管理器后,django不再为模型类生成名为objects的默认管理器
    管理器Manager
  • 管理器是Django的模型进行数据库的查询操作的接口,Django应用的每个模型都拥有至少一个管理器
  • 自定义管理器类主要用于两种情况
  • 情况一:向管理器类中添加额外的方法:见下面“创建对象”中的方式二
  • 情况二:修改管理器返回的原始查询集:重写get_queryset()方法
class testInfoManager(models.Manager):
   def get_queryset(self):
       return super(testInfoManager, self).get_queryset().filter(isDelete=False)
class testInfo(models.Model):
   ...
   test = testInfoManager()
创建对象
  • 当创建对象时,django不会对数据库进行读写操作
  • 调用save()方法才与数据库交互,将对象保存到数据库中
  • 使用关键字参数构造模型对象很麻烦,推荐使用下面的两种之式
  • 说明: _init _方法已经在基类models.Model中使用,在自定义模型中无法使用,
  • 方式一:在模型类中增加一个类方法
class BookInfo(models.Model):
    ...
    @classmethod
    def create(cls, title, pub_date):
        book = cls(btitle=title, bpub_date=pub_date)
        book.bread=0
        book.bcommet=0
        book.isDelete = False
        return book

引入时间包:from datetime import *
调用:book=BookInfo.create(“hello”,datetime(1980,10,11));
保存:book.save()
方式二:在自定义管理器中添加一个方法
在管理器的方法中,可以通过self.model来得到它所属的模型类

class BookInfoManager(models.Manager):
    def create_book(self, title, pub_date):
        book = self.model()
        book.btitle = title
        book.bpub_date = pub_date
        book.bread=0
        book.bcommet=0
        book.isDelete = False
        return book

class BookInfo(models.Model):
    ...
    books = BookInfoManager()

调用:book=BookInfo.books.create_book(“abc”,datetime(1980,1,1))
保存:book.save()
在方式二中,可以调用self.create()创建并保存对象,不需要再手动save()

class BookInfoManager(models.Manager):
    def create_book(self, title, pub_date):
        book = self.create(btitle = title,bpub_date = pub_date,bread=0,bcommet=0,isDelete = False)
        return book

class BookInfo(models.Model):
    ...
    books = BookInfoManager()

调用:book=Book.books.create_book(“abc”,datetime(1980,1,1))
查看:book.pk

实例的属性
  • DoesNotExist:在进行单个查询时,模型的对象不存在时会引发此异常,结合try/except使用
    实例的方法
  • str (self):重写object方法,此方法在将对象转换成字符串时会被调用
  • save():将模型对象保存到数据表中
  • delete():将模型对象从数据表中删除
模型查询
简介
  • 查询集表示从数据库中获取的对象集合
  • 查询集可以含有零个、一个或多个过滤器
  • 过滤器基于所给的参数限制查询的结果
  • 从Sql的角度,查询集和select语句等价,过滤器像where和limit子句
  • 接下来主要讨论如下知识点
    • 查询集
    • 字段查询:比较运算符,F对象,Q对象
查询集
  • 在管理器上调用过滤器方法会返回查询集
  • 查询集经过过滤器筛选后返回新的查询集,因此可以写成链式过滤
  • 惰性执行:创建查询集不会带来任何数据库的访问,直到调用数据时,才会访问数据库
  • 何时对查询集求值:迭代,序列化,与if合用
  • 返回查询集的方法,称为过滤器
    • all()
    • filter()
    • exclude()
    • order_by()
    • values():一个对象构成一个字典,然后构成一个列表返回
  • 写法:
    filter(键1=值1,键2=值2)
    等价于
    filter(键1=值1).filter(键2=值2)
  • 返回单个值的方法
    • get():返回单个满足条件的对象
      如果未找到会引发"模型类.DoesNotExist"异常
      如果多条被返回,会引发"模型类.MultipleObjectsReturned"异常
  • count():返回当前查询的总条数
  • first():返回第一个对象
  • last():返回最后一个对象
  • exists():判断查询集中是否有数据,如果有则返回True
限制查询集
  • 查询集返回列表,可以使用下标的方式进行限制,等同于sql中的limit和offset子句
  • 注意:不支持负数索引
  • 使用下标后返回一个新的查询集,不会立即执行查询
  • 如果获取一个对象,直接使用[0],等同于[0:1].get(),但是如果没有数据,[0]引发IndexError异常,[0:1].get()引发DoesNotExist异常
查询集的缓存
  • 每个查询集都包含一个缓存来最小化对数据库的访问
  • 在新建的查询集中,缓存为空,首次对查询集求值时,会发生数据库查询,django会将查询的结果存在查询集的缓存中,并返回请求的结果,接下来对查询集求值将重用缓存的结果
  • 情况一:这构成了两个查询集,无法重用缓存,每次查询都会与数据库进行一次交互,增加了数据库的负载
    print([e.title for e in Entry.objects.all()])
    print([e.title for e in Entry.objects.all()])
  • 情况二:两次循环使用同一个查询集,第二次使用缓存中的数据
    querylist=Entry.objects.all()
    print([e.title for e in querylist])
    print([e.title for e in querylist])
  • 何时查询集不会被缓存:当只对查询集的部分进行求值时会检查缓存,但是如果这部分不在缓存中,那么接下来查询返回的记录将不会被缓存,这意味着使用索引来限制查询集将不会填充缓存,如果这部分数据已经被缓存,则直接使用缓存中的数据
字段查询
  • 实现where子名,作为方法filter()、exclude()、get()的参数
  • 语法:属性名称__比较运算符=值
  • 表示两个下划线,左侧是属性名称,右侧是比较类型
  • 对于外键,使用“属性名_id”表示外键的原始值
  • 转义:like语句中使用了%与,匹配数据中的%与,在过滤器中直接写,例如:filter(title__contains="%")=>where title like ‘%%%’,表示查找标题中包含%的
比较运算符
  • exact:表示判等,大小写敏感;如果没有写“ 比较运算符”,表示判等
    filter(isDelete=False)
  • contains:是否包含,大小写敏感
    exclude(btitle__contains='传')
  • startswith、endswith:以value开头或结尾,大小写敏感
    exclude(btitle__endswith='传')
  • isnull、isnotnull:是否为null
    filter(btitle__isnull=False)
  • 在前面加个i表示不区分大小写,如iexact、icontains、istarswith、iendswith
  • in:是否包含在范围内
    filter(pk__in=[1, 2, 3, 4, 5])
  • gt、gte、lt、lte:大于、大于等于、小于、小于等于
    filter(id__gt=3)
  • year、month、day、week_day、hour、minute、second:对日期间类型的属性进行运算
    filter(bpub_date__year=1980)
    filter(bpub_date__gt=date(1980, 12, 31))
  • 跨关联关系的查询:处理join查询
    • 语法:模型类名 <属性名> <比较>
    • 注:可以没有__<比较>部分,表示等于,结果同inner join
    • 可返向使用,即在关联的两个模型中都可以使用
      filter(heroinfo_ _hcontent_ _contains='八')
  • 查询的快捷方式:pk,pk表示primary key,默认的主键是id
    filter(pk__lt=6)
聚合函数
  • 使用aggregate()函数返回聚合函数的值
  • 函数:Avg,Count,Max,Min,Sum
    from django.db.models import Max
    maxDate = list.aggregate(Max('bpub_date'))
  • count的一般用法:
    count = list.count()
F对象
  • 可以使用模型的字段A与字段B进行比较,如果A写在了等号的左边,则B出现在等号的右边,需要通过F对象构造
    list.filter(bread__gte=F('bcommet'))
  • django支持对F()对象使用算数运算
    list.filter(bread__gte=F('bcommet') * 2)
  • F()对象中还可以写作“模型类__列名”进行关联查询
    list.filter(isDelete=F('heroinfo__isDelete'))
  • 对于date/time字段,可与timedelta()进行运算
    list.filter(bpub_date__lt=F('bpub_date') + timedelta(days=1))
Q对象
  • 过滤器的方法中关键字参数查询,会合并为And进行
  • 需要进行or查询,使用Q()对象
  • Q对象(django.db.models.Q)用于封装一组关键字参数,这些关键字参数与“比较运算符”中的相同
    from django.db.models import Q
    list.filter(Q(pk_ _lt=6))
  • Q对象可以使用&(and)、|(or)操作符组合起来
  • 当操作符应用在两个Q对象时,会产生一个新的Q对象
    list.filter(pk_ _lt=6).filter(bcommet_ _gt=10)
    list.filter(Q(pk_ _lt=6) | Q(bcommet_ _gt=10))
  • 使用~(not)操作符在Q对象前表示取反
    list.filter(~Q(pk__lt=6))
  • 可以使用&|~结合括号进行分组,构造做生意复杂的Q对象
  • 过滤器函数可以传递一个或多个Q对象作为位置参数,如果有多个Q对象,这些参数的逻辑为and
  • 过滤器函数可以混合使用Q对象和关键字参数,所有参数都将and在一起,Q对象必须位于关键字参数的前面
自连接
  • 对于地区信息,属于一对多关系,使用一张表,存储所有的信息
  • 类似的表结构还应用于分类信息,可以实现无限级分类
  • 新建模型AreaInfo,生成迁移
class AreaInfo(models.Model):
    atitle = models.CharField(max_length=20)
    aParent = models.ForeignKey('self', null=True, blank=True)
  • 访问关联对象
    上级对象:area.aParent
    下级对象:area.areainfo_set.all()
  • 加入测试数据(在workbench中,参见“省市区mysql.txt”)
  • 在booktest/views.py中定义视图area
from models import AreaInfo
def area(request):
    area = AreaInfo.objects.get(pk=130100)
    return render(request, 'booktest/area.html', {'area': area})
  • 定义模板area.html
<!DOCTYPE html>
<html>
<head>
    <title>地区</title>
</head>
<body>
当前地区:{{area.atitle}}
<hr/>
上级地区:{{area.aParent.atitle}}
<hr/>
下级地区:
<ul>
    { %for a in area.areainfo_set.all%}
    <li>{{a.atitle}}</li>
    { %endfor%}
</ul>
</body>
</html>
  • 在booktest/urls.py中配置一个新的urlconf
urlpatterns = [
    url(r'^area/$', views.area, name='area')
]

视图

  • 视图接受Web请求并且返回Web响应
  • 视图就是一个python函数,被定义在views.py中
  • 响应可以是一张网页的HTML内容,一个重定向,一个404错误等等
  • 响应处理过程如下图:
    在这里插入图片描述
URLconf
  • 在settings.py文件中通过ROOT_URLCONF指定根级url的配置
  • urlpatterns是一个url()实例的列表
  • 一个url()对象包括:
    • 正则表达式
    • 视图函数
    • 名称name
  • 编写URLconf的注意:
    • 若要从url中捕获一个值,需要在它周围设置一对圆括号
    • 不需要添加一个前导的反斜杠,如应该写作'test/',而不应该写作'/test/'
    • 每个正则表达式前面的r表示字符串不转义
  • 请求的url被看做是一个普通的python字符串,进行匹配时不包括get或post请求的参数及域名
    http://www.itcast.cn/python/1/?i=1&p=new,只匹配“/python/1/”部分
  • 正则表达式非命名组,通过位置参数传递给视图
    url(r'^([0-9]+)/$', views.detail, name='detail'),
  • 正则表达式命名组,通过关键字参数传递给视图,本例中关键字参数为id
    url(r'^(?P<id>[0-9]+)/$', views.detail, name='detail'),
  • 参数匹配规则:优先使用命名参数,如果没有命名参数则使用位置参数
  • 每个捕获的参数都作为一个普通的python字符串传递给视图
  • 性能:urlpatterns中的每个正则表达式在第一次访问它们时被编译,这使得系统相当快
包含其它的URLconfs
  • 在应用中创建urls.py文件,定义本应用中的urlconf,再在项目的settings中使用include()
from django.conf.urls import include, url
urlpatterns = [
    url(r'^', include('booktest.urls', namespace='booktest')),
]
  • 匹配过程:先与主URLconf匹配,成功后再用剩余的部分与应用中的URLconf匹配
    请求http://www.baidu.com/booktest/1/
    在sesstings.py中的配置:
    url(r'^booktest/', include('booktest.urls', namespace='booktest')),
    在booktest应用urls.py中的配置
    url(r'^([0-9]+)/$', views.detail, name='detail'),
    匹配部分是:/booktest/1/
    匹配过程:在settings.py中与“booktest/”成功,再用“1/”与booktest应用的urls匹配
  • 使用include可以去除urlconf的冗余
  • 参数:视图会收到来自父URLconf、当前URLconf捕获的所有参数
  • 在include中通过namespace定义命名空间,用于反解析
URL的反向解析
  • 如果在视图、模板中使用硬编码的链接,在urlconf发生改变时,维护是一件非常麻烦的事情
  • 解决:在做链接时,通过指向urlconf的名称,动态生成链接地址
  • 视图:使用django.core.urlresolvers.reverse()函数
  • 模板:使用url模板标签
视图函数
定义视图
  • 本质就是一个函数
  • 视图的参数
    • 一个HttpRequest实例
    • 通过正则表达式组获取的位置参数
    • 通过正则表达式组获得的关键字参数
  • 在应用目录下默认有views.py文件,一般视图都定义在这个文件中
  • 如果处理功能过多,可以将函数定义到不同的py文件中
    新建views1.py
#coding:utf-8
from django.http import HttpResponse
def index(request):
    return HttpResponse("你好")

在urls.py中修改配置
from . import views1
url(r'^$', views1.index, name='index'),

错误视图
  • Django原生自带几个默认视图用于处理HTTP错误
404 (page not found) 视图
  • defaults.page_not_found(request, template_name=‘404.html’)
  • 默认的404视图将传递一个变量给模板:request_path,它是导致错误的URL
  • 如果Django在检测URLconf中的每个正则表达式后没有找到匹配的内容也将调用404视图
  • 如果在settings中DEBUG设置为True,那么将永远不会调用404视图,而是显示URLconf 并带有一些调试信息
  • 在templates中创建404.html
<!DOCTYPE html>
<html>
<head>
   <title></title>
</head>
<body>
找不到了
<hr/>
{{request_path}}
</body>
</html>
  • 在settings.py中修改调试
    DEBUG = False
    ALLOWED_HOSTS = ['*', ]
  • 请求一个不存在的地址
    http://127.0.0.1:8000/test/
500 (server error) 视图
  • defaults.server_error(request, template_name='500.html')
  • 在视图代码中出现运行时错误
  • 默认的500视图不会传递变量给500.html模板
  • 如果在settings中DEBUG设置为True,那么将永远不会调用505视图,而是显示URLconf 并带有一些调试信息
400 (bad request) 视图
  • defaults.bad_request(request, template_name='400.html')
  • 错误来自客户端的操作
  • 当用户进行的操作在安全方面可疑的时候,例如篡改会话cookie
HttpReqeust对象
  • 服务器接收到http协议的请求后,会根据报文创建HttpRequest对象
  • 视图函数的第一个参数是HttpRequest对象
  • 在django.http模块中定义了HttpRequest对象的API
属性
  • 下面除非特别说明,属性都是只读的
  • path:一个字符串,表示请求的页面的完整路径,不包含域名
  • method:一个字符串,表示请求使用的HTTP方法,常用值包括:‘GET’、‘POST’
  • encoding:一个字符串,表示提交的数据的编码方式
    • 如果为None则表示使用浏览器的默认设置,一般为utf-8
    • 这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值
  • GET:一个类似于字典的对象,包含get请求方式的所有参数
  • POST:一个类似于字典的对象,包含post请求方式的所有参数
  • FILES:一个类似于字典的对象,包含所有的上传文件
  • COOKIES:一个标准的Python字典,包含所有的cookie,键和值都为字符串
  • session:一个既可读又可写的类似于字典的对象,表示当前的会话,只有当Django 启用会话的支持时才可用,详细内容见“状态保持”
方法
  • is_ajax():如果请求是通过XMLHttpRequest发起的,则返回True
QueryDict对象
  • 定义在django.http.QueryDict
  • request对象的属性GET、POST都是QueryDict类型的对象
  • 与python字典不同,QueryDict类型的对象用来处理同一个键带有多个值的情况
    方法get():根据键获取值
    • 只能获取键的一个值
    • 如果一个键同时拥有多个值,获取最后一个值
      dict.get('键',default)或简写为dict['键']
  • 方法getlist():根据键获取值
    将键的值以列表返回,可以获取一个键的多个值
    dict.getlist('键',default)
GET属性
  • QueryDict类型的对象
  • 包含get请求方式的所有参数
  • 与url请求地址中的参数对应,位于?后面
  • 参数的格式是键值对,如key1=value1
  • 多个参数之间,使用&连接,如key1=value1&key2=value2
  • 键是开发人员定下来的,值是可变的
  • 示例如下:
    创建视图getTest1用于定义链接,getTest2用于接收一键一值,getTest3用于接收一键多值
def getTest1(request):
    return render(request,'booktest/getTest1.html')
def getTest2(request):
    return render(request,'booktest/getTest2.html')
def getTest3(request):
    return render(request,'booktest/getTest3.html')
  • 配置url
url(r'^getTest1/$', views.getTest1),
url(r'^getTest2/$', views.getTest2),
url(r'^getTest3/$', views.getTest3),
  • 创建getTest1.html,定义链接
<html>
<head>
    <title>Title</title>
</head>
<body>
链接1:一个键传递一个值
<a href="/getTest2/?a=1&b=2">gettest2</a><br>
链接2:一个键传递多个值
<a href="/getTest3/?a=1&a=2&b=3">gettest3</a>
</body>
</html>
  • 完善视图getTest2的代码
def getTest2(request):
    a=request.GET['a']
    b=request.GET['b']
    context={'a':a,'b':b}
    return render(request,'booktest/getTest2.html',context)
  • 创建getTest2.html,显示接收结果
<html>
<head>
    <title>Title</title>
</head>
<body>
a:{{ a }}<br>
b:{{ b }}
</body>
</html>
  • 完善视图getTest3的代码
def getTest3(request):
    a=request.GET.getlist('a')
    b=request.GET['b']
    context={'a':a,'b':b}
    return render(request,'booktest/getTest3.html',context)
  • 创建getTest3.html,显示接收结果
<html>
<head>
    <title>Title</title>
</head>
<body>
a:{% for item in a %}
{{ item }}
{% endfor %}
<br>
b:{{ b }}
</body>
</html>
POST属性
  • QueryDict类型的对象
  • 包含post请求方式的所有参数
  • 与form表单中的控件对应
  • 问:表单中哪些控件会被提交?
    答:控件要有name属性,则name属性的值为键,value属性的值为键,构成键值对提交
    • 对于checkbox控件,name属性一样为一组,当控件被选中后会被提交,存在一键多值的情况
  • 键是开发人员定下来的,值是可变的
  • 示例如下,定义视图postTest1
def postTest1(request):
    return render(request,'booktest/postTest1.html')
  • 配置url
    url(r'^postTest1$',views.postTest1)
  • 创建模板postTest1.html
<html>
<head>
    <title>Title</title>
</head>
<body>
<form method="post" action="/postTest2/">
    姓名:<input type="text" name="uname"/><br>
    密码:<input type="password" name="upwd"/><br>
    性别:<input type="radio" name="ugender" value="1"/><input type="radio" name="ugender" value="0"/><br>
    爱好:<input type="checkbox" name="uhobby" value="胸口碎大石"/>胸口碎大石
    <input type="checkbox" name="uhobby" value="跳楼"/>跳楼
    <input type="checkbox" name="uhobby" value="喝酒"/>喝酒
    <input type="checkbox" name="uhobby" value="爬山"/>爬山<br>
    <input type="submit" value="提交"/>
</form>
</body>
</html>
  • 创建视图postTest2接收请求的数据
def postTest2(request):
    uname=request.POST['uname']
    upwd=request.POST['upwd']
    ugender=request.POST['ugender']
    uhobby=request.POST.getlist('uhobby')
    context={'uname':uname,'upwd':upwd,'ugender':ugender,'uhobby':uhobby}
    return render(request,'booktest/postTest2.html',context)

*配 置url
url(r'^postTest2$',views.postTest2)

  • 创建模板postTest2.html
<html>
<head>
    <title>Title</title>
</head>
<body>
{{ uname }}<br>
{{ upwd }}<br>
{{ ugender }}<br>
{{ uhobby }}
</body>
</html>
  • 注意:使用表单提交,注释掉settings.py中的中间件crsf
HttpResponse对象
  • 在django.http模块中定义了HttpResponse对象的API
  • HttpRequest对象由Django自动创建,HttpResponse对象由程序员创建
  • 不调用模板,直接返回数据
#coding=utf-8
from django.http import HttpResponse

def index(request):
    return HttpResponse('你好')
  • 调用模板
from django.http import HttpResponse
from django.template import RequestContext, loader

def index(request):
    t1 = loader.get_template('polls/index.html')
    context = RequestContext(request, {'h1': 'hello'})
    return HttpResponse(t1.render(context))
属性
  • content:表示返回的内容,字符串类型
  • charset:表示response采用的编码字符集,字符串类型
  • status_code:响应的HTTP响应状态码
  • content-type:指定输出的MIME类型
方法
  • init :使用页内容实例化HttpResponse对象
  • write(content):以文件的方式写
  • flush():以文件的方式输出缓存区
  • set_cookie(key, value=’’, max_age=None, expires=None):设置Cookie
    • key、value都是字符串类型
    • max_age是一个整数,表示在指定秒数后过期
    • expires是一个datetime或timedelta对象,会话将在这个指定的日期/时间过期,注意datetime和timedelta值只有在使用PickleSerializer时才可序列化
    • max_age与expires二选一
    • 如果不指定过期时间,则两个星期后过期
from django.http import HttpResponse
from datetime import *

def index(request):
    response = HttpResponse()
    if request.COOKIES.has_key('h1'):
        response.write('<h1>' + request.COOKIES['h1'] + '</h1>')
    response.set_cookie('h1', '你好', 120)
    # response.set_cookie('h1', '你好', None, datetime(2016, 10, 31))
    return response
  • delete_cookie(key):删除指定的key的Cookie,如果key不存在则什么也不发生
子类HttpResponseRedirect
  • 重定向,服务器端跳转
  • 构造函数的第一个参数用来指定重定向的地址
    在views1.py中
from django.http import HttpResponse,HttpResponseRedirect
def index(request):
    return HttpResponseRedirect('js/')
def index2(request,id):
    return HttpResponse(id)

在应用的urls.py中增加一个url对象
url(r'^([0-9]+)/$', views1.index2, name='index2'),
请求地址栏127.0.0.1:8000/
请求结果的地址栏127.0.0.1:800/js/

推荐使用反向解析

from django.core.urlresolvers import reverse

def index(request):
    return HttpResponseRedirect(reverse('booktest:index2', args=(1,)))
子类JsonResponse
  • 返回json数据,一般用于异步请求
  • _init _(data)
  • 帮助用户创建JSON编码的响应
  • 参数data是字典对象
  • JsonResponse的默认Content-Type为application/json
from django.http import JsonResponse

def index2(requeset):
    return JsonResponse({'list': 'abc'})
简写函数
render
  • render(request, template_name[, context])
  • 结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的HttpResponse对象
  • request:该request用于生成response
  • template_name:要使用的模板的完整名称
  • context:添加到模板上下文的一个字典,视图将在渲染模板之前调用它
from django.shortcuts import render
def index(request):
    return render(request, 'booktest/index.html', {'h1': 'hello'})
重定向
  • redirect(to)
  • 为传递进来的参数返回HttpResponseRedirect
  • to推荐使用反向解析
from django.shortcuts import redirect
from django.core.urlresolvers import reverse

def index(request):
    return redirect(reverse('booktest:index2'))
得到对象或返回404
  • get_object_or_404(klass, args, *kwargs)
  • 通过模型管理器或查询集调用get()方法,如果没找到对象,不引发模型的DoesNotExist异常,而是引发Http404异常
  • klass:获取对象的模型类、Manager对象或QuerySet对象
  • **kwargs:查询的参数,格式应该可以被get()和filter()接受
  • 如果找到多个对象将引发MultipleObjectsReturned异常
from django.shortcuts import *

def detail(request, id):
    try:
        book = get_object_or_404(BookInfo, pk=id)
    except BookInfo.MultipleObjectsReturned:
        book = None
    return render(request, 'booktest/detail.html', {'book': book})

将settings.py中的DEBUG改为False
将请求地址输入2和100查看效果

得到列表或返回404
  • get_list_or_404(klass, args, *kwargs)
  • klass:获取列表的一个Model、Manager或QuerySet实例
  • **kwargs:查寻的参数,格式应该可以被get()和filter()接受
from django.shortcuts import *

def index(request):
    # list = get_list_or_404(BookInfo, pk__lt=1)
    list = get_list_or_404(BookInfo, pk__lt=6)
    return render(request, 'booktest/index.html', {'list': list})

将settings.py中的DEBUG改为False

状态保持

http协议是无状态的:每次请求都是一次新的请求,不会记得之前通信的状态
客户端与服务器端的一次通信,就是一次会话
实现状态保持的方式:在客户端或服务器端存储与会话有关的数据
存储方式包括cookie、session,会话一般指session对象
使用cookie,所有数据存储在客户端,注意不要存储敏感信息
推荐使用sesison方式,所有数据存储在服务器端,在客户端cookie中存储session_id
状态保持的目的是在一段时间内跟踪请求者的状态,可以实现跨页面访问当前请求者的数据
注意:不同的请求者之间不会共享这个数据,与请求者一一对应

启用session

使用django-admin startproject创建的项目默认启用
在settings.py文件中
项INSTALLED_APPS列表中添加:
'django.contrib.sessions',

项MIDDLEWARE_CLASSES列表中添加:
'django.contrib.sessions.middleware.SessionMiddleware',
禁用会话:删除上面指定的两个值,禁用会话将节省一些性能消耗

使用session

启用会话后,每个HttpRequest对象将具有一个session属性,它是一个类字典对象
get(key, default=None):根据键获取会话的值
clear():清除所有会话
flush():删除当前的会话数据并删除会话的Cookie
del request.session[‘member_id’]:删除会话

在views.py文件中创建视图

from django.shortcuts import render, redirect
from django.core.urlresolvers import reverse

def index(request):
    uname = request.session.get('uname')
    return render(request, 'booktest/index.html', {'uname': uname})

def login(request):
    return render(request, 'booktest/login.html')

def login_handle(request):
    request.session['uname'] = request.POST['uname']
    return redirect(reverse('main:index'))

def logout(request):
    # request.session['uname'] = None
    # del request.session['uname']
    # request.session.clear()
    request.session.flush()
    return redirect(reverse('main:index'))

配置url
主url:
`
``pyfrom django.conf.urls import include, url
urlpatterns = [
url(r’^’, include(‘booktest.urls’, namespace=‘main’))
]

应用url:
```py
from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'login/$', views.login, name='login'),
    url(r'login_handle/$', views.login_handle, name='login_handle'),
    url(r'logout/$', views.logout, name='logout')
]

创建模板index.html

<!DOCTYPE html>
<html>
<head>
    <title>首页</title>
</head>
<body>
你好:{{uname}}
<hr/>
<a href="{%url 'main:login'%}">登录</a>
<hr/>
<a href="{%url 'main:logout'%}">退出</a>
</body>
</html>

创建模板login.html

<!DOCTYPE html>
<html>
<head>
    <title>登录</title>
</head>
<body>
<form method="post" action="/login_handle/">
    <input type="text" name="uname"/>
    <input type="submit" value="登录"/>
</form>
</body>
</html>
会话过期时间

set_expiry(value):设置会话的超时时间
如果没有指定,则两个星期后过期
如果value是一个整数,会话将在values秒没有活动后过期
若果value是一个imedelta对象,会话将在当前时间加上这个指定的日期/时间过期
如果value为0,那么用户会话的Cookie将在用户的浏览器关闭时过期
如果value为None,那么会话永不过期
修改视图中login_handle函数,查看效果

def login_handle(request):
    request.session['uname'] = request.POST['uname']
    # request.session.set_expiry(10)
    # request.session.set_expiry(timedelta(days=5))
    # request.session.set_expiry(0)
    # request.session.set_expiry(None)
    return redirect(reverse('main:index'))
存储session

使用存储会话的方式,可以使用settings.py的SESSION_ENGINE项指定
基于数据库的会话:这是django默认的会话存储方式,需要添加django.contrib.sessions到的INSTALLED_APPS设置中,运行manage.py migrate在数据库中安装会话表,可显示指定为
SESSION_ENGINE='django.contrib.sessions.backends.db'
基于缓存的会话:只存在本地内在中,如果丢失则不能找回,比数据库的方式读写更快
SESSION_ENGINE='django.contrib.sessions.backends.cache'
可以将缓存和数据库同时使用:优先从本地缓存中获取,如果没有则从数据库中获取
SESSION_ENGINE='django.contrib.sessions.backends.cached_db'

使用Redis缓存session

会话还支持文件、纯cookie、Memcached、Redis等方式存储,下面演示使用redis存储
安装包
pip install django-redis-sessions
修改settings中的配置,增加如下项

SESSION_ENGINE = 'redis_sessions.session'
SESSION_REDIS_HOST = 'localhost'
SESSION_REDIS_PORT = 6379
SESSION_REDIS_DB = 0
SESSION_REDIS_PASSWORD = ''
SESSION_REDIS_PREFIX = 'session'

管理redis的命令

启动:sudo redis-server /etc/redis/redis.conf
停止:sudo redis-server stop
重启:sudo redis-server restart
redis-cli:使用客户端连接服务器
keys *:查看所有的键
get name:获取指定键的值
del name:删除指定名称的键

模板

  • 作为Web框架,Django提供了模板,可以很便利的动态生成HTML
  • 模版系统致力于表达外观,而不是程序逻辑
  • 模板的设计实现了业务逻辑(view)与显示内容(template)的分离,一个视图可以使用任意一个模板,一个模板可以供多个视图使用
  • 模板包含:HTML的静态部分、动态插入内容部分
  • Django模板语言,简写DTL,定义在django.template包中
  • 由startproject命令生成的settings.py定义关于模板的值:
    • DIRS定义了一个目录列表,模板引擎按列表顺序搜索这些目录以查找模板源文件
    • APP_DIRS告诉模板引擎是否应该在每个已安装的应用中查找模板
  • 常用方式:在项目的根目录下创建templates目录,设置DIRS值
    DIRS=[os.path.join(BASE_DIR,"templates")]
模板处理

Django处理模板分为两个阶段
Step1 加载:根据给定的标识找到模板然后预处理,通常会将它编译好放在内存中
loader.get_template(template_name),返回一个Template对象
Step2 渲染:使用Context数据对模板插值并返回生成的字符串
Template对象的render(RequestContext)方法,使用context渲染模板
加载渲染完整代码:

from django.template import loader, RequestContext
from django.http import HttpResponse

def index(request):
    tem = loader.get_template('temtest/index.html')
    context = RequestContext(request, {})
    return HttpResponse(tem.render(context))
快捷函数

为了减少加载模板、渲染模板的重复代码,django提供了快捷函数
render_to_string("")
render(request,'模板',context)

from django.shortcuts import render

def index(request):
    return render(request, 'temtest/index.html')
定义模板

模板语言包括:变量、标签 { % 代码块 % }、过滤器、注释{# 代码或html #}

变量

语法:
{{ variable }}

  • 当模版引擎遇到一个变量,将计算这个变量,然后将结果输出
  • 变量名必须由字母、数字、下划线(不能以下划线开头)和点组成
  • 当模版引擎遇到点("."),会按照下列顺序查询:
    字典查询,例如:foo[“bar”]
    属性或方法查询,例如:foo.bar
    数字索引查询,例如:foo[bar]
  • 如果变量不存在, 模版系统将插入’’ (空字符串)
  • 在模板中调用方法时不能传递参数
在模板中调用对象的方法
  • 在models.py中定义类HeroInfo
from django.db import models

class HeroInfo(models.Model):
    ...
    def showName(self):
        return self.hname

在views.py中传递HeroInfo对象

from django.shortcuts import render
from models import *

def index(request):
    hero = HeroInfo(hname='abc')
    context = {'hero': hero}
    return render(request, 'temtest/detail.html', context)

在模板detail.html中调用
{{hero.showName}}

标签
  • 语法:{ % tag % }
  • 作用:在输出中创建文本、控制循环或逻辑、加载外部信息到模板中供以后的变量使用
  • for标签
    { %for ... in ...%}
  • 循环逻辑
    {{forloop.counter}}表示当前是第几次循环
    { %empty%}
    给出的列表为或列表不存在时,执行此处
    { %endfor%}
  • if标签
    { %if ...%}
    逻辑1
    { %elif ...%}
    逻辑2
    { %else%}
    逻辑3
    { %endif%}
  • comment标签
    { % comment % }
    多行注释
    { % endcomment % }
  • include:加载模板并以标签内的参数渲染
    { %include "foo/bar.html" % }
  • url:反向解析
    { % url 'name' p1 p2 %}
  • csrf_token:这个标签用于跨站请求伪造保护
    { % csrf_token %}
    布尔标签:and、or,and比or的优先级高
    block、extends:详见“模板继承”
    autoescape:详见“HTML转义”
过滤器
  • 语法:{ { 变量|过滤器 }},例如{ { name|lower }},表示将变量name的值变为小写输出
  • 使用管道符号 (|)来应用过滤器
  • 通过使用过滤器来改变变量的计算结果
  • 可以在if标签中使用过滤器结合运算符
    if list1|length > 1
  • 过滤器能够被“串联”,构成过滤器链
    name|lower|upper
    过滤器可以传递参数,参数使用引号包起来
    list|join:", "
  • default:如果一个变量没有被提供,或者值为false或空,则使用默认值,否则使用变量的值
    value|default:"什么也没有"
  • date:根据给定格式对一个date变量格式化
    value|date:'Y-m-d'
  • escape:详见“HTML转义”
注释
  • 单行注释
    {#...#}
  • 注释可以包含任何模版代码,有效的或者无效的都可以
    {# { % if foo % }bar{ % else % } #}
    使用comment标签注释模版中的多行内容

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值