-
安装虚拟环境:
mkvirtualenv django_demo -p python3
-
安装django安装包(联网安装):
pip install django==2.2 -i https://pypi.douban.com/simple
-
创建django工程(项目):
django-admin startproject 项目名称[目录名称]
例如:
django-admin startproject django_demo
第一次创建项目以后的目录结构:
django_demo/ ├── django_demo/ # 开发主应用,这里将来主要保存着项目的核心代码 │ ├── __init__.py # 项目初始化文件 │ ├── settings.py # 项目核心配置文件 │ ├── urls.py # 项目核心路由配置文件 │ └── wsgi.py # wsgi对象初始化文件 └── manage.py # 命令行管理项目的工具[脚手架]
进入项目根目录,通过mange.py启动django项目。
cd ~/Desktop/django_demo/
python manage.py runserver
django项目基于MVT思想搭建的框架.所以django会有固定的目录结构编写对应的代码.
M: Model, 模型, 是一个类, 类里面所有的方法都是用来操作数据库的.
V: View,视图, 也是一个类, 类里面提供了所有关于界面中的代码,一般都是由View加载模型和页面的前端代码
T: Template,模板,是一个前端html文件, 里面主要是编写html, css, js代码
MVT来源于MVC思想.
M: Model, 模型,是一个类,里面所有的方法都是用来操作数据库的.
V: View,视图, 是一个文件, 里面主要编写前端代码.
C: Controller,控制器,是一个类,里面所有的方法都是关于界面的代码,一般都是由controller加载模型和视图的前端代码
02. 创建子应用
python manage.py startapp 子应用目录
安装子应用之前需要了解项目的整个目录。
admin.py 文件跟网站的后台管理站点配置相关。
apps.py 文件用于配置当前子应用的相关信息。
migrations 目录用于存放数据库迁移历史文件。
models.py 文件用户保存数据库模型类。
tests.py 文件用于开发测试用例,编写单元测试。
views.py 文件用于编写Web应用视图。
安装子应用打开项目的配置文件,settings.py。找到INSTALLED_APPS配置项:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # 注册自己的子应用 'user', ]
03-创建视图
-
在子应用的视图文件views.py中,编写视图函数,例如:
from django.shortcuts import render from django.http import HttpResponse # Create your views here. # 视图函数 def index(request): data = "<h1>hello world!</h1>" return HttpResponse(data) def login(request): data = "登录页面!" return HttpResponse(data)
-
视图创建完成以后,需要指定路由,用户才能访问到视图中的内容。
2.1 在子应用目录下创建当前子应用所属的路由文件urls.py,编写代码如下:
# 子应用的路由文件 from django.urls import path # 引入视图文件才能访问指定视图函数 from . import views urlpatterns = [ # path("访问路由的后半段",views.视图函数名称), path('info/',views.index), path("login/",views.login), ]
2.2 在项目的主应用django_demo下的urls.py总路由文件中,加载子应用的路由文件所有路由。
from django.urls import path,include from django.contrib import admin urlpatterns = [ path('admin/', admin.site.urls), # 把子应用的路由文件加载进来 # path("访问路由的前半段",include("子应用目录名.urls")) path("user/",include("user.urls")), ]
04-配置文件
django在安装到当前环境中时,默认已经有了默认配置 django.conf.global_settings.py,这份配置支撑了django项目的运行.
但是这份配置我们作为开发者不能修改!!!所以django提供了在主应用目录下的settings.py,是django 项目的核心配置文件。
settings.py的配置信息都是可以允许开发者修改.将来如果我们出现修改配置项,都在settings.py配置文件中,
如果和global_settings.py配置项重复了,则django会默认优先采用settings.py里面的配置.
""" Django settings for django_demo project. Generated by 'django-admin startproject' using Django 1.11.11. For more information on this file, see https://docs.djangoproject.com/en/1.11/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.11/ref/settings/ """ import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) # 根目录 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! # 秘钥 SECRET_KEY = 'u319rt09av$^zblh^%*913jl_4q-je@%7s4-k2+@8b7#rx$tfh' # SECURITY WARNING: don't run with debug turned on in production! # 开启调试模式 DEBUG = True # 在DEBUG=False,就需要设置允许哪些客户端访问可以访问到项目 ALLOWED_HOSTS = [] # Application definition # 安装子应用 INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # 注册自己的子应用 'users.apps.UsersConfig', ] # 中间件 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] # 项目的总路由文件 ROOT_URLCONF = 'django_demo.urls' # 视图模板的配置信息 TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] # http服务器类 WSGI_APPLICATION = 'django_demo.wsgi.application' # Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases # 数据库 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } # Password validation # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators # django默认提供了用户管理管理功能,用户管理里面内置了用户的验证功能 AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/1.11/topics/i18n/ # 设置项目的默认语言 LANGUAGE_CODE = 'en-us' # 设置项目的默认时区 TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.11/howto/static-files/ # 静态资源访问url路径[图片/js/css路径] STATIC_URL = '/static/'
访问静态资源与项目的路由无关,是在settings的STATICFILES_DIRS和STATIS_URL里面单独进行配置的。
05-设置静态资源
-
在项目配置文件中STATIC_URL下面添加一个配置项
STATICFILES_DIRS和STATIS_URL
,代码:# 静态资源实际存储目录,可以有多个,这样设置的好处,可以把不同地方的静态资源进行存储 STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ]
-
在项目根目录下创建指定名称的自定义目录名
static
(上面配置项中指定的)。项目根目录/ ├── django_demo/ │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── manage.py ├── static/ # 项目静态资源目录 └── dog.png
-
启动项目,访问项目的静态资源dog.png
http://127.0.0.1/static/dog.png
效果:
用户访问视图的url地址 = 总路由的前半段路由+子应用的后半段路由
总结:
Django路由解析匹配的顺序,django先读取主应用[Desktop/demo/demo]下面的urls总路由文件中的路由代码,然后总路由中如果有include函数,则自动帮我们根据include中指定的路径访问子应用下的urls路由文件中。
最终访问视图函数的路由地址:
http://127.0.0.1:8000/总路由文件中的路由前缀/子应用路由文件中的路由地址
子应用的路由书写规范必须要是:
urlpatterns=[ path("^路由地址/$",视图函数); ]
主应用中的路由书写规范必须要是:
urlpatterns=[ path("路由前缀", include("子应用的目录名.urls")), ]
提示:
django 2.0以前,声明视图的url路由,使用函数url
django 2.0以后,声明视图的url路由,使用函数path和re_path
path函数的使用
子应用user的urls.py,代码:
from django.urls import path urlpatterns = [ # path("访问url子路径/","视图函数"), path("login/",views.login), ]
主应用urls.py,代码:
from django.urls import path,include urlpatterns = [ # ... # path('访问url前缀/', include("子应用包名.urls")), path('user/', include("user.urls")), ]
re_path函数的使用
子应用user的urls.py,代码:
from django.urls import re_path urlpatterns = [ # path("访问url子路径/", "视图函数"), re_path("info/(?P<pk>d+)/(?P<mobile>1[3-9]d{9})/",views.info), ]
主应用urls.py,代码:
from django.urls import path,include urlpatterns = [ # ... # path('访问url前缀/', include("子应用包名.urls")), path('user/', include("user.urls")), ]
此时,在路由中使用re_path标记的正则,可以通过<变量>传递到视图中,让视图直接使用.
user/views.py,代码:
def info(request, pk,mobile): data = "id=%s. mobile=%s 的个人中心" % (pk,mobile) return HttpResponse(data)
路由就是在接收客户端请求以后,分析请求中的路径,到urls中进行正则的匹配,然后把客户端请求转发给匹配到的视图函数中。【 完成了客户端访问路径和web项目中的应用程序(视图)的 一 一 绑定关系 】
django本身执行视图的顺序是先找到路由,根据路由地址找到视图。
反解析:就是在视图中通过路由的命名空间和路由的别名获取对应的路由地址,和上面的顺序相反。
06.1-路由反解析
reverse()是一个函数,可以帮我们自动获取视图函数对应的路由地址。
reverse反解析分三个步骤:
-
需要在总路由文件中,给对应的子应用目录声明命名空间,作用是:区分路由。
path("user/",include("user.urls",namespace="user")),
-
需要在子应用user路由文件urls.py中, 给对应视图的路由地址(后半段)声明别名,作用是:区分路由,避免重复
from django.urls import path,re_path from . import views app_name='user' # 注意,声明当前路由文件是属于哪个命名空间 urlpatterns = [ # path("访问url路径","视图函数","访问别名"), # .. path("test/", views.test, name="test"), ]
-
在视图user/views.py中使用reverse必须完成前面两个步骤。
from django.urls import reverse def test(request): # 路由反解析函数reverse的参数就是视图函数名 # reverse("总路由中include设置的命名空间:子应用下的include的name参数") result = reverse("user:test") return HttpResponse(result)
附加说明:
reverse也可以生成附带参数的url地址.我们服务端很少使用,一般都是前端自动生成.
07-请求[request]
学习过程中,我们可以借助一个网上开源免费的postman工具,来完成http请求的自定义.
下载地址: https://www.getpostman.com/downloads/
request有提供了5种方式给我们获取客户端发送过来的数据
07.1-提取URL的特定部分
两个简便的方式可以完成:
-
未命名参数
路由文件中通过正则的小括号提取需要的路由信息:
url(r"^req/(d+)/([a-z]+)$",views.req),
视图函数中request参数后面新增对应数量的形参用于接收数据
def req(request,num,city): print(num) print(city) return HttpResponse("django")
访问:http://127.0.0.1:8000/test/req/11/guangzhou
效果:
-
命名参数
在未命名参数 的左边圆括号后面加上?P<参数名称>.
url(r"^req2/(?P<num>d+)/(?P<city>[a-z]+)$",views.req2),
在视图中获取命名参数
def req2(request,city,num): print(num) print(city) return HttpResponse("django")
07.2-查询字符串(query string)
-
request.GET.get() 获取单个查询字符串的参数 ,支持两种写法。
username = request.GET.get("username") age = request.GET["age"]
-
request.GET.getlist() 获取多个查询字符串的参数
like = request.GET.getlist("like")
07.3-请求体(body)
-
表单类型数据,只能获取method="post"的数据
request.POST.get("表单项的name值") # 获取一个值 request.POST.getlist("表单项的name值") # 获取多个值
-
非表单类型数据[ajax]
import json json_bytes = request.body json_str = json_bytes.decode() # python3.6以后可以不用执行 json_dict = json.loads(json_str)
07.4-请求头信息(header)
-
自定义请求头信息
request.META["HTTP_名称大写"]
07.5-其他的request请求信息
-
request.method
-
request.user
-
request.FILES
08-响应
08.1-内容响应
-
响应html文本信息
return HttpResponse(content="响应内容",content_type="内容类型,常见的有application/json,text/text",status="状态码,常见的有:404,200,201,204") # 还可以设置响应的响应头信息 response = HttpResponse() response["company"] = "我的公司" return response
-
响应其他信息[json]
# 把字典数据响应成json格式数据 dict1 = { "name":"xiaobai", "age":21 } # return HttpResponse(str(dict1),content_type="application/json") return JsonResponse(dict1) # 如果要响应的数据格式是列表. list2 = ["xiaoming","xiaohei"] return JsonResponse(list2)
08.2-页面跳转
也叫页面重定向。
from django.shortcuts import redirect def response_redirect(request): # 页面重定向 return redirect("/test/response_text/") # return redirect("http://www.baidu.com")
扩展内容
前后端传递数据时,数据的格式可以是html文本格式,json格式,xml格式。当然不同平台,不同的编程语言也是如此。
-
文本格式:
username=小明&password=123456
-
json格式:
{ "username":"小明", "password":"123456", "sex":"女" }
-
xml格式:
xml格式类似于html,也是采用标签来表达数据的,但是不一样的是,xml的所有标签都需要开发者自定义。
现在使用这种格式的公司很少了。
<xml version="1.0" charset="utf-8"> <username>小明</username> <password>123456</password> <sex>女</sex> </xml>
09-会话控制技术
http协议是一种无状态的短连接协议.
这个意味着, 如果有两个http请求来到django里面,我们django分不出来,这两个请求是不是同一个用户发送出来到的.
会话跟踪技术就是用于解决项目中无法识别用户身份的技术.
会话[Session], 表示客户端与浏览器之间的一次通信.
会话开始: 从用户输出当前url开始
会话结束: 从用户关闭访问代理软件[浏览器/uc/app]以后
会话控制: 使用特定的web技术,实现从会话开始到会话结束这段时间,记录/限制用户在网站中的行为和操作.
web开发中常用的会话控制技术: cookie / session / 本地存储 / token授权码
Cookie
cookie中文翻译:"小饼干",意思就是说,把用户的身份记录状态作为一个字符串,保存到用户的访问代理软件中.
cookie在pc端网站中,就是放置在浏览器里面的一个键值对信息.
cookie保存到客户端中,默认情况不会长期有效, 会有一个指定的时间的有效期.
cookie默认情况下,如果不设置有效期,默认为会话期内有效.也就是说当有用户关闭了访问代理软件以后,则cookie就会消失掉
cookie的设置,我们也可以设置为指定有效时间
cookie的原理:
设置Cookie
# url path("set_cookie/", views.set_cookie),
def set_cookie(request): """设置一个cookie信息保存到客户端""" response = HttpResponse() """ 通过响应里面提供的set_cookie就可以设置 set_cookie(key=变量名,value=变量值,max_age=有效期) """ response.set_cookie("name","xiaoming") return response
获取Cookie
# url path("get_cookie/", views.get_cookie),
def get_cookie(request): """获取一个来自于客户端的cookie""" """通过request.COOKIES""" # 获取来自客户端的所有cookie[ cookie有域名限制,所以服务端只能获取当前客户端对应域名端口的cookie ] print(request.COOKIES) # {'name': 'xiaoming'} # 获取指定名称的cookie print(request.COOKIES.get("name")) return HttpResponse("ok")
设置cookie的有效期
def set_cookie(request): """设置一个cookie信息保存到客户端""" response = HttpResponse() """ 通过响应里面提供的set_cookie就可以设置 set_cookie(key=变量名,value=变量值,max_age=有效期) """ # 设置一个cookie,有效时间为"会话期" response.set_cookie("name","xiaoming") # 设置一个cookie,有效时间为30秒 response.set_cookie("is_login","1", max_age=30) return response def get_cookie(request): """获取一个来自于客户端的cookie""" """通过request.COOKIES""" # 获取来自客户端的所有cookie[ cookie有域名限制,所以服务端只能获取当前客户端对应域名端口的cookie ] print(request.COOKIES) # {'name': 'xiaoming'} # 获取指定名称的cookie print(request.COOKIES.get("name")) # 获取具有有效期的cookie is_login = request.COOKIES.get("is_login") return HttpResponse("当前cookie的值=%s" % is_login)
注意: 删除cookie就是设置一个同名的cookie,并设置max_age=-1或0
案例: 基于cookie完成一个用户登录功能
urls.py,代码:
path("cookie/login/", views.login), path("cookie/center/", views.center),
views.py,代码:
def login(request): """登录页面""" if request.method == "GET": html = """ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href=""> </head> <body> <form action="" method="post"> 账号: <input type="text" name="username"><br><br> 密码: <input type="text" name="password"><br><br> <input type="submit" value="登录"> </form> </body> </html> """ return HttpResponse(html) else: username = request.POST.get("username") password = request.POST.get("password") # 从数据库中查询账号, 然后密码进行比较 username2 = "root" password2 = "123456" response = HttpResponse() if username==username2 and password == password2: """登录成功""" # 保存登录状态 response.set_cookie("username","xiaoming") response.set_cookie("is_login","1") response.status_code = 302 response["Location"] = "/cookie/center/" return response else: """登录失败""" # 返回上一页 print("hello") return redirect("/cookie/login/") def center(request): """个人中心""" """必须是登录用户才可以访问!""" if not request.COOKIES.get("is_login"): return redirect("/cookie/login") username = request.COOKIES.get("username") return HttpResponse("欢迎回来~%s" % username)
从上面可以看到:
cookie,可以把数据保存在客户端里面,这样可以减轻服务器的存储压力,同时因为数据是保存在了客户端,
所以很容易被别人查看到或者修改/删除/通过浏览器禁用cookie
基于这点, cookie是不安全的.只能保存一些通用的.不怕别人修改的数据.对于用户的隐私不要使用cookie来保存
Session
与cookie相对来说比较安全的技术.session是一种保存用户状态信息到服务器里面的技术.
实现的原理:
设置session
def set_session(request): # 设置session request.session["username"] = "xiaohei" return HttpResponse("设置session")
获取session
def get_session(request): # 获取session print( request.session["username"] ) return HttpResponse("获取session")
删除session
def del_session(request): # 删除session del request.session["username"] return HttpResponse("删除session")