· Django流程
· Django url
· Django view
· Django form
MTV模式
注明的MVC模式:所谓MVC就是把web应用分为模型(M),控制器(C),视图(V)三层;他们之间以一种插件似的,松耦合的方式连接在一起.
模型负责业务对象与数据库的对象(ORM),视图负责与用户的交互(页面),控制器(C)接受用户的输入调用模型和视图完成用户的请求.
注: 什么是松耦合:简单的说,松耦合是一个 重要的保证互换性的软件开发方法.
Django的MTV模式本质上与MVC模式没有什么差别,也是各组件之间为了保持松耦合关系,只是定义上有些许不同,Django的MTV分别代表:
Model(模型):负责业务对象与数据库的对象(ORM)
Template(模版):负责如何把页面展示给用户
View(视图):负责业务逻辑,并在适当的时候调用Model和Template
此外,Django还有一个url分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。URL的家在是从配置文件中开始。
参数说明:
· 一个正则表达式字符串
· 一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
· 可选的要传递给视图函数的默认参数(字典形式)
· 一个可选的name参数
下面是一个示例URLconf:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/([0-9]{4})/$', views.year_archive),
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),
]
注释:
· To capture a value from the URL, just put parenthesis around it.
(从URL中捕获值,只是把它周围的括号。)
^articles
, not ^/articles
.(没有必要添加一个领先的削减,因为每个URL。例如,它的^的文章,而不是^ /文章。)
· The 'r' in front of each regular expression string is optional but recommended. It tells Python that a string is “raw” – that nothing in the string should be escaped. See Dive Into Python’s explanation.
(每个正则表达式字符串前面的'R'是可选的,但建议。它告诉Python字符串是“原始” - 没有什么字符串中应该进行转义。见深入Python的解释。)
Example requests:
· A request to /articles/2005/03/
would match the third entry in the list. Django would call the functionviews.month_archive(request, '2005', '03')
.
(请求/文章/ 2005/03 /匹配列表中的第三项,Django的将调用函数views.monthly存档(要求下,'2005','03')。)
· /articles/2005/3/ would not match any URL patterns, because the third entry in the list requires two digits for the month.
(/文章/ 2005/3 /不匹配任何URL模式,因为第三个条目列表中需要两个数字的月. .)
· /articles/2003/
would match the first pattern in the list, not the second one, because the patterns are tested in order, and the first one is the first test to pass. Feel free to exploit the ordering to insert special cases like this. Here, Django would call the function views.special_case_2003(request)
(/文章/ 2003 /将匹配第一个模式列表中,没有第二个,因为模式是为了进行测试.第一个是第一个测试通过,随时利用顺序插入这样的特殊情况,这里,Django所说的功能的观点。特殊情况2003(请求))
· /articles/2003 would not match any of these patterns, because each pattern requires that the URL end with a slash.
(/文章/ 2003不匹配任何这些模式,因为每个模式要求以斜线结尾的URL。)
· /articles/2003/03/03/
would match the final pattern. Django would call the functionviews.article_detail(request, '2003', '03', '03')
.
(/文章/ 2003/03/03 /将最终的模式相匹配,Django将调用函数views.article细节(的要求,'2003','03','03')。)
Named groups
· The above example used simple, non-named regular-expression groups (via parenthesis) to capture bits of the URL and pass them as positional arguments to a view. In more advanced usage, it’s possible to use named regular-expression groups to capture URL bits and pass them as keyword arguments to a view.
(上面的例子中使用简单,non-named正则表达式组(通过括号)捕捉到的URL,将他们作为一个视图的位置参数。在更高级的用法,可以使用指定的正则表达式组捕获的URL)
· In Python regular expressions, the syntax for named regular-expression groups is (?P<name>pattern)
, where name
is the name of the group and pattern
is some pattern to match.
(在Python正则表达式,命名正则表达式组的语法是(?P <名>的模式),其中name是组的名称和模式是某种模式相匹配。)
· Here’s the above example URLconf, rewritten to use named groups:
(下面是上面的例子中的URLconf,改写使用命名组:)
import re
ret=re.search('(?P<id>\d{3})/(?P<name>\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<year>[0-9]{4})/$', views.year_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]
This accomplishes exactly the same thing as the previous example, with one subtle difference: The captured values are passed to view functions as keyword arguments rather than positional arguments. For example:
(这完成了前面的例子一样,有一个微妙的差异:捕获的值传递给视图函数作为关键字参数而不是位置参数。例如:)
A request to /articles/2005/03/ would call the function views.month_archive(request, year='2005',month='03'), instead of views.month_archive(request, '2005', '03').
(的请求/用品/ 2005/03/会调用函数views.monthly存档(要求,今年='2005',一个月='03'),而不是views.monthly存档(要求下,'2005','03')。)
A request to /articles/2003/03/03/
would call the function views.article_detail(request, year='2003',month='03', day='03')
.
(请求/文章/ 2003/03/03 /将调用该函数的观点。文章细节(请求,年= ' 2003 ',月=“03”,天=“03”)。)
In practice, this means your URLconfs are slightly more explicit and less prone to argument-order bugs – and you can reorder the arguments in your views’ function definitions. Of course, these benefits come at the cost of brevity; some developers find the named-group syntax ugly and too verbose.
(在实践中,这意味着你的URLconf稍微更明确,不容易参数顺序错误 - 你可以在你的意见'函数定义重新排序的参数。当然,这些优点来在简短的费用;一些开发商找到命名组的语法丑陋,太冗长。)
常见写法实列:
Each captured argument is sent to the view as a plain Python string, regardless of what sort of match the regular expression makes. For example, in this URLconf line:
(每个捕获的参数发送到视图作为普通的Python字符串,无论什么样的匹配正则表达式做。例如,在该URL配置行:)
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
...the year
argument passed to views.year_archive()
will be a string,
(…参数传递给视图。年存档()将是一个字符串,)
not an integer, even though the [0-9]{4}
will only match integer strings.
(不是整数,即使[0-9]{4}将只匹配整数串。)
Including other URLconfs :
At any point, your urlpatterns
can “include” other URLconf modules. This essentially “roots” a set of URLs below other ones.
(在任何时候,您的网址模式可以“包含”其他的URLconf模块。这实质上是“根”的一套低于其他的网址。)
For example, here’s an excerpt of the URLconf for the Django website itself. It includes a number of other URLconfs:
(例如,这里的URL配置为Django的网站本身的摘录。它包括许多其他URL配置的:)
from django.conf.urls import include, url
urlpatterns = [
# ... snip ...
url(r'^community/', include('django_website.aggregator.urls')),
url(r'^contact/', include('django_website.contact.urls')),
# ... snip ...
]
URLconfs have a hook that lets you pass extra arguments to your view functions, as a Python dictionary.
(URLconf中有一个挂钩,可以传递额外的参数给您的视图功能,作为一个Python字典。)
The django.conf.urls.url()
function can take an optional third argument which should be a dictionary of extra keyword arguments to pass to the view function.
(该django.conf.urls.url()函数可以接受这应该是额外的参数的字典传递给视图功能可选的第三个参数。)
For example:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]
In this example, for a request to /blog/2005/, Django will call views.year_archive(request, year='2005',foo='bar').
(在本例中,请求/博客/ 2005 / Django将调用视图。年存档(请求,年= ' 2005 ',foo = '参数')。)
This technique is used in the syndication framework to pass metadata and options to views.
(这种技术用于聚合框架通过元数据和视图选项。)
Dealing with conflicts
( 应对冲突)
It’s possible to have a URL pattern which captures named keyword arguments, and also passes arguments with the same names in its dictionary of extra arguments. When this happens, the arguments in the dictionary will be used instead of the arguments captured in the URL.
(可以有一个URL模式捕获关键字参数,并通过参数具有相同名字的字典的额外参数。当这种情况发生时,将使用参数在字典里而不是参数捕获)
需要注意的是,当你加上参数时,对应函数views.index必须加上一个参数,参数名也必须命名为a,如下:
if auth():
obj=model.user.filter()
{'obj':obj}
name param
urlpatterns = [
url(r'^index',views.index,name='bieming'),
url(r'^admin/', admin.site.urls),
# url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/([0-9]{4})/$', views.year_archive),
# 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),
]
###################
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">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{# <form action="/index/" method="post">#}
<form action="{% url 'bieming' %}" method="post">
用户名:<input type="text" name="username">
密码:<input type="password" name="password">
<input type="submit" value="submit">
</form>
</body>
</html>
#######################
http请求中产生两个核心对象:
# 获取提交方式
request.method
if request.method == "POST":
times = time.time()
return render(request,'index.html')
# 获取前端post提交的数据
request.POST.get('username')
# 获取域名后路径
get_full_path()
例:http://127.0.0.1:8000/index33/?name=123 ,req.get_full_path()得到的结果就是/index33/?name=123
def test(request):
# 往前端写入字符串
return HttpResponse("xxx")
# 跳转路径
return redirect('/index/')
# 渲染HTML文件两种方式
return render(reuqest, "test.html")
return render_to_response('text.html')
# 可以直接将函数中所有的变量传给模板
return render(reuqest, "test.html",locals())
# 可以根据通过字典的方式往前端传值,取值输入key即可
return render(reuqest, "test.html",{'shijie':'你好'})
# 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都是<input type="file" name="" />标签中 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支持时该属性才可用。
一、基础form提交
比如写一个计算 a和 b 之间的简单应用,网页上这么写.
<!DOCTYPE html>
<html>
<body>
<p>请输入两个数字</p>
<form action="/add/" method="POST"><input type="text" name="a"> <input type="text" name="b">
<input type="submit" value="提交">
</form>
</body>
</html>
把这些代码保存成一个index.html,放在 templates 文件夹中。
网页的值传到服务器是通过 <input> 或 <textarea>标签中的 name 属性来传递的,在服务器端这么接收:
from django.http import HttpResponse
from django.shortcuts import render
def index(request):
return render(request, 'index.html')
def add(request):
a = request.POST.GET('a')
b = request.POST.GET('b')
a = int(a)
b = int(b)
return HttpResponse(str(a+b)
但是,比如用户输入的不是数字,而是字母,就出错了,还有就是提交后再回来已经输入的数据也会没了。
那么,当然如果我们手动将输入之后的数据在 views 中都获取到再传递到网页,这样是可行的,但是很不方便,所以 Django 提供了更简单易用的 forms 来解决验证等这一系列的问题。
二、Django Forms应用
1、简单案例一
在app01下新建一个文件forms.py
from django import forms
class AddForm(forms.Form):
a = forms.IntegerField()
b = forms.IntegerField()
(视图函数) views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django.shortcuts import render,HttpResponse
from app01.forms import AddForm
def index(request):
if request.method == 'POST':# 当提交表单时
# form 包含提交的数据
form = AddForm(request.POST)
# 如果提交的数据合法
if form.is_valid():
a = form.cleaned_data['a']
b = form.cleaned_data['b']
return HttpResponse(str(int(a) + int(b)))
# 当正常访问时
else:
form = AddForm()
return render(request, 'index.html', {'form': form})
对应的模板文件 index.html
<form method='post'>
{% csrf_token %}
{{ form }}
<input type="submit" value="提交">
</form>
这个简单的案例,大家不知道有没有看出其中的蹊跷呢,仔细观察,form类给我做了验证,用户输入错了会弹出报错信息
2丶简单案例二
from django.db import models
# Create your models here.
class BookType(models.Model):
caption = models.CharField(max_length=64) #最大长度
class Book(models.Model):
name = models.CharField(max_length=64) #最大长度
pages = models.IntegerField()
price = models.DecimalField(max_digits=10,decimal_places=2)
pubdate = models.DateField()
book_type = models.ForeignKey('BookType')
#当然min_length --最小长度
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django.shortcuts import render
from app01.forms import Form1
def form1(request):
if request.method == 'POST':
# 获取请求内容做验证
f = Form1(request.POST)
if f.is_valid():
print(f.cleaned_data)
else:
print(type(f.errors),f.errors)
return render(request,'form1.html',{'error':f.errors,'form':f})
else:
f = Form1()
return render(request,'form1.html',{'form':f})
在app01下新建一个文件forms.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import forms
from app01 import models
class Form1(forms.Form):
# 用户名,给该标签添加一个class属性,还有空值的报错信息修改
user = forms.CharField(
widget=forms.TextInput(attrs={'class': 'c1'}),
error_messages={'required': '用户名不能为空'},)
# 密码定义最大长度和最小长度
pwd = forms.CharField(max_length=4,min_length=2)
# 邮箱定义错误信息,required为空值错误信息,invalid为邮箱匹配错误信息
email = forms.EmailField(error_messages={'required': '邮箱不能为空', 'invalid': '邮箱格式错误'})
# 生成多行文本编辑框
memo = forms.CharField(widget=forms.Textarea())
# 下拉菜单实时更新数据库
user_type_choice = models.BookType.objects.values_list('id','caption')
book_type = forms.CharField(widget=forms.widgets.Select(choices=user_type_choice,attrs={'class': "form-control"}))
def __init__(self,*args, **kwargs):
super(Form1, self).__init__(*args, **kwargs)
self.fields['book_type'] = forms.CharField(
widget=forms.widgets.Select(choices=models.BookType.objects.values_list('id','caption'),attrs={'class': "form-control"}))
HTML页面(form1.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.input-group{
position: relative;
padding: 20px;
width: 250px;
}
.input-group input{
width: 200px;
display: inline-block;
}
.input-group span{
display: inline-block;
position: absolute;
height: 12px;
font-size: 8px;
border: 1px solid red;
background-color: darksalmon;
color: white;
top: 41px;
left: 20px;
width: 202px;
}
</style>
</head>
<body>
<form action="/form1/" method="post">
<div class="input-group">
{{ form.user }}
{% if error.user.0 %}
<span>{{ error.user.0 }}</span>
{% endif %}
</div>
<div class="input-group">
{{ form.pwd }}
{% if error.pwd.0 %}
<span>{{ error.pwd.0 }}</span>
{% endif %}
</div>
<div class="input-group">
{{ form.email }}
{% if error.email.0 %}
<span>{{ error.email.0 }}</span>
{% endif %}
</div>
<div class="input-group">
{{ form.memo }}
{% if error.memo.0 %}
<span>{{ error.memo.0 }}</span>
{% endif %}
</div>
<div class="input-group">
{{ form.book_type }}
{% if error.book_type.0 %}
<span>{{ error.book_type.0 }}</span>
{% endif %}
</div>
<div>
<input type="submit" value="提交">
</div>
</form>
</body>
</html>