Django基础

Web框架

Web开发除了代码全部从头写起以外,还可以在其他人已经有的基础上进行开发,简化开发流程,这些Web开发环境统称为Web框架。
全栈表示可以开发Web应用所有阶段和层次的代码。框架可以提供所有相关的服务,如Web服务器,数据库ORM,模板和所有需要的中间件hook。
Django是由一个开发团队作为单个突出创建的,但并不是所有框架都要遵循这中哲学,以TurboGears为例,这是一个非常优秀的全栈系统,由分散在全世界的开发者开发,其作为胶水代码,将栈中其他独立的组件组合起来,如ToscaWidgets(高级Web部件,它可利用多种JS框架,如ExLtJs,JQuery)、SQLAlchemy(ORM)、Pylons,还有Genshi(模板化)。
Web服务器网关接口(WSGI)标准的建立加速了Web框架的发展。有了WSGI,应用开发者就可以方便的切换WSGI兼容的服务器,而无须担心需要改变应用代码。

Django简介

Django自称是“能够很好的应对应用上线期限的Web框架”。Django社区使用另一种形式的MVC模式,在Django中,它称为模型-模版-视图,简称MTV,数据模型保持不变,但视图在Django中是模版,因为模版用来定义用户可见的内容,最后,Django中的视图表示视图函数,他们组成控制器的逻辑,这与MVC完全相同,但仅仅是对不同角色进行了不同的解释。

安装

easy_install django
or
sudo python setup.py install

这里建议使用“容器”环境,如virtualenv,使用virtualenv可以同时安装多个版本的Python,Django,数据库等。每个环境在独立的容器中运行,可以自由创建,管理,执行,销毁。关于virtualenv可以参见http://pypi.python.org/pypi/virtualenv

项目和应用

项目是一系列文件,用来创建并运行一个完整的Web站点,在项目文件夹下,有一个或者多个子文件夹,每个子文件夹有特定的功能,称为应用,应用并不一定要位于项目文件夹中,应用可以专注于项目某一方面的功能,或可以作为通用组件,用于不同的项目。应用是一个具有特定功能的子模块,这些子模块合起来就能完成Web站点的功能。

创建项目

使用python安装文件下的Script中的django-admin创建Django项目

django-admin startproject mysite

创建成功后
这里写图片描述
在Django中基本的文件就包含4个,

文件名描述/用途
__init__.py告诉python这是一个软件包
urls.py全局URL配置
setting.py项目相关的配置
manage.py应用的命令行接口

startproject创建的每个文件都是纯python文件,没有ini文件或者xml文件,因为纯粹的Python既可以在不同的框架添加复杂东西的情况下拥有灵活性,同时也可以根据不同的情况从其他文件导入额外的配置,或动态计算数值,而不是硬编码。

运行开发服务器

Django内置了一个Web服务器,该服务器运行在本地,专门用于开发阶段。存在这个开发服务器的原因有三个:

  1. 使用开发服务器,可以直接运行与测试项目和应用,无需完整的生产环境
  2. 当改动python源码文件并重新载入模块的时候,开发服务器会自动检测,这样既能节省时间,也能方便地使用系统,无需你每次编辑代码后手动启动
  3. 开发服务器知道如何为Django管理应用程序寻找和显示静态媒体文件,所以无须立即了解管理方面的内容
python manage.py runserver 0.0.0.0:8888

在浏览器中访问localhost:8888
这里写图片描述

说明创建成功,在命令行中我们可以看见

[30/Oct/2016 19:42:27] "GET / HTTP/1.1" 200 1767

这是日志,每一行含有四个部分,从左到右,依次是时间戳,请求,HTTP响应编码,以及字节数。

创建应用

在这个项目下创建一个应用

>python manage.py startapp blog

创建成功
这里写图片描述
应用文件介绍

文件名描述/目的
__init__.py告诉python这是一个包
urls.py应用的URL配置文件,这个文件并不像项目的URL配置文件那样自动创建
models.py数据模型
views.py视图模型
tests.py单元测试

为了让Django知道这个新的应用是项目的一部分,需要编辑settting.py。在INSTALLED_APPS这个元组中将blog添加到元组的末尾

这里写图片描述

创建模型来添加数据库服务

models.py文件,在这里将定义博客的数据结构。数据模型表示将会存储在数据库每条记录中的数据类型,Django提供了许多字段,用来将数据映射到应用中。
blog/models.py

from __future__ import unicode_literals

from django.db import models

# Create your models here.

class BlogPost(models.Model):
    title=models.CharField(max_length=150,null=False)
    body=models.TextField(null=True,blank=True)
    timestamp=models.DateTimeField()

设置数据库

在这里我们使用mysql数据库,不过在测试环境中,建议使用sqlite,SQLite将数据库另存为文件系统中的单个文件。访问控制就是简单的文件访问权限。
使用MYSQL
需要在setting.py中配置数据库信息,首先我们应该在数据库中创建一个名叫blog数据库。

mysql> create database blog charset utf8;

setting.py

这里写图片描述

如果是SQLite,由于SQLite使用本地文件来存储数据,本地文件系统的访问权限就是数据库的访问控制,SQLIte不仅可以使用本地文件,还可以使用纯内存数据库,因此针对SQLITE数据库的配置,在settings.py中


DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': '/tmp/mysite.db',
    }
}

创建表

生成配置文件
G:\python_study\PYCHARM\WEB\DjangoStudy\mysite>python manage.py migrates

Unknown command: 'migrates'
Type 'manage.py help' for usage.

根据配置文件创建数据库相关
G:\python_study\PYCHARM\WEB\DjangoStudy\mysite>python manage.py migrate
System check identified some issues:

WARNINGS:
?: (mysql.W002) MySQL Strict Mode is not set for database connection 'default'
        HINT: MySQL's Strict Mode fixes many data integrity problems in MySQL, s
uch as data truncation upon insertion, by escalating warnings into errors. It is
 strongly recommended you activate it. See: https://docs.djangoproject.com/en/1.
10/ref/databases/#mysql-sql-mode
Operations to perform:
  Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying blog.0001_initial... OK
  Applying sessions.0001_initial... OK

然后我们授权一个创建一个超级用户,用于登陆Django自带的管理界面

G:\python_study\PYCHARM\WEB\DjangoStudy\mysite>python manage.py createsuperuser
Username (leave blank to use 'abnerchow'): admin
Email address:
Password:
Password (again):
Superuser created successfully.

查看数据库中的表
这里写图片描述

Django管理应用

设置admin

每次向项目中添加新应用时,需要执行makemigrations和migrate来确保在数据库中创建所需要的表。既然admin设置完成,所要做的就是给定一个URL,这样才能访问admin页面,在自动生成的项目urls.py中。

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

urlpatterns = [
    url(r'^admin/', admin.site.urls),
]

最后,应用程序需要告知Django哪个模型需要在admin页面中显示并编辑,为了做到这一点,只需要注册BolgPost,在blog/admin.py中添加一下代码

from django.contrib import admin
import models
# Register your models here.

admin.site.register(models.BlogPost)

使用admin

在浏览器的地址栏中输入localhost:8888/admin进入
这里写图片描述
接下来用我们刚刚注册的超级用户登陆
这里写图片描述
注意:如果列表中没有列出我的类,有三种常见的原因:

  1. 忘记通过admin.site.register()注册模型类
  2. 应用的models.py文件中存在的错误
  3. 忘记将应用添加到settings.py文件中的INSTALLED_APPS元组中

    接下来我们就可以使用blog,向数据库中添加内容了
    这里写图片描述
    添加成功
    这里写图片描述
    但是我们发现,我们无法看见内容
    这时候就需要修改一下代码了
    在admin.py中修改

from django.contrib import admin
import models
# Register your models here.


class BlogPostAdmin(admin.ModelAdmin):
    list_display = ('title','timestamp')

admin.site.register(models.BlogPost,BlogPostAdmin)

这里写图片描述

创建用户界面

从Django的角度来看,Web页面应该有以下几个经典组件:
1. 一个模版:用于显示通过Python类字典对象传入的信息
2. 一个视图:用于执行针对请求核心逻辑,视图会从数据库中获取信息,并格式化显示结果
3. 一个URL模式:将传入的请求映射到对应的视图中,同时也可以将参数传递给视图。

Django Template

>>> from django.template import Context, Template
>>> t = Template('My name is {{ name }}.')
>>> c = Context({'name': 'Stephane'})
>>> t.render(c)
u'My name is Stephane.'

同一模板,多个上下文
一旦有了 模板 对象,你就可以通过它渲染多个context, 例如:

>>> from django.template import Template, Context
>>> t = Template('Hello, {{ name }}')
>>> print t.render(Context({'name': 'John'}))
Hello, John
>>> print t.render(Context({'name': 'Julie'}))
Hello, Julie
>>> print t.render(Context({'name': 'Pat'}))
Hello, Pat

无论何时我们都可以像这样使用同一模板源渲染多个context,只进行 一次模板创建然后多次调用render()方法渲染会更为高效:

# Bad
for name in ('John', 'Julie', 'Pat'):
    t = Template('Hello, {{ name }}')
    print t.render(Context({'name': name}))

# Good
t = Template('Hello, {{ name }}')
for name in ('John', 'Julie', 'Pat'):
    print t.render(Context({'name': name}))

在到目前为止的例子中,我们通过 context 传递的简单参数值主要是字符串,然而,模板系统能够非常简洁地处理更加复杂的数据结构,例如list、dictionary和自定义的对象。

在 Django 模板中遍历复杂数据结构的关键是句点字符 (.)。

最好是用几个例子来说明一下。 比如,假设你要向模板传递一个 Python 字典。 要通过字典键访问该字典的值,可使用一个句点:

>>> from django.template import Template, Context
>>> person = {'name': 'Sally', 'age': '43'}
>>> t = Template('{{ person.name }} is {{ person.age }} years old.')
>>> c = Context({'person': person})
>>> t.render(c)
u'Sally is 43 years old.'

同样,也可以通过句点来访问对象的属性。 比方说, Python 的 datetime.date 对象有 year 、 month 和 day 几个属性,你同样可以在模板中使用句点来访问这些属性:

>>> from django.template import Template, Context
>>> import datetime
>>> d = datetime.date(1993, 5, 2)
>>> d.year
1993
>>> d.month
5
>>> d.day
2
>>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.')
>>> c = Context({'date': d})
>>> t.render(c)
u'The month is 5 and the year is 1993.'

创建URL模式

服务器通过WSGI功能,最终会将请求传递给Django,接受请求的类型(GET,POST)和路径(URL中除了协议、主机、端口之外的内容)并传递到项目中的URLconf文件(mysite/urls.py)这些信息必须通过正则表达式正确匹配到对应的路径中,否则,服务器会返回404错误。
为了正确分离项目和应用的URL配置,需要通过两步来定义URL映射规则并创建两个URLconf,一个是用于项目,一个用于应用。

路由系统

1.静态路由
2.动态路由:按照顺序,第n个匹配的数据,交给函数的第n个参数,严格按照顺序模版的方法:将匹配的参数,传给指定的形式参数
3.二级路由
project_name:
urls.py

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

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^app01/',include('app01.urls')),
    url(r'^app02/',include('app02.urls')),
]

当使用include()时,会移除当前的URL路径头,路径中剩下的部分传递给下游URLconf中的patterns()函数。


app01
urls.py


from django.conf.urls import url
from django.contrib import admin
import views
#匹配并调用views中对应的函数
urlpatterns = [
    url(r'^test/',views.test), 
    url(r'^news/(\d+)/(\d+)',views.news),
    url(r'^page/(?P<n1>\d+)/(?P<n2>\d+)',views.page),
]

创建视图函数

#coding:utf-8
from django.shortcuts import render
from datetime import datetime
import models
import random
# Create your views here.

def blogInfo(request):
    #插入数据
    title=''
    for i in range(random.randint(1,7)):
        title+=chr(random.randrange(65,123))
    body=''
    for i in range(random.randint(1,100)):
        body+=chr(random.randrange(65,123))

    models.BlogPost.objects.create(title=title,body=body,timestamp=datetime.now())
    post=models.BlogPost.objects.all()
    #返回给客户端的模版内容内容
    return render(request,'archive.html',{'posts':post}) 

示例

archive.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Blog</title>
</head>
<body>
    {% for post in posts %}
        <h2>{{ post.title|title }}</h2>
        <p>{{ post.timestamp }}</p>
        <p>{{ post.body }}</p>
    {% endfor %}
</body>
</html>

blog/mysite/urls.py

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

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^blog/',include('blog.urls')),
]

blog/blog/urls.py

from django.conf.urls import url,include
import views

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

blog/blog/models.py

from __future__ import unicode_literals

from django.db import models

# Create your models here.

class BlogPost(models.Model):
    title=models.CharField(max_length=150,null=False)
    body=models.TextField(null=True,blank=True)
    timestamp=models.DateTimeField()

blog/blog/views.py

#coding:utf-8
from django.shortcuts import render,HttpResponse
from datetime import datetime
from django.template import loader,Context
import models
import random
# Create your views here.

def blogInfo(request):
    #插入数据
    for i in range(10):
        models.BlogPost.objects.create(title="post #%d"%i,body="body of post #%d"%i,timestamp=datetime.now())
    #查看前10条数据
    post=models.BlogPost.objects.all()[:10]

    t=loader.get_template('archive.html')
    c=Context({'posts':post})
    return HttpResponse(t.render(c))

    # return render(request,'archive.html',{'posts':post})

结果示例
这里写图片描述

处理用户输入

使用form表单

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Blog</title>
</head>
<body>
    {% if flag == 1 %}
    <form method="post" action="/blog/">
        <br>Title
        <p><input type="text" name="title"></p>
        <br>内容
        <p><textarea name="body" style="width:500px;height:200px; "></textarea></p>
        <br><input type="submit">
    </form>
    <hr>
    {% endif %}
    {% for post in posts %}
        <h2>{{ post.title|title }}</h2>
        <p>{{ post.timestamp }}</p>
        <p>{{ post.body }}</p>
    {% endfor %}
</body>
</html>

views.py

#coding:utf-8
from django.shortcuts import render,HttpResponse
from datetime import datetime
from django.template import loader,Context
import models
import random
# Create your views here.

def blogInfo(request):
    #插入数据
    # for i in range(10):
    #     models.BlogPost.objects.create(title="post #%d"%i,body="body of post #%d"%i,timestamp=datetime.now())
    # 查看数据
    post = models.BlogPost.objects.all()[:10]

    #接受数据
    if request.POST:
        title=request.POST['title']
        body=request.POST['body']
        flag=0
    else:
        flag=1
        return render(request,'archive.html',{'flag':flag,'posts':post})
    #查看数据
    post=models.BlogPost.objects.all()[:10]

    t=loader.get_template('archive.html')
    c=Context({'posts':post,'flag':flag})
    return HttpResponse(t.render(c))

    # return render(request,'archive.html',{'posts':post})

结果示例:
这里写图片描述

  • 提交
    这里写图片描述

跨站点请求伪造

Django有数据保留特性,这不允许不安全的POST通过跨站点请求伪造来进行攻击,对CSRF的解释超出了本书的范畴,对于这个简单的应用,需要修改两个地方,这两处都需要向已经有的代码添加一些代码
1. 向表单中添加CSRF标记({% csrf_token %}),让这些POST回到对应的页面。
2. 通过模版发送向这些标记请求的上下文实例

请求上下文实际上是一个字典,它包含关于请求的信息

<form method="post" action="/blog/">
{% csrf_token %}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值