Django - 两周从入门到熟练工

初识 Django

以前 Python 后端开发框架中,对 Tornado 和 Flask 接触比较多,前者适合做为服务框架,后者因为轻量经常使用来构建简单的后台或服务。python

Django 之于上面两个 Web 框架,其自身实现了不少工具类库,显得更为笨重,但上手以后,不少功能不须要再本身实现,比较方便。docker

因为已经集成诸多功能,Django 也更常被用来做为后台开发框架。数据库

最近新接手一个后台开发任务也是基于 Django 开发,所以本文对最近这两周的所学作个自我总结。django

Django 几个模块用法

在具体讲代码以前,我先讲讲整个系统的架构。后端

刚接手任务时,数据库使用 MySQL5.5,对应的 Django 版本为 2.0(支持MySQL5.5的最高版本)。设计模式

考虑到系统对接了不一样产品线,一些数据格式存在不肯定性,我将数据库改成支持 JSON 格式的 MySQL5.7,Django 也对应升级到最新版 2.2。固然,使用其余数据库也是能够的,例如 PostgreSQL 或者 MongoDB,为了避免影响原来开发人员的操做习惯,我仍是继续使用 MySQL。api

同时考虑到平台存在上传、解析 Excel 文件这种耗时操做,我引入 Celery + RabbitMQ 实现这类操做的异步执行,优化用户体验。bash

Django 还有不少功能我暂时未使用到,其自己功能之强大着实减小了我造轮子的代码量,但因为初学,也确实花了很大功夫琢磨每一个功能。架构

下面讲讲这两周接触到的 Django 的几个模块以及基础用法,更详细的功能请查看官方文档。app

manage.py

在正式讲功能模块以前,必须得先介绍一下 Django 自带的强大的项目管理工具: django-admin

一般咱们建立一个 Django 项目的过程是这样:

# 安装 Django
pip install django
# 建立一个 Django 项目
django-admin startproject myproject
复制代码

在建立好 Django 项目后,项目根路径会生成一个 manage.py 文件。该文件实际执行的就是 django-admin 的功能,只不过已经配置好一些系统变量。

例如在项目内建立一个名为 mysite 的 App ,那么能够:

# 建立一个 App
python manage.py startapp mysite
复制代码

记住这个 mysite ,这是你的应用名而不只仅是文件夹名称,后面的开发代码都会准确引用这个名称。

manage.py 管理工具,能够方便地实现服务启动、数据库迁移等操做,特别是数据库迁移是我最经常使用也最爱用的功能,后面会提到。

Project 与 App

Django 中,有 Project(项目) 与 App(应用) 的概念,其区别以下:

Project 是整个项目的最高层级,能够在 Project 中对项目所需的依赖、环境等进行配置;

App 依托于项目,一个项目能够有多个应用。

通常来讲,一个独立的管理后台项目配置一个应用便可,将不一样的用户、项目、任务等功能都同属于一个 App。而若是须要开发一个内部管理后台,集成 2 个不一样的系统,这两个系统中各有项目、任务等模块,那么咱们就建立 2 个 App,由于这两个应用中的功能互不相关。

Model

Django 可用 ORM(对象关系映射) 模式操做数据库,举个例子:

# 获取当前用户的用户名
operator = request.user
return operator.username
复制代码

简单的两行代码,底层已经由 Django 实现了链接数据库(链接池)、查询用户表、返回 username 字段值等功能。

犹记得我在使用 Tornado 写服务时,须要本身维护一个数据库单例,关心服务启动时数据库实例的初始化顺序等等...

使用 ORM 就须要你对每张表建立一个 Model ,内含你对表字段的定义,例如字段类型、默认值、外键约束等。

举个例子,一个 Task 表的 Model :

models.py

class Task(models.Model):
    status = models.IntegerField(default=0)
    assignee = models.ForeignKey(settings.AUTH_USER_MODEL,
                                 related_name='+',
                                 null=True,
                                 on_delete=models.SET_NULL)
    create_time = models.DateTimeField(auto_now_add=True)
    update_time = models.DateTimeField(auto_now=True)
复制代码

这里也有要注意的地方:若是不特殊配置,Model 类名会被做为数据库表名的一部分,完整为:<APP_NAME>_<MODEL_NAME>,例如本例为 mysite_task

Migration

建立数据库表的 Model 以后,咱们就能够用 Migrations 功能建立表的初始化脚本,以及真正在数据库中建表:

# 初始化迁移脚本
python manage.py makemigrations [<APP_NAME>]
# 执行迁移操做,将数据库脚本在对应的数据库中执行一遍
python manage.py migrate
复制代码

Migration的功能强大在于,当你须要更新某个字段(例如将为某字段设置默认值)时,你能够直接修改 Model 中的字段配置便可,而后再次执行 makemigrations ,Django 会为你新建一个数据库脚本记录这次更新,你再执行 migrate 便能将这次更新写入到数据库中。

不只如此,咱们还能够新建一个空的 migrations 脚本,编写数据插入操做。有这个脚本,咱们能够在系统迁移时都保持一部分测试数据:

from django.db import migrations

# 插入方法
def insert_task(apps, schema_editor):
    Task = apps.get_model('mysite', "Task")
    db_alias = schema_editor.connection.alias
    Task.objects.using(db_alias).bulk_create([
        Task(name='task1'),
    ])

# 回滚方法
def rollback_task(apps, schema_editor):
    Task = apps.get_model('mysite', "Task")
    db_alias = schema_editor.connection.alias
    Task.objects.using(db_alias).filter(name="task1").delete()


class Migration(migrations.Migration):
    dependencies = [
        ('mysite', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(insert_task, rollback_task),
    ]

复制代码

每次迁移,Django都会存有记录,可以判断当前已经执行的操做,待执行的操做,存在风险的操做等。可使用 showmigrations 查看当前各个应用的数据库迁移脚本执行状况:

python manage.py showmigrations
复制代码

View

Django 是 MVT 模式,View 至关于 MVC 设计模式中的 Controller(控制器) 而非 View(视图)。真正的视图由 Template(模版)或者静态资源提供。

既然做为控制器,那么 View 的功能就相对清晰了:对接收到的请求数据(Request)作相应处理,并返回处理结果数据(Response)。

View 能够是类,也能够是函数+View装饰器的模式,直接上官方文档的代码吧:

基于类的 View:

from django.http import HttpResponse
from django.views.generic import ListView
from books.models import Book

class BookListView(ListView):
    model = Book

    def head(self, *args, **kwargs):
        last_book = self.get_queryset().latest('publication_date')
        response = HttpResponse('')
        # RFC 1123 date format
        response['Last-Modified'] = last_book.publication_date.strftime('%a, %d %b %Y %H:%M:%S GMT')
        return response
复制代码

基于装饰器的 View:

from django.views.decorators.http import require_http_methods

@require_http_methods(["GET", "POST"])
def my_view(request):
    # I can assume now that only GET or POST requests make it this far
    # ...
    pass
复制代码

这部分更多地涉及到业务逻辑,不够通用所以很少赘述了。

URL

URL 模块定义了 View 的路由地址:

mysite/urls.py

from django.urls import path
from books.views import BookListView

urlpatterns = [
    path('books/', BookListView.as_view()),
]
复制代码

能够配置多层路由,而后在最上层 URL 使用 includes 为子路由添加 Prefix:

myproject/urls.py

path('api/v1/', include('mysite.urls')),
复制代码

Test

做为测试开发工程师,对单元测试模块仍是须要了解下的(惋惜目前正处于开发前期,测试用例可能须要在项目基本稳定以后再补充了)。

和大部分 Web 框架同样,Django 的测试模块也是提供了一个 HTTP Client,使用相似接口测试的模式进行“单元测试”。

我在编写 Tornado 单元测试基础框架时候,是将 Tornado 与数据库的链接 Mock 掉,实际并未操做数据库。但在 Django 中,因为数据库的链接并不是由我本身实现,也由于使用了 ORM 模式,因此想真正与其余服务解耦进行单测有些困难,目前就先保持这种测试模式了。

仍是以官方示例代码为例吧,编写一个测试套件类:

import unittest
from django.test import Client

class SimpleTest(unittest.TestCase):
    def setUp(self):
        # Every test needs a client.
        self.client = Client()

    def test_details(self):
        # Issue a GET request.
        response = self.client.get('/customer/details/')

        # Check that the response is 200 OK.
        self.assertEqual(response.status_code, 200)

        # Check that the rendered context contains 5 customers.
        self.assertEqual(len(response.context['customers']), 5)
复制代码

运行单元测试:

python manage.py test
复制代码

代码目录结构

在我接手该项目时候,大部分的代码都糅合在一个 Python 文件中,让我有代码洁癖的人看着着实难受。

由于我本身也是才接触 Django,为了数理目录结构我也踩了很多坑,包括将各个模块拆分红不一样的应用等骚操做...

我就直接分享我目前正在使用的大体代码结构吧:

myapp/          # 存放应用具体实现的代码等
    app_mod1/
        models.py
        views.py
    app_mod2/
        models.py
        views.py
    admin.py
    app.py
    models.py
    views.py
    urls.py
myproject/      # 存放项目配置文件
    settings.py
    urls.py
dockerfiles/    # 存放先后端Dockerfile
docs/           # 存放项目相关的文档
tests/          # 存放测试套件
manage.py
README.md
复制代码

总结

在这个项目中,我还引入了 Django-REST-Framework(DRF) 框架的序列化和分页模块,Django-MySQL 对 JSON/List 格式数据的支持,以及 Celery 实现异步与定时任务等操做,总体来讲两周时间对 Django 以及扩展模块的学习算是满意,不过背后也是我天天下班继续工做到11点,周末在家查文档学习的辛苦。

Django 自己功能强大,是一个很是成熟的 Web 开发框架,可是上手有必定难度,须要下功夫好好消化官方文档阅读源码,而且应用在本身的项目中。

后期会继续分享本项目开发过程当中的一些经验技巧,欢迎持续关注!可私聊加群。

参考

www.djangoproject.com/

相关文章
相关标签/搜索