Web框架Django使用概览

Web框架Django使用概览

标签: django python


1 开始一个新项目

django的安装比较简单,在命令行里执行下面的命令。

pip install django

为了能使用django已有的模板代码,需要使用django-admin命令来执行诸如创建项目,创建项目下的子模块(在django中称为app)的工作。django-admin会帮我们准备好一系列目录结构和文件,在保持文件和目录规范同时减少我们的工作量。

下面以创建项目mysite为例说明创建过程,执行

$ django-admin startproject mysite

''' 项目目录结构
mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        wsgi.py
'''

进入mysite目录,执行

$ python manage.py startapp app1
''' app1结构
app1/
    __init__.py
    admin.py
    apps.py
    migrations/
        __init__.py
    models.py
    tests.py
    views.py
'''

为了激活新增加的app1模块,需要修改mysite.settings.py,在INSTALLED_APPS的列表项中增加一项’app1’。

此外django自带一套管理后台系统,支持简单的用户和组管理功能以及对应的权限管理,为了启用此功能,可以执行下面初始化工作。

python manage.py migrate
python manage.py createsuperuser
python manage.py runserver 0.0.0.0:8000

这样就可以通过本地localhost:8000/admin便可见到admin后台的登录页面了。

2 MVT简介

django使用了MVT的模式,数据模型使用Model来建模,View用来接收/处理/返回数据,而Template用来渲染展现内容。通过MVT模式将数据/处理/表现三层进行了分离。

Model支持ORM,根据需要,可以创建普通的只有数据项模型,也可以创建带有业务逻辑的模型。

对于简单的应用,业务逻辑可以放在View里处理,如果是复杂系统,那就需要创建单独的业务层,在view里借助业务层来完成相应的功能。

Template使用了自定义的模板语法,可以根据情况使用。如果有独立的前端支持,完全可以不借用模板。前后端只通过数据api接口交互,前端可以使用各种流行框架来解决展现逻辑。如果人员或模块划分没那么细分,使用模板在后端进行全部页面渲染或者部分渲染都是可行的。

3 View

如上节所述,View层用于接收请求,处理请求,并返回数据。模块的view处理逻辑都位于的各模块的views.py文件中,下面的代码示例了一个没有什么作用的处理器,它返回一个显示一行"hello world"的页面。更复杂的功能包括数据库访问,业务规则应用,远程过程调用等,都可以在这样一个函数中进行流程的组织。

# app1/views.py

from django.http import HttpResponse


def test(request):
    return HttpResponse('Hello world')

目前客户是访问不到这个页面的,因为还没有为这个页面设置uri,或者说没有在django中为其设置路由。

4 路由

django的路由在文件urls.py中进行配置。在以项目名命名目录下的urls.py中进行全局路由分派,其会将子模块的请求派发到相应的app.urls中进行二级路由,下面展示示例中的mysite的urls文件内容:

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

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

简单的说,所有路由规则都定义在urlpatterns的列表内,每一项都是一条规则。定义了一个路径对应的处理函数或要派发模块的urls配置。
下面示例了将上节views.test返回的页面在app1.urls.py中添加路由规则的代码:

# app1/urls.py

from django.conf.urls import url
from app1 import views

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

这样就可以访问http://localhost:8000/app1/test页面,可看到其中展示的"hello world"。

5 Model

5.1 数据模型定义与数据表

在django中定义数据模型十分便捷,其ORM框架可以十分方便的生成对应的DDL语句,并通过表管理器生成DQL/DML,向开发人员屏蔽了底层的数据库及SQL的知识。
下面以演员,电影和签约为例说明django中model的使用。假设影视公司需要跟踪演员和电影的签约和支付情况,建立下面的简化模型。Actor和Movie对应现实中的演员和电影,使用Contact来记录二者之间的合同关系,以及演员出演电影的角色信息,薪资情况等。

# app1/models.py

from django.db import models

class Actor(models.Model):
    name = models.CharField(max_length=128, db_index=True)
    birth = models.DateField()
    
    def __unicode__(self):
        return self.name


class Movie(models.Model):
    name = models.CharField(max_length=128, db_index=True)
   
    actors = models.ManyToManyField(Actor, through='Contact')

    def __unicode__(self):
        return self.name


class Contact(models.Model):
    actor = models.ForeignKey(Actor)
    movie = models.ForeignKey(Movie)
    role  = models.CharField(max_length=64)
    payment = models.IntegerField()
    sign_date = models.DateField()
   
    def __unicode__(self):
        return self.role + self.sign_date.strftime('%Y-%m-%d')



在django中,models下定义了各种类型的字段,如DateField, IntegerField等,对应了SQL创建的各种column类型。此外还定义了PramaryKey, ForeignKey字段来声明主外键。这些字段都会对应到具体数据库表中的字段。

为了声明演员和电影之间的这种关系,需要使用 ManyToManyField,其声明的字段并不会在表中存在,但它告诉django框架,二者之间存在多对多的关系,并指明关系模型的名称。在一对多对多关系中,只需要在其中任意一个模型中声明即可,不需要在声明两次。

在定义了模型之后,就可以让框架帮我们创建对应的数据表了。在项目目录下执行命令:

python manage.py makemigrations app1
python manage.py migrate

其中第一行用来为app1生成一个迁移文件,存储在对应模块的migration目录下。
第二行是执行具体的数据库创建/修改工作。
在执行migrate之前,可以执行sqlmigrate app1 0001来查看自动生成的SQL语句。如下所示。


BEGIN;

CREATE TABLE "app1_actor" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(128) NOT NULL, "birth" date NOT NULL);

CREATE TABLE "app1_contact" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "role" varchar(64) NOT NULL, "payment" integer NOT NULL, "sign_date" date NOT NULL, "actor_id" integer NOT NULL REFERENCES "app1_actor" ("id"));

CREATE TABLE "app1_movie" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(128) NOT NULL);

ALTER TABLE "app1_contact" RENAME TO "app1_contact__old";

CREATE TABLE "app1_contact" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "role" varchar(64) NOT NULL, "payment" integer NOT NULL, "sign_date" date NOT NULL, "actor_id" integer NOT NULL REFERENCES "app1_actor" ("id"), "movie_id" integer NOT NULL REFERENCES "app1_movie" ("id"));

INSERT INTO "app1_contact" ("sign_date", "movie_id", "payment", "role", "actor_id", "id") SELECT "sign_date", NULL, "payment", "role", "actor_id", "id" FROM "app1_contact__old";
DROP TABLE "app1_contact__old";

CREATE INDEX "app1_actor_name_b00a760a" ON "app1_actor" ("name");
CREATE INDEX "app1_movie_name_2c168972" ON "app1_movie" ("name");
CREATE INDEX "app1_contact_actor_id_64e85f27" ON "app1_contact" ("actor_id");
CREATE INDEX "app1_contact_movie_id_2ae6d051" ON "app1_contact" ("movie_id");

COMMIT;

从SQL中我们可以知道,创建的表名为{子模块名_模型名},表中自动创建了自增类型的主键id。

5.2 使用模型进行增/删/改/查

下面以电影碟中谍为例来说明新增模型到数据表的方式

from models import Actor, Movie, Contact

# 使用表管理器objects来新增记录
movie = Movie.objects.create(name='碟中谍6:全面瓦解')

# 使用模型对象新增记录
actor = Actor()
actor.name = '汤姆·克鲁斯'
actor.birth = '1962-07-03'
actor.save()

# 添加签约关系
Contact.objects.create(movie=movie, actor=actor,role='伊森·亨特', payment=800, sign_date='2018-01-10')

# 添加另一个演员及签约
actor = Actor.objects.create(name='丽贝卡·弗格森', birth='1983-10-19')
actor.save()

Contact.objects.create(movie=movie, actor=actor,role='伊尔莎·浮士德', payment=400, sign_date='2018-01-20')

下面列出一些常用的查询方式:

# 单表查询
actors = Actor.objects.filter(name__contains='汤姆·克鲁斯')
actor = actors[0]
print actor.name, actor.birth # 汤姆·克鲁斯 1962-07-03

# 由对象进行关联查询
tom_movies = actor.movie_set.all()
print tom_movies # <QuerySet [<Movie: 碟中谍6:全面瓦解>]>


tom_contacts = actor.contact_set.all()
print tom_contacts  # <QuerySet [<Contact: 伊森·亨特2018-01-10>]>


# 表关联查询
contacts = Contact.object.filter(actor__name__contains='汤姆·克鲁斯', movie__name__contains='6')
contact = contacts[0]
print contact.actor.name, contact.movie.name, contact.role
# 汤姆·克鲁斯 碟中谍6:全面瓦解 伊森·亨特


# 反向关联查询
actors = Actor.objects.filter(contact__sign_date__gt='2018-01-01')
print actors # <QuerySet [<Actor: 丽贝卡·弗格森>, <Actor: 汤姆·克鲁斯>]>

actors = Actor.objects.filter(contact__movie__name__contains='6')
print actors
# <QuerySet [<Actor: 丽贝卡·弗格森>, <Actor: 汤姆·克鲁斯>]>

模型的修改与删除更加简单,调用对象上的delete即可删除对象,将对象修改后进行save即可实现数据的更新。

5.3 order_by与limit

上节所有查询结果返回的是一个支持迭代的QuerySet,如果需要排序,在结果集上调用order_by(‘field’)即可。

如果需要限制返回的结果数量,像数据一样进行切片即可,如Actor.objects.all()[0:10]

django的查询集是lazyload的,只有真的需要数据的时候才会执行数据库查询。

5.4 聚合查询

from django.db.models import Sum, Avg

# 计算碟6所有演员的费用
Contact.objects.filter(movie__name__contains='碟中谍6').aggregate(total=Sum('payment'))
# Out[17]: {'total': 1200}

# 计算每部电影演员费用的汇总
qs = Contact.objects.values('movie__name').annotate(cost=Sum('payment'))

# <QuerySet [{'movie__name': u'\u789f\u4e2d\u8c0d6\uff1a\u5168\u9762\u74e6\u89e3', 'cost': 1200}]>

print qs.query
# SELECT "app1_movie"."name", SUM("app1_contact"."payment") AS "cost" FROM "app1_contact" INNER JOIN "app1_movie" ON ("app1_contact"."movie_id" = "app1_movie"."id") GROUP BY "app1_movie"."name"

6 Template

Template可以是纯html文档,在view中通过将html文档作为字符串返回即可。

如果需要django在后端动态渲染数据,例如返回符合条件的结果列表,可以使用template。在template中可以对传入的对象进行求值,从而生成实例页面。

template的求值语法为{{value}},同时支持条件及循环等tag,tag语句需要使用{%tag sentence %}将sentence进行包裹,并需要以{%endtag%} 来声明tag结束。

下面是一个template页面。

# template/app1/test.html
<html>
<head>
    <title>{{title}}</title>
</head>

<body>
    <ul>
        {%for actor in actors%}
            <li>{{actor.name}} -- {{actor.birth}}</li>
        {%endfor%}
    </ul>
</body>

为了将数据传入这个模板页面,需要在views中函数中传递相应的参数给模板。

# app1/views.py
from app1.models import Actor
from django.shortcuts import render

def test(request):
    actors = Actor.objects.all()
    context = {
        'title': '所有演员',
        'actors': actors
    }
    html = render(request, 'app1/test.html', context)
    return html

7 Admin定制

django中的admin站点可以通过注册的机制,快速将模型转化为管理页面,在页面中可以实现列表查询,数据的增删改等各种操作。

下面列出了将Actor模型注册到admin站点的代码,其中声明的ContactsInline类是为了在演员的编辑页面中可以关联编辑签约模型数据。

from django.contrib import admin
from web.models import *


class ContactsInline(admin.TabularInline):
    model = Contact
    extra = 0

class ActorAdmin(admin.ModelAdmin):
    list_display = ['name', 'birth']
    inlines = [ContactsInline, ]

admin.site.register(Actor, ActorAdmin)

完成之后,打开admin站点,便可以看到新增的Actor管理页面入口。

8 项目Settings

在项目的根目录下存放着项目的Settings,如果要指定不同的设置,可以通过环境变量DJANGO_SETTINGS_MODEULE来设置。

export DJANGO_SETTINGS_MODULE=mysite.settings

另一种是在python代码中通过os模块来设置

import os

os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'

在代码中可以动态的修改当前的配置

from django.conf import settings

settings.DEBUG = True

有时可能需要在非django项目中复用django的功能或代码,例如引用已经定义的django model,这也是可以的。参见下面的代码片段:

import sys
import os

setting_path = '/path/of/settings.py'
setting_dir = os.path.dirname(setting_path)

sys.path.append(setting_dir)
os.environ['DJANGO_SETTINGS_MODULE'] = 'setting_dir.settings'

import django
django.setup()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值