概述
官网很多相关文档,省略。。。
一些文档是整理的网上资源,可以参考Yuan先生 的技术博客。
环境
- python: 3.6
- pip: 9.0.1
- django: 1.11.7
安装Django
- 根据自己环境安装pip
- pip install Django
新建django工程
- 创建Django工程(根据自己环境配置修改)
c:\Python36\Scripts\django-admin.exe startproject mysite
mysite:django工程名称
- cd mysite目录下
python manage.py startapp blog
blog:应用名称
启动
python manage.py runserver 8090
目录结构
mysite目录
- manage.py #入口文件
- mysite
- __init__.py #初始化文件
- settings.py #项目主配置文件
- urls.py #路由分配配置文件
- wsgi.py #Django web server(封装socket,解析APP)
blog目录
- __init__.py
- admin.py
- apps.py
- models.py #数据库相关配置(orm)
- tests.py #检测、测试
- views.py #视图函数
settings.py文件配置
定义templates位置
修改TEMPLATES中的DIRS:
'DIRS': [os.path.join(BASE_DIR, 'templates')],
最后效果为
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
创建APP后要在 INSTALLED_APPS 添加相应名称
比如,我这里创建的是blog应用
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'blog', ]
添加mysql数据库连接
DATABASES 中修改
DATABASES = { 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 'ENGINE': 'django.db.backends.mysql', 'NAME': 'DBNAME', 'USER': 'username', 'PASSWORD': 'password', 'HOST': 'db_host', 'PORT': 'port', } }
注释掉错误警告
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', ]
指定静态文件位置(如:js、css、jpg等)
STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'statics') )
开启配置之旅
第一个页面
blog APP下views.py文件添加一个展示数据的函数
from django.shortcuts import render, HttpResponse # Create your views here. def cur_time(request): return HttpResponse('hello world!')
- request: 请求,参数可以自定义,但必须有
- HttpResponse: 返回(当请求成功后要返回的信息)
mysite下的urls.py添加相关路由信息
from blog import views #导入blog下的views模块 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^cur_time', views.cur_time), ]
运行启动命令
python manage.py runserver 8090
浏览器打开 localhost:8090/cur_time 就能看到 hello world!信息了。
添加html文件
之前在 settings.py 配置文件中指定了html文件的路径。所以,django会在 templates 目录下获取html文件,在mysite工程下新建一个 templates 目录,最后整个工程目录机构为:
mysite
- +mysite
- +blog
- +templates
在templates目录下新键一个cur_time.html的html文件并进行编辑,最后代码为
cat views.py
from django.shortcuts import render, HttpResponse # Create your views here. import datetime def cur_time(request): times = datetime.datetime.now() return render(request, 'cur_time.html', {'abc': times})
cat cur_time.html
<!DOCTYPE html> <html lang="en"> <body> 当前时间: </body> </html>
解释
- render: 模版渲染,第一个是请求参数<request>,第二个参数是跳转的url名称,第三个是传递变量 abc
- cur_time.html中的{{}}是jinja2的模版语言,abc 则是render传过来的变量名,注意两边有空格
再次访问浏览器,应该就能看到当前时间了。
HttpResponse与render的区别
- HttpResponse:
- 一个类,后面跟一个字符串,是实例化的一个对象,直接返回给客户端浏览器,django所有返回给客户端浏览器都是通过这个类实现的
- render
- 渲染工作,首先指定一个html文件,解析完成后调用HttpResponse类返回给客户端浏览器,html文件中的变量、{}都不会显示在客户端浏览器上
数据库连接
做一个userInfo信息表单,当用户填入相关信息提交后,数据存入数据库中,并展示信息功能
如前面settings.py中的配置文件指定的数据库
userInfo信息有三个字段:username、sex、email,所以需要在blog中的models.py进行初始化数据库操作
from django.db import models # Create your models here. class UserInfo(models.Model): username = models.CharField(max_length=64) sex = models.CharField(max_length=64) email = models.CharField(max_length=64)
运行初始化数据命令
python manage.py makemigrations
如果报类似如下错误
File "C:\Python36\lib\site-packages\django\db\__init__.py", line 33, in __getattr__ return getattr(connections[DEFAULT_DB_ALIAS], item) File "C:\Python36\lib\site-packages\django\db\utils.py", line 211, in __getitem__ backend = load_backend(db['ENGINE']) File "C:\Python36\lib\site-packages\django\db\utils.py", line 115, in load_backend return import_module('%s.base' % backend_name) File "C:\Python36\lib\importlib\__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "C:\Python36\lib\site-packages\django\db\backends\mysql\base.py", line 30, in'Did you install mysqlclient or MySQL-python?' % e django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module: No module named 'MySQLdb'. Did you install mysqlclient or MySQL-python?
原因:python3不支持MySQLdb,需要在工程mysite下的init.py文件中添加如下内容
import pymysql pymysql.install_as_MySQLdb()
切记
settings.py里的INSTALLED_APPS添加应用名称,否则报错:
File "C:\Python36\lib\site-packages\django\db\models\base.py", line 118, in __new__ "INSTALLED_APPS." % (module, name) RuntimeError: Model class blog.models.UserInfo doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
django不会创建数据库,所以要提前手动创建。
mysite下的urls.py添加路由指向
from django.conf.urls import url from django.contrib import admin from blog import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^cur_time', views.cur_time), url(r'^userInfo', views.userInfo), #添加userInfo路由指向 ]
views.py更新后的内容为:
from django.shortcuts import render, HttpResponse from blog import models #导入models模块,用于数据库操作 # Create your views here. import datetime def cur_time(request): times = datetime.datetime.now() # return HttpResponse('hello world!') return render(request, 'cur_time.html', {'abc': times}) def userInfo(req): if req.method == "POST": u = req.POST.get('username', None) s = req.POST.get('sex', None) e = req.POST.get('email', None) # user={'username':username,"sex": sex, "email": email} models.UserInfo.objects.create( #插入数据 username=u, sex=s, email=e ) user_list = models.UserInfo.objects.all() #从数据库中获取所有数据 return render(req, "index.html", {"user_list": user_list})
index.html文件内容
<!DOCTYPE html> <html lang="en"> <body> <form action="/userInfo/" method="post"> <p>姓名<input type="text" name="username"></p> <p>性别<input type="text" name="sex"></p> <p>邮箱<input type="text" name="email"></p> <p><input type="submit" value="submit"></p> </form> <table border="1px"> <tr> <td>姓名</td> <td>性别</td> <td>邮箱</td> </tr> </table> </body> </html>
表单以 post 提交后跳转到 userInfo 页面。
Django URL(路由系统)
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。
urlpatterns = [ url(正则表达式, views视图函数,参数,别名), ]
参数:
- 一个正则表达式字符串
- 一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
- 可选的要传递给视图函数的默认参数(字典形式)
- 一个可选的name参数
示例
from django.conf.urls import url from django.contrib import admin from blog import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^cur_time', views.cur_time), url(r'^userInfo', views.userInfo), url(r'^articles/2003/$', views.special_case_2003), #url(r'^articles/[0-9]{4}/$', views.year_archive), url(r'^articles/([0-9]{4})/$', views.year_archive), #no_named group url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ]
- URL匹配规则是由上到下,比如url(r’^articles/2003/$’, views.special_case_2003)和url(r’^articles/([0-9]{4})/$’, views.year_archive) 这两条,都是匹配四个数字。如果URL是articles/2003,虽然也属于^articles/([0-9]{4}),但是会优先匹配url(r’^articles/2003/$’, views.special_case_2003)。
- 正则表达式添加()后,指定的views的视图函数也要增加一个自定义的形参,如上面的url(r’^articles/([0-9]{4})/$’, views.year_archive),在views.year_archive中的year_archive视图函数定义时也要添加一个形参:
def year_archive(req,year): return HttpResponse(year)
浏览器访问时就会返回year值
多个(),year_archive要设定多个形参
正则分组(Named groups)
有时候URL传参需要指定值,这里就会用到Python正则表达式的?P
named groups
ret=re.search('(?P\d{3})/(?P \w{3})','weeew34ttt123/ooo') print(ret.group()) print(ret.group('id')) print(ret.group('name'))
from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/(?P[0-9]{4})/$', views.year_archive), url(r'^articles/(?P [0-9]{4})/(?P [0-9]{2})/$', views.month_archive), url(r'^articles/(?P [0-9]{4})/(?P [0-9]{2})/(?P [0-9]{2})/$', views.article_detail), ]
参数名称(name param)
urlpatterns = [ url(r'^index',views.index,name='bieming'), ]
def index(req): if req.method=='POST': username=req.POST.get('username') password=req.POST.get('password') if username=='alex' and password=='123': return HttpResponse("登陆成功") return render(req,'index.html')
<!DOCTYPE html> <html lang="en"> <body> <form action="{% url 'bieming' %}" method="post"> 用户名:<input type="text" name="username"> 密码:<input type="password" name="password"> <input type="submit" value="submit"> </form> </body> </html>
导入其他URLconfs
#At any point, your urlpatterns can “include” other URLconf modules. This #essentially “roots” a set of URLs below other ones. #For example, here’s an excerpt of the URLconf for the Django website itself. #It includes a number of other URLconfs: from django.conf.urls import include, url urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^blog/', include('blog.urls')), ]
Django Views(视图函数)
浏览器 –(Rquest)–> WebServer
浏览器 <–(Response)– WebServer
http请求中产生两个核心对象:
- http请求: HttpRequest对象
- http响应: HttpResponse对象
HttpRequest对象的属性和方法:
# path: 请求页面的全路径,不包括域名 # # method: 请求中使用的HTTP方法的字符串表示。全大写表示。例如 # # if req.method=="GET": # # do_something() # # elseif req.method=="POST": # # do_something_else() # # GET: 包含所有HTTP GET参数的类字典对象 # # POST: 包含所有HTTP POST参数的类字典对象 # # 服务器收到空的POST请求的情况也是可能发生的,也就是说,表单form通过 # HTTP POST方法提交请求,但是表单中可能没有数据,因此不能使用 # if req.POST来判断是否使用了HTTP POST 方法;应该使用 if req.method=="POST" # # # # COOKIES: 包含所有cookies的标准Python字典对象;keys和values都是字符串。 # # FILES: 包含所有上传文件的类字典对象;FILES中的每一个Key都是标签中 name属性的值,FILES中的每一个value同时也是一个标准的python字典对象,包含下面三个Keys: # # filename: 上传文件名,用字符串表示 # content_type: 上传文件的Content Type # content: 上传文件的原始内容 # # # user: 是一个django.contrib.auth.models.User对象,代表当前登陆的用户。如果访问用户当前 # 没有登陆,user将被初始化为django.contrib.auth.models.AnonymousUser的实例。你 # 可以通过user的is_authenticated()方法来辨别用户是否登陆: # if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware # 时该属性才可用 # # session: 唯一可读写的属性,代表当前会话的字典对象;自己有激活Django中的session支持时该属性才可用。 #方法 get_full_path(), 比如:http://127.0.0.1:8000/index33/?name=123 ,req.get_full_path()得到的结果就是/index33/?name=123 req.path:/index33
注意一个常用方法:request.POST.getlist(‘’)
HttpResponse对象:
对于HttpRequest对象来说,是由django自动创建的,但是,HttpResponse对象就必须我们自己创建。每个view请求处理方法必须返回一个HttpResponse对象。
HttpResponse类在django.http.HttpResponse
在HttpResponse对象上扩展的常用方法:
页面渲染: render()(推荐)
render_to_response(), 页面跳转: redirect("路径") locals(): 可以直接将函数中所有的变量传给模板url.py
url(r"login", views.login), url(r"yuan_back", views.yuan_back),
views.py
def login(req): if req.method=="POST": if 1: # return redirect("/yuan_back/") name="yuanhao" return render(req,"my backend.html",locals()) return render(req,"login.html",locals()) def yuan_back(req): name="duanruijun" return render(req,"my backend.html",locals())
login.html
<form action="/login/" method="post"> <p>姓名<input type="text" name="username"></p> <p>性别<input type="text" name="sex"></p> <p>邮箱<input type="text" name="email"></p> <p><input type="submit" value="submit"></p> </form>
my backend.html
<h1>用户{{ name }}你好</h1>
#总结: render和redirect的区别: # 1 if render的页面需要模板语言渲染,需要的将数据库的数据加载到html,那么所有的这一部分 # 除了写在yuan_back的视图函数中,必须还要写在login中,代码重复,没有解耦. # 2 the most important: url没有跳转到/yuan_back/,而是还在/login/,所以当刷新后 # 又得重新登录.
模版
什么是模版语言
简单说就是html+逻辑控制语句。
模版常用用例 – 万能的句号点(.)
urls.py
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index),
views.py
from django.shortcuts import render import datetime # Create your views here. def index(req): class profile(object): def __init__(self, name, age): self.name = name self.age = age s1 = [1,22,333] s2 = {'username': 'duanrj', 'email': '123@qq.com'} s3 = datetime.datetime.now() s4 = profile("Bob", "20") s5 = 'hello' s6 = 6 s7 = [] s8 = "跳转" return render(req, 'index.html', { 'value1': s1, 'value2': s2, 'value3': s3, 'value4': s4, 'value5': s5, 'value6': s6, 'value7': s7, 'value8': s8, })
index.html
<!DOCTYPE html> <html lang="en"> <body> ====打印列表第n个值====
{{ value1.2 }}
====打印dict的username值====
{{ value2.username }}
打印对象的属性
{{ value3.year }}
====打印对象的属性2====
{{ value4 }}
{{ value4.name }}
{{ value4.age }}
====模版语言中的遍历==== {% for i in obj %}{{ forloop.counter }}:{{ i }}
//索引从1开始{{ forloop.counter0 }}:{{ i }}
//索引从0开始 {% endfor %} ====filter:小写转为大写====
{{ value5 | upper }}
{{ value5 | lower }}
{{ value5 | capfirst }}
{{ value5 | first }}
====算数运算====
{{ value6 | add:5 }}
====为空时提示信息====
{{ value7 | default:'空的' }}
====当成普通字符串处理====
{{ value8 }}
如果想把类似于html 标签的都渲染出来可以这样
{% autoescape off %} {{ value8 }} {% endautoescape %} 也可以用safe {{ obj|safe }} ====禁止render==== {% verbatim %} {{ name }} {% endverbatim %} </body> </html>
filter
作用于简单操作,简化前后端开发重复性工作