学习极客学院视频。
Django 基础
软件安装
1、python2.7.3
2、pycharm(python编译器)
3、下载Django 1.8.6 ,在文件目录下使用python setup.py install。
报错no model named setuptools。因为Windows环境下Python默认是没有安装setuptools这个模块的,这也是一个第三方模块,那么需要下载setuptools。链接:https://pypi.python.org/pypi/setuptools#windows-simplified,下载 ez_setup.py文件,双击运行即可。
搭建Django应用
1、将C:\Python27\Scripts加入系统全局变量中。
2、django-admin.exe startproject myTest 创建工程。
3、进入工程myTest内django-admin.exe startapp myFirst 创建app。
4、在myTest工程配置文件setting.py中INSTALLED_APPS中添加app名字“myFirst”.
5、部署 python manage.py runserver(可能需要 python manage.py migrate),django默认前端端口8000.此时访问localhost:8000即可。
视图开发及URL配置
views.py:
def hello1(request,num):
try:
n=int(num)
except ValueError:
raise Http404()
return HttpResponse("hello world "+num)
urls.py:
url(r'^hello/(\d+)/$',hello1),
url后面括号是一个元组,第一项为正则表达式,第二项为要匹配的函数。把\d+用括号()括起来,可以当做一个参数传给视图函数。
正则表达式中前面不需要‘/’,尾部必须有‘/’,如果尾部无/,则会被重定向到对应尾部有/的url上。
^表示精确匹配头部,$表示精确匹配尾部。如果r'hello/' 表示只要包含hello即可匹配。
(正则表达式:?表示出现0或者1次,*表示出现0次或者多次,+表示出现1次或者多次,[^/]表示不包含 / 的式子,非的意思。)
此时
访问localhost:8000/hello/1/ 显示 hello world1
访问localhost:8000/hello/2/ 显示 hello world2
具体Django web实现过程:
启动manage.py 会去调用settings.py,查找相应大写字母的常量配置和ROOT_URLCONF,再去ROOT_URLCONF所指向的url文件逐个匹配url,与第一个匹配后调用相应视图函数,视图函数会返回一个Httpresponse,Django会将Httpresponse转为对应的HTTP response,在网页上显示出来。
settings中Debug=false,则不会显示具体出错信息
Django的MVC模式/MTV模式(摘自《The Django Book》):
Django紧紧地遵循MVC模式,可以称得上是一种MVC框架。 以下是Django中M、V和C各自的含义:
· M:数据存取部分,由django数据库层处理;
· V:选择显示哪些数据要显示以及怎样显示的部分,由视图和模板处理;
· C:根据用户输入委派视图的部分,由Django框架根据URLconf设置,对给定URL调用适当的Python函数。
由于C由框架自行处理,而Django里更关注的是模型(Model)、模板(Template)和视图(Views),Django也被称为MTV框架。在MTV开发模式中:
· M代表模型(Model):即数据存取层。该层处理与数据相关的所有事务:如何存取、如何验证有效性、包含哪些行为以及数据之间的关系等;
· T代表模板(Template):即表现层。该层处理与表现相关的决定:如何在页面或其他类型文档中进行显示。
· V代表视图(View),即业务逻辑层。该层包含存取模型及调取恰当模板的相关逻辑。你可以把它看作模型与模板之间的桥梁。
Django模板语法与使用
html显示那块可以在views视图函数中直接硬编码,比如html="<html><body>It is %s</body></html>" % now。
但是这样如果需要修改前端显示页面HTML/CSS,需要修改python代码,这样就没有做到前端后端的分离,耦合度太高,而Django是一个低耦合的框架,使用模板Template来负责前端页面显示。
模板
模板是一个文本,用于分离文档的表现形式和内容。 模板定义了占位符以及各种用于规范文档该如何显示的各部分基本逻辑(模板标签)。 模板通常用于产生HTML,但是Django的模板也能产生任何基于文本格式的文档。
{{a}}两个大括号表示a是变量。
标签:{% if a %} {% else %} {% endif %}
().[].{}.0.False,' '.None---->这些都为bool值里的false,其他都为True。
if标签可以使用and not or 但是不能同时使用几个,也不能用圆括号来组合操作,也没有{% elif %} 这个可以使用嵌套{% if %}。
{% for a in alist %} {% empty %} {% endfor %}
{% for a in alist reversed %} {% endfor %} 表示反向迭代
for循环里面有一个forloop变量,有一些记录循环信息的属性。遇到{% endfor %}就不起作用了
forloop.counter:循环计数,从1开始。
forloop.counter0:循环计数,从0开始。
forloop.revcounter: 记录循环剩余次数,初始为总次数,剩余一个元素时为1.
forloop.revcounter0:记录循环剩余次数,初始为总次数减1,结束时为0.
forloop.first: 是一个bool值,当执行第一个数时,被置为True。
forloop.last: 是一个bool值,当执行最后一个数时,为True。
有一个用 | 链接url的用法:{% for link in links %}{{ link }}{% if not forloop.last %} | {% endif %}{% endfor %} 输出 Link1 | Link2 | Link3 | Link4
forloop.parentloop:指向当前循环的上一级循环的forloop对象的引用。
{% ifequal user curuser %} {% else %} {% endifequal %}
只有模板变量,字符串,整数和小数可以作为 {% ifequal %} 标签的参数。下面是合法参数的例子:
{% ifequal variable 1 %}
{% ifequal variable 1.23 %}
{% ifequal variable 'foo' %}
{% ifequal variable "foo" %}
其他任何类型,例如Python的字典类型、列表类型、布尔类型,不能用在 {% ifequal %} 中,这些类型还是用{% if %}。
注释
单行注释{# #}
多行注释
{% comment % }
This is
comment
{% endcomment %}
过滤器
在变量被显示前进行修改的一种方法。
{{ name|lower }} 将name以小写输出
有些过滤器有参数,在后面加 :传入。{{ship_date|date:”F j, Y” }},我们将变量ship_date传递给date过滤器,同时指定参数”F j,Y”。date过滤器根据参数进行格式输出。 过滤器是用管道符(|)来调用的,具体可以参见Unix管道符。
Django中模板使用方法
Django模板系统的基本规则: import模板,创建 Template 对象,创建 Context , 调用 render() 方法。
from django import template
t=template.Template("My name is {{name}}") #创建template对象
c=template.Context({'name':'zhang'}) #创建Context 包含变量值
s=t.render(c) # s为制定模板变量值后的模板字符串(unicode对象)
print s #输出 My name is zhang
同一个模板,可以被不同的Context渲染,这样更加高效。创建一个模板对象,调用多次render()函数渲染不同的context值。
在视图中使用模板
为了实现html不出现在views.py中,而是将html和python代码完全分离。这需要考虑模板自加载和模板目录的技巧。
模板加载
为了减少模板加载调用过程及模板本身的冗余代码,Django 提供了一种使用方便且功能强大的 API ,用于从磁盘中加载模板。
要使用此模板加载API,首先你必须将模板的保存位置告诉框架。 设置的保存文件就是我们前一章节讲述ROOT_URLCONF配置的时候提到的 settings.py。
在与manage.py同层的目录添加一个templates目录用于存模板文件。(并将目录加入settings.py中的TEMPLATES 的‘DIRS)。
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',
],
},
},
]
template目录下添加一个html文件current_time.html : <html><body>It is now {{ time }}.</body></html>
views中使用get_template()函数加载模板
def cur_time(request):
now=datetime.datetime.now()
t=get_template('current_time.html')
c=Context({'time':now})
return HttpResponse(t.render(c))
urls.py中 配置url:url(r'^cttime/$',cur_time),
访问http://localhost:8000/cttime/ 即可。
上面cur_time函数还是很复杂,Django对加载进行封装,不再需要导入 get_template 、 Template 、 Context 和 HttpResponse 。相反,我们导入django.shortcuts.render_to_response
from django.shortcuts import render_to_response
def cur_time1(request):
now=datetime.datetime.now()
return render_to_response('current_time.html',{'time':now})
render_to_response函数第一个参数是模板文件(如果模板文件有子目录,则使用 filename/current_time.html,使用/不是\),第二个是对应变量值。
{% include a.html %}可以包含另一个html模板。
Django中使用模板继承。
首先,定义基本模板base.html,后面会有字模板继承这个模板。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<h1>My helpful timestamp site</h1>
{% block content %}{% endblock %}
{% block footer %}
<hr>
<p>Thanks for visiting my site.</p>
{% endblock %}
</body>
</html>
所有的 {% block %} 标签告诉模板引擎,子模板可以重载这些部分.
其次,子模板中current_time.html 继承base.html。
{% extends "base.html" %}
{% block title %}The current time{% endblock %}
{% block content %}
<p>It is now {{ time }}.</p>
{% endblock %}
配置数据库和创建新app
1、检查Django project中settings.py中数据库配置,这里使用python自带的sqlite3:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
运行python manage.py shell,执行命令:from django.db import connection cursor=connection.cursor() 如果这里没出错,就说明数据库配置正确。
2、上文提到过的 django.exe startapp myFirst(进入myTest工程目录下) 或者使用命令python manage.py startapp myFirst,创建一个app.
3、在settings.py的INSTALLED_APPS 中添加‘myFirst’,如下
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myFirst',
)
4、此时开始思考数据的存储,即模型的定义。
Django使我们只需要写python的代码,后台会生成数据库表。
参考 http://www.dannysite.com/blog/7/
Django模型是用Python代码形式表述的数据在数据库中的定义。对数据层来说它等同于CREATE TABLE语句,只不过执行的是Python代码而不是SQL,而且还包含了比数据库字段定义更多的含义。Django用模型在后台执行SQL代码并把结果用Python的数据结构来描述。
下面举例说明数据库的使用。
一个博客包含标题、作者、发表的时间、分类、标签等内容;而作者肯定有姓名和一些基本的联系方式;分类和标签则可以简单一些,只需要名字就足够了......
在myFirst的models.py中添加如下代码:
from django.db import models
# Create your models here.
class Tag(models.Model):
tag_name=models.CharField(max_length=200)
create_time=models.DateTimeField(auto_now_add=True)
def __unicode__(self): #此函数作用是print对象时会打印具体返回值。
return self.tag_name
class Classification(models.Model):
name=models.CharField(max_length=200)
def __unicode__(self):
return self.name
class Author(models.Model):
name=models.CharField(max_length=30)
email=models.EmailField(blank=True)
website=models.URLField(blank=True)
def __unicode__(self):
return u'%s' % (self.name)
class Article(models.Model):
caption=models.CharField(max_length=30)
subcaption=models.CharField(max_length=50,blank=True)
publish_time=models.DateTimeField(auto_now_add=True)
update_time=models.DateTimeField(auto_now=True)
author=models.ForeignKey(Author)
classification=models.ForeignKey(Classification)
tags=models.ManyToManyField(Tag,blank=True)
content=models.TextField()
Django中models里每个类一个数据库表,有多对多关系(ManyToMany)的会建一个关系表。例如上面Article类中有一个ManyToMany关系的tags,因此数据库中总共有5个表(4个类4个表,一个多对多表),Django会为每个表自动添加一个自增长主键id。如果某个字段可以选填,设置blank=True即可。
再执行 python manage.py sqlall myFirst.出现对应sql语句。
这里如果报错“app myFirst has migrations”,删除myFirst目录下的migrations文件夹即可。
BEGIN;
CREATE TABLE "myFirst_tag" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"tag_name" varchar(200) NOT NULL,
"create_time" datetime NOT NULL
)
;
CREATE TABLE "myFirst_classification" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" varchar(200) NOT NULL
)
;
CREATE TABLE "myFirst_author" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" varchar(30) NOT NULL,
"email" varchar(254) NOT NULL,
"website" varchar(200) NOT NULL
)
;
CREATE TABLE "myFirst_article_tags" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"article_id" integer NOT NULL,
"tag_id" integer NOT NULL REFERENCES "myFirst_tag" ("id"),
UNIQUE ("article_id", "tag_id")
)
;
CREATE TABLE "myFirst_article" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"caption" varchar(30) NOT NULL,
"subcaption" varchar(50) NOT NULL,
"publish_time" datetime NOT NULL,
"update_time" datetime NOT NULL,
"author_id" integer NOT NULL REFERENCES "myFirst_author" ("id"),
"classification_id" integer NOT NULL REFERENCES "myFirst_classification" ("id"),
"content" text NOT NULL
)
;
CREATE INDEX "myFirst_article_tags_e669cc35" ON "myFirst_article_tags" ("article_id");
CREATE INDEX "myFirst_article_tags_5659cca2" ON "myFirst_article_tags" ("tag_id");
CREATE INDEX "myFirst_article_e969df21" ON "myFirst_article" ("author_id");
CREATE INDEX "myFirst_article_d3dde821" ON "myFirst_article" ("classification_id");
COMMIT;
很明显,模型已经变成了SQL语句,确认无误后,最后执行python manage.py syncdb即可将创建的模型同步至数据库。这里系统可能会提示你添加一个超级用户,按步骤添加即可,这个用户可以用于在之后登录Django的站点管理。
此时,shell交互下,对数据库表Tag进行操作,创建两条数据对象‘aaaa’和‘bbbb’,使用save()保存(Django在后台执行insert语句),Tag.objects.all()获得表中所有对象(Django在后台执行select语句)。
创建和保存是两部操作,如果想一步完成,使用Tag.objects.create(tag_name='aaaa').
Django中数据过滤filter()(相当于sql中where),Tag.objects.filter(tag_name='aaaa').
contains作用是like,模糊匹配,Tag.objects,filter(tag_name__contains='a'),两个下划线。
Tag.objects.get(tag_name='aaaa')获得一个对象,而不是列表,如果有多个对象匹配,会报错。
排序:
1、Tag.objects.order_by(“tag_name”)正向排序方法。加“-”逆序Tag.objects.order_by(“-tag_name”)。
也可以在models.py类中加代码
2、class Meta:
ordering = ['name']
限制输出行数:
Tag.objects.filter(tag_name='aaaa')[0:2]
更新数据:
1、先get到,再对属性赋值,再调用save()
2、Tag.objects.filter(id=1).update(tag_name='cccc') update可对一个集合元素进行更新操作。 返回整型值,表示更新的条数。
删除数据:
Tag.objects.filter(id=1).delete()
Tag.objects.all().delete() 全部删除
其实我们可以创建数据库连接、创建数据库游标、执行某个语句、然后关闭数据库。---》一种重复性极高的操作数据库的方法。例如:
from django.shortcuts import render_to_response
import MySQLdb
def book_list(request):
db = MySQLdb.connect(user='me', db='mydb', passwd='secret', host='localhost')
cursor = db.cursor()
cursor.execute('SELECT name FROM books ORDER BY name')
names = [row[0] for row in cursor.fetchall()]
db.close()
return render_to_response('book_list.html', {'names': names})
Django站点管理
django.contrib庞大的功能集。
django.contrib.admin
访问localhost:8000/admin/ 进入登陆页面,之前填写models.py后 python manage.py syncdb会创建一个超级用户,包括用户名和密码。如果当时没有创建,使用python manage.py createsuperuser 创建一个超级用户。
'django.middleware.locale.LocaleMiddleware',加到MIDDLEWARE_CLASSES中,会让默认admin页面变成中文。
将models加入到admin管理中
from django.contrib import admin
from myFirst.models import *
# Register your models here.
admin.site.register(Tag)
admin.site.register(Classification)
admin.site.register(Author)
admin.site.register(Article)
在app目录下添加admin.py文件,填入以上代码,admin页面就会为app的这些数据模型添加相应界面。此时可以再访问localhost:8000/admin/查看。
后台admin是怎么工作的
当服务启动时,Django从`` url.py`` 引导URLconf,然后执行`` admin.autodiscover()`` 语句。 这个函数遍历INSTALLED_APPS配置,并且寻找相关的 admin.py文件。 如果在指定的app目录下找到admin.py,它就执行其中的代码。
在`` books`` 应用程序目录下的`` admin.py`` 文件中,每次调用`` admin.site.register()`` 都将那个模块注册到管理工具中。 管理工具只为那些明确注册了的模块显示一个编辑/修改的界面。
models的类注册到admin后在页面显示的字段,是models中类变量 _变空格,首字母大写后的,是自动变的,如果想自定义字段名称,models中变量定义处加:verbose_name='my-subcaption'。此时字段为My-subcaption
subcaption=models.CharField(max_length=50,blank=True,verbose_name='my-subcaption')
使用ModelAdmin,编辑数据显示界面。
在admin.py中register前添加list_display:
class AuthorAdmin(admin.ModelAdmin):
list_display = ('name','email','website')
注册改为:
#admin.site.register(Author)
admin.site.register(Author,AuthorAdmin)
在list_display后面加search_fields = ('name','email')
添加过滤器list_filter:
class ArticleAdmin(admin.ModelAdmin):
list_display = ('caption','subcaption','publish_time','author')
list_filter = ('publish_time',)#会出现按时间过滤的选项
date_hierarchy = 'publish_time'也是一种按时间过滤的方式,在页面顶端会出现逐层深入的导航条,,但是我在操作过程报错,需要下东西。
ordering = ('-publish_time',) -按出版时间逆序排序,与class Meta中一样
自定义编辑页面
fields = ('caption','author','classification')修改的时候显示的项,不想被人显示的项就不放在里面,就可以做到禁止某项被修改。
filter_horizontal = ('tags',)对于多值属性,多选时需要按住ctrl很麻烦,可以使用水平移动框去选择,tags区中有一个精巧的JavaScript过滤器,它允许你检索选项,然后将选中的authors从Available框移到Chosen框,还可以移回来。从左往右或者从右往左移动。
raw_id_fields = ('author',)用于外键属性,原本外键属性是下拉框,用这个函数后是以文本形式,当值特别多时比较有效。
URL相关信息
views.py中request自带一些函数。
request.path request.get_host() request.get_full_path() request.is_secure()
request.META 是一个Python字典,包含了所有本次HTTP请求的Header信息,比如用户IP地址和用户Agent(通常是浏览器的名称和版本号)。
Django Book 第七章前面介绍一个查找数据库信息的例子。
验证:首先会有javascript的验证,但是服务端也需要对用户输入进行验证,比如视图中。
创建contact表单,发邮件。
1、新建一个app,在myTest项目里使用 django_admin.exe startapp contact.
2、在templates里添加模板contact_form.html
<!DOCTYPE html>
<html>
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>
{% if errors %}
<ul>
{% for error in errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<form action="/contact/" method="post">
<br />{% csrf_token %}<br />
<p>Subject: <input type="text" name="subject" value="{{ subject }}" ></p>
<p>Your e-mail (optional): <input type="text" name="email" value="{{ email }}" ></p>
<p>Message: <textarea name="message" rows="10" cols="50">{{ message }}</textarea></p>
<input type="submit" value="Submit">
</form>
</body>
</html>
3、在contact app里的views里加入contact视图函数。
from django.shortcuts import render
# Create your views here.
from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext
def contact(request):
errors = []
if request.method == 'POST':
if not request.POST.get('subject', ''):
errors.append('Enter a subject.')
if not request.POST.get('message', ''):
errors.append('Enter a message.')
if request.POST.get('email') and '@' not in request.POST['email']:
errors.append('Enter a valid e-mail address.')
if not errors:
send_mail(
request.POST['subject'],
request.POST['message'],
request.POST.get('email', 'noreply@example.com'),
['735347248@qq.com'],
)
return HttpResponseRedirect('/contact/thanks/')
return render_to_response('contact_form.html',
{'errors': errors,
'subject': request.POST.get('subject', ''),
'message': request.POST.get('message', ''),
'email': request.POST.get('email', ''),},context_instance=RequestContext(request))
4、urls.py里urlpatterns添加url('^contact/$',contact),
5、访问localhost:8000/contact出现CSRF验证失败. 相应中断的错误,主要根据错误提示的第2、3点解决。
首先,注意views.py中contact函数。使用RequestContext代替Context。
from django.template import RequestContext render_to_response中加入context_instance=RequestContext(request)。
其次,form表单处加入<br />{% csrf_token %}<br /> 见上面代码。
另外,因为settings.py里已经有了django.middleware.csrf.CsrfViewMiddleware,就不需要再加了。
6、关于django 中send_mail。
send_mail(
request.POST['subject'],
request.POST['message'],
request.POST.get('email', 'noreply@example.com'),#fromemail
['735347248@qq.com'],#toemail list
)
settings中需设置发送邮箱代理。
#send_mail need
EMAIL_HOST= 'smtp.163.com'
EMAIL_PORT= 25
EMAIL_HOST_USER = 'XXXXXXX@163.com'
EMAIL_HOST_PASSWORD = 'XXXXXXX'
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
最好使用163邮箱,因为默认smtp是打开了的,qq邮箱就不一定。
第一个Form类
Django带有一个form库,称为django.forms,这个库可以处理我们本章所提到的包括HTML表单显示以及验证。
表单框架最主要的用法是,为每一个将要处理的HTML的`` <Form>`` 定义一个Form类。
在与views.py同层目录下新建一个forms.py,一个ContactForm类包含一个html表单数据。
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
email = forms.EmailField(required=False,label='Your e-mail address'<span style="font-family: 'Microsoft YaHei'; font-size: 10px;">)</span>
message = forms.CharField(widget=forms.Textarea)
def clean_message(self):
message = self.cleaned_data['message']
num_words = len(message.split())
if num_words < 4:
raise forms.ValidationError("Not enough words!")
return message
clean_message自定义校验方法。
自定义标签label='Your e-mail address'
views.py中添加
from forms import ContactForm
def newcontactform(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
send_mail(
cd['subject'],
cd['message'],
cd.get('email', 'noreply@example.com'),
['735347248@qq.com'],
)
return HttpResponseRedirect('/contact/thanks/')
else:
form = ContactForm()
return render_to_response('newcontact_form.html', {'form': form},context_instance=RequestContext(request))
新建一个模板newcontact_form.html
<!DOCTYPE html>
<html>
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="" method="post">
<br />{% csrf_token %}<br />
<table>
{{ form.as_table }}
</table>
<input type="submit" value="Submit">
</form>
</body>
</html>
form.as_table是一种自动生成html的方式,但是可以对其中单独的某些项进行渲染。