您的位置:首页 > 编程语言 > Go语言

Django学习笔记

2015-05-03 19:21 483 查看

一、概述

Django是一个开放源代码的Web应用框架,由Python写成。采用了MVC的软件设计模式,即模型M,视图V和控制器C。

Django遵循BSD版权。

二、安装

参见:https://docs.djangoproject.com/en/1.8/intro/install/

需要3步:

1)首先安装python

2)安装pip

3)安装Django的生产版

验证是否安装成功:

python -c "import django; print(django.get_version())"


注1:用easy_install也可以安装。

注2:当环境里有多个版本的python时,需要将Django安装到哪个python中,就要用哪个python下的easy_install、pip进行安装django。安装pip时,通过执行安装脚本的python的版本来决定将pip安装到哪个python中。

三、从零开始

1)创建一个项目:

django-admin startproject mysite


目录结构如下:

mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py


目录结构说明:

外层的mysite/根目录仅仅是项目所在的位置,它的命名和Django本身无关;你可以把它改名为任何你喜欢的名字。

manage.py:一个命令行工具,可以使你用多种方式对Django项目进行管理。你可以在django-admin.py and manage.py读到所有关于manage.py的使用细节。

内层的mysite/目录实际上是你的项目里的一个Python包。这个目录的名字就是Python包的名字。你将使用这个名字从这个Python包中导入模块或者类等等(例如mysite.urls)。

mysite/__init__.py:这是一个空文件。它告诉Python,这个目录应该被看做一个Python包。(如果你是一个Python初学者,阅读官方文档中关于包的更多知识。)

mysite/settings.py:Django项目的配置文件。Django配置将告诉你这些配置项的作用。

mysite/urls.py:这个Django项目的URL声明;你的Django站点的“目录”。你可以在URL调度中读到更多关于URLs的资料。

mysite/wsgi.py:一个WSGI兼容的Web服务器的一个入口。用来连接你的项目和相关Web服务器。查看怎样部署WSGI获得更多细节。

修改settings.py

LANGUAGE_CODE = 'zh-CN'
TIME_ZONE = 'Etc/GMT-8'


2)为INSTALLED_APPS(settings.py的配置项)创建必要的数据库文件:

python manage.py migrate


此命令参照 INSTALLED_APPS 设置,并在你的 settings.py 文件所配置的数据库中创建必要的数据库表。

每创建一个数据库表你都会看到一条消息。

3)启动web server

python manage.py runserver 0.0.0.0:41188
# 使用如下方法让web server在终端断开后也可以稳定提供服务
nohup python manage.py runserver 0.0.0.0:41188 &
# 停止的方法?先找到PID,然后kill
ps aux | grep python
kill -9 xxx


该方法通过参数指定了web server的ip和端口,如上的设置会监听所有公共 IP 地址,从而可以在其他电脑上访问到该web server。此时,已经访问如上地址和端口,可以看到默认页面:”It worked!“

只是修改了python文件内容,则web server会自动加载对应的python代码;但如果新增加了文件等,就需要重启该web server来生效了。

4)创建应用

在manage.py的同级目录下执行以下命令来创建一个应用polls:

python manage.py startapp polls


目录结构如下:

polls/
__init__.py
admin.py
migrations/
__init__.py
models.py
tests.py
views.py


5)创建models

models即代表了DB的表结构,它们使用python类进行描述。

编辑polls/models.py文件,添加以下内容:

from django.db import models
#from django.utils import timezone

class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')

### print model's info when using Django API
#def __str__(self):              # __unicode__ on Python 2
#    return self.question_text
### a query, using Django API
#def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

class Choice(models.Model):
question = models.ForeignKey(Question)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)

### print model's info when using Django API
#def __str__(self):              # __unicode__ on Python 2
#    return self.choice_text


每个模型都由继承自 django.db.models.Model 子类的类来描述。 每个模型都有一些类变量,每一个类变量都代表了一个数据库字段。

每个字段由一个 Field 的实例来表现 – 比如 CharField 表示字符类型的字段和 DateTimeField 表示日期时间型的字段。这会告诉 Django 每个字段都保存了什么类型的数据。一些 Field 实例是需要参数的。 例如 CharField 需要你指定 :attr:`~django.db.models.CharField.max_length`。这不仅适用于数据库结构,以后我们还会看到也用于数据验证中。一个 Field 实例可以有不同的可选参数; 在本例中,我们将 votes 的
default 的值设为 0 。

每一个 Field 实例的名字就是字段的名字或者<字段名_类型>(如: question_text 或者 pub_date ),而表名则是<应用名_表名>。你可以在初始化 Field 实例时使用第一个位置的可选参数来指定人类可读的名字。在本例中,我们仅定义了一个符合人类习惯的字段名 Poll.pub_date 。

上面的语句创建的表应该是这个样子:(在后面激活models时可以看到)

BEGIN;
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL);
CREATE TABLE "polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "question_text" varchar(200) NOT NULL, "pub_date" datetime NOT NULL);
CREATE TABLE "polls_choice__new" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL, "question_id" integer NOT NULL REFERENCES "polls_question" ("id"));
INSERT INTO "polls_choice__new" ("choice_text", "votes", "id", "question_id") SELECT "choice_text", "votes", "id", NULL FROM "polls_choice";
DROP TABLE "polls_choice";
ALTER TABLE "polls_choice__new" RENAME TO "polls_choice";
CREATE INDEX "polls_choice_7aa0f6ee" ON "polls_choice" ("question_id");

COMMIT;


6)激活models

首先,将polls应用添加到我们的工程之中。编辑mysite/settings.py文件,添加polls到INSTALLED_APPS配置项中,例如下面:

INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'polls',
)


然后,执行命令,创建DB的数据表

# 创建migrations,保存路径类似:polls/migrations/0001_initial.py。0001_initial.py是由下面的命令执行结果中查看到的
python manage.py makemigrations polls
# 根据migrations,生成SQL语句,对照SQL语句确认无误。也可以运行python manage.py check来进行检查
python manage.py sqlmigrate polls 0001
# 执行变更,创建DB的数据表
python manage.py migrate


Migrations机制使得我们开发过程中,变更models时,无需删除DB再重新建立,该机制会更新你的DB完成models变更的同步,并且不会丢失数据。

综上,变更models的三部曲为:

1. 修改models.py文件

2. 执行python manage.py makemigrations,生成变更的migrations

3. 执行python manage.py migrate,将migrations应用到DB的变更

之所以单独分离出第二步来生成变更的migrations,是为了将这些migrations纳入版本控制系统,从而方便以后的开发和维护。

7)使用Django的API

我们需要进入 Python 的交互式 shell 中来操作 Django 提供给你的 API。

不同于简单的输入 “python” 进入的 shell 环境,通过manage.py的方式,因为 manage.py 设置了 DJANGO_SETTINGS_MODULE 环境变量,该变量给定了 Django 需要导入的 settings.py 文件所在路径。

python manage.py shell


操作DB的一些语句

# 导入刚刚的models
>>> from polls.models import Question, Choice
# 打印Question里的所有数据
>>> Question.objects.all()
[]
# 新建一条Question数据,并保存
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())
>>> q.save()
# 打印刚刚新建的数据的相关属性
>>> q.id
1
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)
# 修改刚刚新建的数据
>>> q.question_text = "What's up?"
>>> q.save()
# 打印Question里的所有数据,此处直接打印出object是因为没有为models类定义__str__方法
>>> Question.objects.all()
[<Question: Question object>]
# 添加__str__()方法后
>>> Question.objects.all()
[<Question: What's up?>]
# 使用filter函数进行查询
>>> Question.objects.filter(id=1)
[<Question: What's up?>]
>>> Question.objects.filter(question_text__startswith='What')
[<Question: What's up?>]
# 使用get函数进行简单查询并返回一条结果供直接使用,如果没有结果则会报一个异常
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>
>>> Question.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Question matching query does not exist.
# 使用pk作为主键的简写,这里的主键是id
>>> Question.objects.get(pk=1)
<Question: What's up?>
# 调用model类的函数
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True
# 通过Question获取choice_set并新建choice,以自动和当前Question做关联
>>> q = Question.objects.get(pk=1)
>>> q.choice_set.all()
[]
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)
>>> c.question
<Question: What's up?>
>>> q.choice_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> q.choice_set.count()
3
# 查看Choice
>>> Choice.objects.filter(question__pub_date__year=current_year)
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
# 删除一条数据
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()


8)创建管理员账户

运行如下命令来创建管理员账户:

python manage.py createsuperuser


管理员页面是默认开启的,只需要访问/admin目录就可以看到登录界面。

9)把polls应用添加到管理页面

打开polls/admin.py文件,添加类似以下的内容:

from django.contrib import admin

from .models import Choice, Question

admin.site.register(Question)
admin.site.register(Choice)

### 指定更多的表现形式
#class QuestionAdmin(admin.ModelAdmin):
fields = ['pub_date', 'question_text']
#admin.site.register(Question, QuestionAdmin)


此时再进入管理页面就可以看到polls应用的models了,并可以进行直观操作对应的数据。

10)创建View

在 Django 应用程序中,View(视图)是一“类”具有特定功能和模板的网页。每个View就是一个简单的 Python 函数(或方法, 对于基于类的Views情况下)。Django 会通过检查所请求的 URL (确切地说是域名之后的那部分 URL)来匹配一个View。

Django 是通过 ‘URLconfs’ 从 URL 获取到视图的。而 URLconf 是将 URL 模式 ( 由正则表达式来描述的 ) 映射到视图的一种配置。

首先,编辑polls/views.py,添加以下内容:

from django.http import HttpResponse

def index(request):
return HttpResponse("Hello, world. You're at the polls index.")


然后,在polls目录下创建一个urls.py文件来保存URLconf,内容为polls使用到的url到view的映射:

from django.conf.urls import url

from . import views

urlpatterns = [
url(r'^$', views.index, name='index'),
]


最后,在根URLconf的配置里加入polls的URLconf。编辑mysite/urls.py文件,添加之后的内容类似:

from django.conf.urls import include, url
from django.contrib import admin

# 通过namespace避免了多个应用时,通过name来引用url时多个应用之间的混淆
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^polls/', include('polls.urls')),
#url(r'^polls/', include('polls.urls', namespace="polls")),
]


此时,再访问/polls路径就可以看到刚才在views.py里添加的内容提示了。

11)URLconf的url()函数详解

url() 函数有四个参数,两个必须的: regex 和 ``view``, 两个可选的: ``kwargs``, 以及 ``name``。

a. regex 是 regular expression 的简写, 在 Django 中就是是 url path(不含 GET 和 POST 参数,以及域名的部分)的匹配模式。 Django 将请求的 URL Path从上至下依次匹配列表中的正则表达式,直到匹配到一个为止。注:这些正则表达式在 URLconf 模块第一次加载时会被编译,即生成urls.pyc文件,因此它们速度超快。

b. View指定了被调用的视图(python函数或者类方法),当 Django 匹配了一个正则表达式就会调用指定的视图功能,包含一个 HttpRequest 实例作为第一个参数,正则表达式 “捕获” 的一些值的作为其他参数。

c. kwargs是一个保存关键字参数的词典,该词典参数会被传入到视图中。不推荐使用该方法。

d. 通过name参数来命名你的 URL ,让你在 Django 的其他地方明确地引用它,特别是在模板中。 这一强大的功能可允许你通过一个文件就可全局修改项目中的 URL 模式。

12)更多视图的实例

1. 通过URL捕获参数

修改polls/views.py,增添以下内容:

def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id)

def results(request, question_id):
response = "You're looking at the results of question %s."
return HttpResponse(response % question_id)

def vote(request, question_id):
return HttpResponse("You're voting on question %s." % question_id)


修改polls/urls.py,增添以下内容:

from django.conf.urls import url

from . import views

urlpatterns = [
# ex: /polls/
url(r'^$', views.index, name='index'),
# ex: /polls/5/
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
# ex: /polls/5/results/
url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
# ex: /polls/5/vote/
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]


此时,再访问上面示例的链接,会将5作为参数question_id传递给view。

13)创建模板和使用模板的视图

创建polls/templates目录,根据Django的默认配置,它会去每个应用的目录寻找子目录templates来引入模板。

创建模板文件:polls/templates/polls/index.html,而引用该文件时则可以使用路径:polls/index.html。

为什么要在templates下创建polls子目录?因为如果直接在templates下建立模板文件index.html,则在有多个应用并均有该文件时,引用该模板文件就会出现混淆。

index.html的内容如下:

{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<!-- <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> -->
<!-- 以下方式避免了硬编码url -->
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
<!-- 以下方式为使用namespace方式 -->
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}


同理,建立polls/templates/polls/detail.html文件:

{{ question }}


然后更新polls/veiws.py文件,以让index视图引用该模板:

from django.http import HttpResponse
from django.template import RequestContext, loader
from django.http import Http404
from django.shortcuts import render

from .models import Question

def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = RequestContext(request, {
'latest_question_list': latest_question_list,
})
return HttpResponse(template.render(context))

### render is shortcut for template.render
#def index(request):
#    latest_question_list = Question.objects.order_by('-pub_date')[:5]
#    context = {'latest_question_list': latest_question_list}
#    return render(request, 'polls/index.html', context)

def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, 'polls/detail.html', {'question': question})

### get_object_or_404 is shortcut for try-except 404
#def detail(request, question_id):
#    question = get_object_or_404(Question, pk=question_id)
#    return render(request, 'polls/detail.html', {'question': question})


14)处理form请求

修改polls/templates/polls/detail.html文件增加简单的form:

<h1>{{ question.question_text }}</h1>

{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}

<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
{% endfor %}
<input type="submit" value="Vote" />
</form>


该form的action表示其会提交给vote视图进行处理,所以我们修改polls/views.py文件,实现vote视图如下:

from django.shortcuts import get_object_or_404
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect

from .models import Choice, Question
# ... ...

def vote(request, question_id):
p = get_object_or_404(Question, pk=question_id)
try:
selected_choice = p.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': p,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('polls:results', args=(p.id,)))
说明:

1. request.POST 是一个类似字典的对象,可以让你 通过关键字名称来获取提交的数据。request.POST 的值永远是字符串形式的。

2. Django 也同样的提供了通过 request.GET 获取 GET 数据的方法

3. 如果 choice 未在 POST 数据中提供,则 request.POST['choice'] 将抛出 KeyError

4. 当成功的处理了 POST 数据后你应该总是返回一个 HttpResponseRedirect 对象,原因如上面的注释所解释。

5. reverse() 函数将URLConf的name转换为实际的URL。 此函数有助于避免在视图中硬编码 URL 的功能。

15)使用样式

在polls目录下新建static子目录,和寻找模板目录机制一样,Django的默认配置会去每个应用下搜索static目录作为静态文件的目录,可以存放js、css和图片等。

同样,在static中再新建polls子目录,在polls子目录下新建一个mystyle.css文件,其路径为:polls/static/polls/mystyle.css,而引用时可以使用路径:/static/polls/mystyle.css。

该css文件内容为:

li a {
color: green;
}


在模板文件polls/index.html的头部增加以下代码:

<link rel="stylesheet" type="text/css" href="/static/polls/mystyle.css" />


刷新页面/polls/页面,可以看到mystyle.css的样式生效了。

四、更多帮助

1. API参考

API Reference

2. Topic指南

Topic Guides

3. 问题指南

How-to Guides

4. FAQ

FAQ
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: