2003年,堪萨斯(Kansas)州 Lawrence 城中的一个 网络开发小组 ——World Online 小组,为了方便制作维护当地的几个新闻站点(一般要求几天或者几小时内被建立),Adrian Holovaty 和 Simon Willison 使用ptyhon开发了一种节省时间的网络程序开发框架。
在2005年夏天,这个框架被开发完成,World Online 小组中的Jacob Kaplan-Moss 决定把这个框架发布为一个开源软件。于是7月份Django发布了,名字以比利时的吉普赛爵士吉他手Django Reinhardt来命名。
Dango 的主要目的是为了使 开发复杂的、数据库驱动的网站 变得简单。
截止目前 django 支持的数据有 SQLite,MySQL, Oracle, PostgreSQ,默认使用SQLite。
Django的安装:
官方下载地址: http://www.djangoproject.com/download/
1. 下载tar包,Django-*.tar.gz # 具体版本根据需要下载
2. tar xzvf Django-*.tar.gz 。
3. cd Django-*
4. sudo python setup.py install
pip 安装
$ pip install Django
验证:
$ python >>> import django >>> print(django.VERSION) (1, 10, 1, 'final', 1)
第一个Django程序
$ django-admin startproject blog # 创建一个 project $ tree blog/ blog/ ├── blog │ ├── __init__.py │ ├── settings.py # 当前项目的配置文件 │ ├── urls.py # 当前项目的URL规则声明,其实就是django站点的内容清单 │ └── wsgi.py # 为WSGI 兼容服务提供的接口 └── manage.py # 一个命令行工具,用来让你和django 进行各种交互
启动 开发服务器
python3 manage.py runserver
开发服务器是完全使用python编写的轻量级服务器程序,使用开发服务器可以帮助我们集中精力快速开发,而不必考虑服务器配置的事情。等到发布产品的时候在考虑就可以了。
runserver 命令在默认情况下 使用的8000端口,且只有本机IP可以访问。如果希望使用其他端口可以将端口修改掉。同样,修改 IP 也是如此。
python3 manage.py runserver 8080 # 修改端口 python3 manage.py runserver 0.0.0.0:8000 # 修改IP
配置数据库
前面我们说到 setting.py 包含,django project的设置信息。数据库的配置 也是在这里进行配置的。
django默认使用的数据库是 sqlite ,官方还支持mysql、oracle、postgresql。 如果需要使用第三方的数据库,需要自己安装。查看详细信息
# 默认配置 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } # mysql 配置 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'mydatabase', # 数据库名 'USER': 'mydatabaseuser', 'PASSWORD': 'mypassword', 'HOST': '127.0.0.1', 'PORT': '3306', } }
ENGINE : 从 'django.db.backends.sqlite3'
, 'django.db.backends.postgresql'
,'django.db.backends.mysql'
, or 'django.db.backends.oracle' 中选一个就可以了,其他的可以,需要自己配置。
NAME: 你使用的数据库的名。如果使用的是SQLite,那么数据库就是你本机上的一个文件,这时NAME 应该是这个文件的完整路径(含文件名),如果文件不存在,django会在第一次同步数据库的时候自动创建。
USER : 连接数据库的用户名(sqlite不用写)
PASSWORD :连接数据库的密码(sqlite不用写)
HOST : 数据库所在的主机,如果数据库在本机,可以留空,(sqlite不用写)
PORT: 数据库所在机器的端口(sqlite不用写)
注意: 使用prostgresql和mysql时需要提前创建好数据库。
设置时区
django默认的时区,是美国中央时区(芝加哥),通过设置 TIME_ZONE 可以更改为本地时区。
TIME_ZONE = 'Asia/Shanghai'
配置到这里就做完了。
这里我们开始添加第一个app
$ cd blog/ $ django-admin startapp vote # 添加一个app $ tree . . ├── blog │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── manage.py └── poll ├── admin.py # 用来配置django admin ├── apps.py ├── __init__.py ├── migrations │ └── __init__.py ├── models.py # 在这里写的类对应数据库中的表 ├── tests.py └── views.py #
一个app就是完成某件事的一个web程序,比如一个公共数据资料库 或者一个简单的投票程序
一个project 包含一系列的配置,以及多个app。
添加 app 以后如果我们想在 project 中使用,需要将app注册到project中
注册的过程就是在 setting.py 的 INSTALLED_APPS 变量中 添加 app 的名字。这里 app 的名字是 poll。
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'poll', # 这一行是我们自己添加的 ]
models.py : 在这里定义model,这里定义的类对应了你数据库中的表,数据库中的表根据这里定义的类生成,可以通过这里的类操作数据库。
from django.db import models # Create your models here. class Poll(models.Model): """ 问题表 """ question = models.CharField(max_length=200) pub_date = models.DateTimeField("date published") class Choice(models.Model): """ 选项表 """ poll = models.ForeignKey(Poll) choice = models.CharField(max_length=200) votes = models.IntegerField()
类中的每一个变量对应数据库表中的一个字段。每一个字段都使用Field类的实例来表示,比如CharField表示字符类型的字段,DateTimeField 表示日期类型的字段。
每个实例的名字(类中的变量) 就是字段的名字。
每个Field实例你都可以通过位置参数 来 定义一个可读性更强的名字,就像上面的 pub_date 。
现在我们添加了一个叫 poll 的 app, 还写了 model。现在我们生成一下 model(也就是创建数据库表)。
python3 manage.py makemigrations # 相当于 在该app下建立 migrations目录,并记录下你所有的关于modes.py的改动,比如0001_initial.py, 但是这个改动还没有作用到数据库文件。
同步:
python3 manager.py migrate # 将该改动作用到数据库文件,比如生成数据库表
django admin 是为管理员设计的,它的存在是为了方便管理员对数据进行增删改查 和管理站点任务。
使用django admin之前我们要先创建超级用户
python3 manage.py createsuperuser # 创建超级用户
在django admin中现实Poll表
在poll/admin.py中添加如下内容:
from django.contrib import admin from poll.models import Poll admin.site.register(Poll)
调整admin中表数据的显示
from django.contrib import admin # Register your models here. from poll.models import Poll from poll.models import Choice class ChoiceInline(admin.StackedInline): model = Choice extra = 3 class PollAdmin(admin.ModelAdmin): """ 自定义 字段顺序 """ fields = ['pub_date', 'question'] inlines = [ChoiceInline] # 添加Poll的时候在Poll页面实现添加多个Choice; 和ChoiceInline类共同实现 list_display = ('question', 'pub_date') admin.site.register(Poll,PollAdmin) admin.site.register(Choice)
编写第一个view, views.py中有很多函数,每一个函数可以表示我们的一个或多个页面。
from django.shortcuts import render # Create your views here. from django.http import HttpResponse def index(request): return HttpResponse("Hello world!")
我们写出的view 终究是要别人来访问的。而别人放访问网站的页面都是通过url 来访问的。
设计URL
总url配置在 blog/url.py 中进行配置,我们先配置一个最简单的。
from django.conf.urls import url from django.contrib import admin from poll import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', views.index), # 对应views.py中的 index函数 url(r'^poll/$', views.index), # 对应views.py中的index 函数 ]
这样我们就编写了一个最基本的页,实现了页面的访问。
如果我们将 views.py中的 index() 函数的返回值,用前端语言包装一下。会有什么效果?
def index(request): return HttpResponse("<h1>Hello world!</h1><h2>The second line.</h2>")
这个时候我们就再访问 http://127.0.0.1:8000/ 就会发现 网页的内容变了。
如果index() 返回的内容很多,我们肯定不会这样写,一般我们会将 要返回的内容,放到一个html文件里。
这样我们就可以编写一个见到那的静态网站了。
但是很多时候我们网页的内容是动态变化的。
我们可以在对上面的进行一个简单的修改。
## views.py def index(request): lst = [1, 2, 3, 4, 5] return render(request, 'index.html', {'lst':lst}) ## index.html ## 在 body 标签中 增加如下内容 {% if lst %} <ul> {% for i in lst %} <li> {{ i }}</li> {% endfor %} </ul> {% endif %}
很多时候,我们是需要操作数据库的:
## views.py def index(request): lst = [1, 2, 3, 4, 5] data = Poll.objects.all()[:5] # 获取前5个数据,这里得到的是一个QuerySet, 了解更多QuerySet print(data) return render(request, 'index.html', {'lst':lst, "data":data}) ## index.html ## 在 body 标签中 增加如下内容 {% if data %} <ul> {% for i in data %} <li> {{ i.id }}</li> <li> {{ i.question }}</li> <li> {{ i.pub_date }}</li> {% endfor %} </ul> {% endif %}
这些还不够,我们在写django项目的时候,很多时候是要用到bootstrap这怎样的框架的。
在django中我们这样去配置。
在setting.py末尾添加如下内容:
# 更多内容
STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'statics'), )
# static 目录结构 . ├── blog ├── db.sqlite3 ├── manage.py ├── poll ├── static │ └── bootstrap │ ├── css │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ └── bootstrap-theme.min.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ ├── jquery-3.1.1.js │ └── js │ ├── bootstrap.js │ ├── bootstrap.min.js │ └── npm.js └── templates
# html文件 部分设置
.........
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css"> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap-theme.css"> <script src="/static/bootstrap/jquery-3.1.1.js"></script> <script src="/static/bootstrap/js/bootstrap.js"></script> .........
<!--使用bootstrap --> <h1> <p class="bg-primary">Something Something Something</p> <p class="bg-success">Something Something Something</p> <p class="bg-info">Something Something Something</p> <p class="bg-warning">Something Something Something</p> <p class="bg-danger">Something Something Something</p> </h1> <!-- 通过 JavaScript 启动一个模态框。此模态框将从上到下、逐渐浮现到页面前。 --> <!-- Button trigger modal --> <button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal"> Launch demo modal </button> <!-- Modal --> <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> <h4 class="modal-title" id="myModalLabel">Modal title</h4> </div> <div class="modal-body"> ... </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> <button type="button" class="btn btn-primary">Save changes</button> </div> </div> </div> </div>
前端向后端提交数据
## views.py if request.method == "GET": print(request.GET) print("GET username: ", request.GET.get("username")) # request.GET可以看成一个字典,用GET方法传递的值都会保存到其中, print("GET password: ", request.GET.get('password')) # 也可以用 request.GET.get('key', None)来取值,没有时不报错 elif request.method == "POST": print("POST username", request.POST['username']) print("POST username", request.POST['password']) ## index.html <form action="/" method="post"> {% csrf_token %} <!--防御 CSRF(Cross Site Request Forgery, 跨站域请求伪造)--> <!--网页的值传到服务器是通过 <input> 或 <textarea>标签中的 name 属性来传递的 --> <input type="text" name="username"> <br> <input type="text" name="password"> <br> <input type="submit" value="提交"> </form>
Web服务器开发领域里著名的MVC模式是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的、松耦合的方式连接在一起,
M 模型负责业务对象与数据库的映射(ORM),
V 视图负责与用户的交互(页面),
C 控制器接受用户的输入调用模型和视图完成用户的请求:
Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同,Django的MTV分别是值:
M 代表模型(Model):负责业务对象和数据库的关系映射(ORM)。
T 代表模板 (Template):负责如何把页面展示给用户(html)。
V 代表视图(View):负责业务逻辑,并在适当时候调用Model和Template。
除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的View处理,View再调用相应的Model和Template,MTV的响应模式如下所示
过程:
1. 客户端发送请求
2. Web服务器(中间件)接收到请求
3. urlconf中找到对应的 view 函数
4. view函数根据请求,调用相应的Model存取数据、获取 Template 向用户展示数据
5. view函数根据处理结果,返回一个Http相应给web服务器
6. web服务器将相应发送给客户端