打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Django 全栈项目经验


作者:kinegratii

来源:https://kinegratii.github.io/2017/07/31/django-full-stack-note/

概述

BWS项目是自己一年来在开发的项目。本文就项目中一些技术选型、功能实现、项目流程做一些简单的总结。

python3

虽然Python3发布已经10年之久,但是2和3之争直到今天依旧存在,对于如何学习,每个人都有自己的理解和学习策略。我个人看法:

  • 果断学习面向未来的3;

  • 3和2的差别对于学习过程没有太多的影响,学好了3自然也能够很快上手2了;

  • 常见的第三方库大多数(80%以上)是支持Python3的;

  • 不过在系统安装的时候总是23共存的,可以自由切换;

今年4月份重新开发的时候做了一个比较激进的做法:完全抛弃对Python2的支持。当时的考量,把这个项目作为Django持续学习的一个示范项目,毕竟 Django的下一个大版本2.0(预计2017年12月发布),也已经要求最低版本为3.5了。

其实在项目中使用几个Python2不支持的语法和没有的标准库,就可以达到以上目的,具体来说,在代码中使用了以下几个语法:

  • 字典合并创建语法(PEP448)

  • 强制关键字传参(PEP3102)

根据 PEP448,在Python3.5中可以使用更加简洁明了的代码实现合并多个字典。

  1. # 3.5+

  2. combination = {**first_dictionary, 'x': 1, 'y': 2}

  3. # 3.5以下

  4. combination = first_dictionary.copy()

  5. combination.update({'x': 1, 'y': 2})

另外Python3在文本和二进制方面作了比较大的改变,这对文件导入导出功能开发提供了便利,不用再纠结2的编码问题,可以集中解决业务层面的问题。

Django

我也算是Django的忠实用户了,从1.4到1.11都有用到,不断看到Django的成长和壮大。1.4/1.8/1.11是LTS版本,项目使用的是1.10。这些年来Django比较大的变更有:

  • 自定义用户类型:这个是1.5就有的功能了,之前只能使用内置的用户类,连使用邮箱作为用户名也不能直接支持;

  • 数据库迁移:1.7借鉴 South 实现的,这个是开发的利器,修改用户模型时候可以使用命令一键将修改同步到数据库,而忽略具体的数据库类型;

  • 自定义过滤查询:1.7,这个主要用于封装一些业务数据库查询。

  • 多模板支持:1.8引入的,Django自己的模板引擎效率历来为人们所诟病,现在可以在Django中使用Jinja2这样的模板了。

  • 表单控件支持模板渲染:Django表单其实是着重于后端验证,前端相对薄弱,导致定制起来没有那么顺手。最新的1.11引入的可以通过模板文件定制控件样式等等。

CBV

强烈建议使用 Class-Based-View 组织视图处理函数。

Class-Based-View 是相对于Function-Based-View而言,主要支持封装,减少重复的代码编写工作,逻辑流程清晰,经过测试过的。在具体编写代码还是一定要查看源代码,才能理解其中的功能实现。

CBV的核心是Mixin模式。

Mixin是一种将多个类中的功能单元的进行组合的利用的方式,这听起来就像是有类的继承机制就可以实现,然而这与传统的类继承有所不同。通常mixin并不作为任何类的基类,也不关心与什么类一起使用,而是在运行时动态的同其他零散的类一起组合使用。

使用mixin机制有如下好处:可以在不修改任何源代码的情况下,对已有类进行扩展;可以保证组件的划分;可以根据需要,使用已有的功能进行组合,来实现'新'类;很好的避免了类继承的局限性,因为新的业务需要可能就需要创建新的子类。

现在也基本上不写视图函数了,项目上能见到的也就是 django.contrib.auth.login 等几个函数了,不过现在也要改成视图类形式了。

是否启用admin

虽然admin是Django的主要优势所在,但是它的使用场景有限,主要由于整合许多功能,比如分页、过滤、搜索、增删改查和批量操作等等,相互之间具有非常高的耦合度。在没有提供公开的API下去实现一些定制往往是'牵一发而动全身',最后基本上也改的是不成样子。

由于项目中没有使用内置的admin组件,增删改查的页面就需要多花一点时间自己去适配。

日志模型也要自己去设计,项目中我自己添加了ip这个字段,这个是原来所没有的。

后端数据API - DRF

后端数据采用的是 Django Rest Framework 这个框架,覆盖了大多数需求,包括:

  • 搜索/分页

  • 访问权限

  • 请求限制(频率、IP)

  • 表单验证

前端 Amaze UI

前端UI用的是 Amaze UI这个框架。不过从后来的发展形势来看,这是最为错误的决定了,主要原因在于无法和后端比较平稳地整合。

Django表单中有一个比较大的问题,如何需要定制控件样式,需要在Python代码中修改,而且需要应用的每一处都需要更改,灵活度不够。目前主要有两种解决方式:

  • 使用Django1.11版本的模板功能,这个功能刚刚推出,文档也只有一页的内容,不太建议使用。

  • 使用 django-crispy-forms 第三方库,这个库的思路也是使用模板html文件渲染控件,已经有一定的使用规模,但是支持 Bootstrap这样常见的UI框架,不支持 Amaze UI。

导入导出

实现导入导出功能主要使用的是 tablib 和 django-import-export 这两个库,其中后者依赖前者。

导出

编写 Resource, 几点值得注意的地方:

  • 需要设置表头,不仅需要指定字段 Meta.fields,同时也要显示指定 Meta.export_order的值,通常和 Meta.fields一样即可。

  • Meta.fields 里的元素必须是模型的数据库字段,不能是自定义的 property,这一点和 ModelAdmin.list_display 不一样。

  • 可以使用 dehydrate_FOO 函数重写导出内容

    class BillResource(resources.ModelResource):

    1. def get_export_headers(self):

      return ['流水号','月份', '类型','单价','用量', '金额']


    2. def dehydrate_price(self, obj):

      return obj.get_price_display


    3. class Meta:

      model = models.Bill



    4. fields = ('id', 'month', 'resource_type','price', 'amout', 'total')



    5. export_order = fields


导入

django-import-export也提供了几个Mixin,但问题这些和admin组件耦合很高,不利于一些自定义操作,所以直接使用tablib库比较好。根据官方文档,可以使用以下代码实现文件导入

  1. imported_data = Dataset().load(open('data.csv').read())

但其实load还有几个比较重要的参数:

  • format:文件格式,如果不写,使用自动识别,但有出错的机率,之前试验过一个xlsx文件在不同环境下识别为json文件的,因此建议这个参数也留给用户输入

  • headers:表示第一行是否是表头,这个参数在文档中没有表明,需要自行查看源代码获取相关信息。

所以最后就写成下面这个样子

  1. class BillUploadForm(form.Form):

  2.    import_file = forms.FileField()

  3.    format = forms.ChoiceField(choices=(('xlsx', 'xlsx'), ('xls', 'xls')))

  4. # 导入

  5. tablib.Dataset().load(form.cleaned_data['import_file'].read(), format=form.cleaned_data['format'], headers=False)

数据库查询优化

select_related函数

selectrelated是 django.db.models.QuerySet 类的一个方法,它解决了 ORM中常见的N+1查询效率问题,关于这一部分可以参考我之前写过的一篇文章《selectrelated函数性能基本测试》。

更新记录

在更新记录时可以使用 update_fields 参数指定只需更新的字段列表。这个参数在只更新一两个字段的时候特别有用。

  1. product.name = 'Name changed again'

  2. product.save(update_fields=['name'])

如果不指定参数的值,将更新所有字段。

测试和部署

分离配置文件

Django使用 settings 模块配置相关参数,这使得其很好的区分开发/测试/生产。

  1. - BillWorkingSystem

  2.    - BillWorkingSystem

  3.        - __init__.py

  4.        - settings.py

  5.        - test_settings.py

  6.        - urls.py

  7.        - wsgi.py

一个简单的testsettings.py如下,可以配置一些仅用于测试的项目,如数据目录 FIXTUREDIRS 。

  1. from BillWorkingSystem.settings import *

  2. class DisableMigrations(object):

  3.    def __contains__(self, item):

  4.        return True

  5.    def __getitem__(self, item):

  6.        return 'notmigrations'

  7. MIGRATION_MODULES = DisableMigrations()

  8. FIXTURE_DIRS = (

  9.    os.path.join(BASE_DIR, 'fixtures').replace('\', '/'),

  10. )

  11. UPLOAD_TEST_DATA_DIR = os.path.join(BASE_DIR, 'fixtures', 'test_data').replace('\', '/')

MIGRATION_MODULES 设置表示是否运行数据迁移脚本。上述例子设置为空,表示测试无需运行这些迁移脚本。

单元测试

单元测试主要测试那些返回为实际数据(如json/yaml)的视图。

测试采用标准的 django.test.TestCase,按照文档所描述的步骤,一步一步的编写。

  1. class BillCreateTestCase(TestCaseBase):

  2.    url = '/api/bill/create/'

  3.    def test_success(self):

  4.        data = {

  5.            'enterprise': 1,

  6.            'year': 2017,

  7.            'month': 1,

  8.            'amount': 4000,

  9.            'create_name': 'Test'

  10.        }

  11.        rsp = self.client.post(self.url, data)

  12.        self.assertEqual(201, rsp.status_code)

  13.        # 其他assert语句

  14.    def test_with_error_enterprise(self):

  15.        data = { } # 参数

  16.        rsp = self.client.post(self.url, data)

  17.        self.assertEqual(400, rsp.status_code)

  18.        # 其他assert语句

一个基本模式,

  • 一个TestCase表示一个主要功能,如一个POST请求

  • 每个 test_FOO 函数表示一种情况,包括正确和无效参数

  • 依次对响应对象的状态码和内容、数据变更进行断言(Assert)测试

docker部署

之前采用的是daocloud这个平台的工具。具体可参考《使用DaoCloud部署Django项目》这篇文章。由于对docker这方面没有一个完整的学习,加上daocloud.io更新到3版本,作了一些比较大的改变,后来就决定搬迁到阿里云服务器上,这样相对比较容易把握。

后记

轮子

什么是轮子 wheel,写多了代码就会发现一些代码具有共同之处,将其抽象并提取,慢慢地就形成了一个库,可以和别人分享。本质上来说,Django也是一个轮子。

持续开发

由于是个人项目,因此一些版本升级方面就比较随意,基本上新版本出来就完全废弃旧有版本。

第三方库

稳定才是真,不要为追求标新立异而盲目升级。


题图:pexels,CC0 授权。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Django(四)后台管理及Field参数
django之路由层
pycharm上运行django服务器端、以及创建app方法
Django save方法的update_fields参数
Django限制表单中ForeignKey对应下拉菜单选项数量的两种经典方法
Django 教程 10: 测试 Django 网页应用
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服