1
概述在python实现的web框架中,最为流行的要数据django和flask的,django是一个重型框架,主要的目标是使开发复杂的、数据库驱动的网站变得简单。这类框架包含了创建应用的几乎全部功能,如安全认证、URL routing、处理请求的视图系统、模板引擎、ORM及数据库schema映射等。此外,django具有很好的扩展性及性能。与Django类似的重型框架还包括Pyramid、TurboGears及Web2py等。Django官网对自己的解释为:
Flask是最流行的Python轻量级Web框架,目的是要建立一个非常稳定和可靠的Web应用的基础系统,Flask本身包含的功能并不全,但可以加上各种插件,扩展和其他模块构建功能强大的网站和应用,达到与Django框架一样能够支持复杂系统的需求。Flask基于Werkzeug WSGI toolkit以及 Jinja2 模板。本系列文章会围绕Django的使用和内部原理展开介绍,暂不展开介绍Flask,后续以单独的系列文章对Flask进行介绍。代码git repo:https://github.com/836304831/mp_weixin
2Django应用开发准备Django应用开发准备主要包括Django软件包的安装及开发环境生成。本文的实验环境为linux环境,在安装django之前,系统需要安装python的开发环境,可参考教程。安装好python开发环境后,使用pip 命令安装。
pip install django==1.8 # 也可以直接安装最新版本
pip install rest_framework
pip install django-rest-swagger
安装完成后,打开终端,输入django-admin, 若提示帮助,则说明安装成功,如下:
依赖安装好之后即可创建Django应用,先创建工程django-demo,然后在django-demo工程下执行:
django-admin startproject apps .
运行上述命令后,在django-demo目录下会生成一些文件,如下图:
manage.py: 主要代码如下,是用来和项目交互的命令行的工具。是对django-admin.py工具的一个简单包装, 后续的开发过程中,可能会管理多个应用,所以“DJANGO_SETTINGS_MODULE”的环境变量可能需要修改一下(后续会介绍相关内容)。
if __name__ == '__main__': os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'apps.settings') try: from django.core.management import execute_from_command_line except ImportError as exc: raise ImportError( "Couldn't import Django. Are you sure it's installed and " "available on your PYTHONPATH environment variable? Did you " "forget to activate a virtual environment?" ) from exc execute_from_command_line(sys.argv)
apps/urls.py:主要代码如下,是url入口,默认的admin是django后台的访问地址,对应的功能也已经实现。业务相关的地址需要开发者自行添加。一般来说,一个url关联一个处理视图(view),在视图中处理相关的业务逻辑。
from django.contrib import adminfrom django.urls import pathurlpatterns = [ path('admin/', admin.site.urls),]
apps/settings.py:Django的配置文件,在实际的业务开发过程中需要修改文件,主要修改的点包括:应用列表添加(开发者创建的应用),根url的配置,数据库的配置,django访问权限级别控制。主要代码如下:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.staticfiles', 'apps' # 添加创建的“apps”应用]ROOT_URLCONF = 'apps.urls' # 管理多个应用时可能需要修改# 权限的控制,请求数据库分页的大小等REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', ), 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', # 'rest_framework.permissions.DjangoModelPermissions', ), 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 1000}WSGI_APPLICATION = 'apps.wsgi.application' # wsgi启动应用配置# 数据库配置,为每个应用单独配置,每个应用可以是不同类型数据库DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), }}
apps/wsgi.py:配置你的项目,让它作为一个WSGI程序来运行。
生成上述文件之后,终端运行:
python manage.py runserver
按提示代开127.0.0.1:8000, 可以看到如下页面,则表示django的应用开发环境准备就绪。
Django的主要目标是使得开发复杂的、数据库驱动的网站变得简单。所以其中一个很重要的功能是对数据库表进行管理,包括表的model定义,视图定义,model操作接口实现等。下面以书籍的管理为基础,在第二部分生成的apps环境的基础上介绍如何使用Django开发自己的应用。
一般来说,一个Django会包含多个应用,为了更好的管理,我们在apps目录下通过创建书籍管理应用bm模块(通过"django-admin startproject bm ."创建会重复生成manage.py文件等文件,需要手动调整,建议手动创建),跟书籍管理的相关py文件均在bm模块中实现。bm模块中一般包含models.py, serializers.py, views.py, url.py, admin.py, 一般还会在bm目录下加一个tests目录,用于接口的单元测试。添加bm的模块之后的目录如下:
apps目录下的db目录是手动创建的,用于存放应用创建的数据库文件。 下面一一介绍bm模块下的各个文件的实现。
3.1 models.py文件介绍
Model.py文件是定义数据表model的文件,需要引用django.db.models,本项目定义了BaseTimeStamp、BaseStatus、ModelFiltered 、Title、Author和Book几个类,其中BaseTimeStamp、BaseStatus分别定义创建时间,更新时间及记录是否可见的基础字段,其他表均会继承这两个类。ModelFiltere类是过滤字段的类,具体使用见该文件。Title、Author和Book这三个类对应我们创建的三个表(类型定义了表字段),下文提到的表的概念,指的就是这个表。models.py内容如下:
from django.db import modelsclass BaseTimeStamp(models.Model): created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: abstract = Trueclass BaseStatus(models.Model): STATUS_ENABLED = 0 STAUS_DISABLED = 1 STATUS_CHOICE = ( (STATUS_ENABLED, 'enabled'), (STAUS_DISABLED, 'disabled') ) status = models.SmallIntegerField(choices=STATUS_CHOICE, default=STATUS_ENABLED) class Meta: abstract = Trueclass ModelFiltered(object): @staticmethod def get_model_field_names(cls, excludes=[], includes=[]): fields = list(map(lambda model_field: model_field.name , cls._meta.fields)) filtered = list(filter(lambda field_name: field_name not in excludes, fields)) filtered.extend(includes) return filteredclass Title(BaseTimeStamp, BaseStatus): name = models.CharField(max_length=128, verbose_name='title') @staticmethod def get_serializer_fields(): return ModelFiltered.get_model_field_names(Title) @ staticmethod def get_admin_display_fields(): return ModelFiltered.get_model_field_names(Title) class Meta: ordering = ('created_at', )class Author(BaseTimeStamp, BaseStatus): passclass Book(BaseTimeStamp, BaseStatus): pass
其中Title和Author类中定义的是django支持的类型,Book类中定义了django支持的类型外,还将Title和Author两个表作为外键引入。BaseStatus的作用是用于用于逻辑删除,BaseTimeStamp的作用是表示创建和更新的时间,两者在多个表中均会用到,所以抽象为通用类。
3.2 serializers.py文件介绍
该文件是对数据表字段进行序列化得文件,一个表对应的序列化类,表的定义在models.py中,servializers.py的内容如下:
from rest_framework import serializersfrom . models import Title, Author, Bookclass TitleSerializer(serializers.ModelSerializer): class Meta: model = Title fields = Title.get_serializer_fields()class AuthorSerializer(serializers.ModelSerializer): class Meta: model = Author fields = Author.get_serialier_fields()class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = Book.get_serialier_fields() def to_representation(self, instance): self.fields['title'] = TitleSerializer(read_only=True) self.fields['author'] = AuthorSerializer(read_only=True) return super(BookSerializer, self).to_representation(instance)
注意,book表的序列化中重写了to_representation方法,主要是因为该表中包含了Title和Author两个外键,改写后读取数据时可以完整的读取外键的各个字段。
tips:本文的例子中,采取外键关联的方式创建表,但是在实际的应用中,处于管理方便和性能考虑,表中不关联外键。
3.3 views.py文件介绍
该文件是表的视图文件,对表进行操作,文件中的每一个类都需要继承rest_framework.generics模块中的父类,这些父类定义了支持的操作,整体包含了get, post, put, patch, delete方法(与http支持的方法相似),不同的支持的方法个数和种类也不一致,具体实现是可根据自身需要选择继承不同的方法。views.py文件的内容如下:
from . models import Title, Author, Book, BaseStatusfrom . serializers import TitleSerializer, AuthorSerializer, BookSerializerfrom rest_framework import genericsfrom django.shortcuts import get_object_or_404from django.db.models import Qclass TitleList(generics.ListAPIView): queryset = Title.objects.all().filter(~Q(status=BaseStatus.STAUS_DISABLED)) serializer_class = TitleSerializerclass TitleUpdate(generics.ListCreateAPIView): queryset = Title.objects.all().filter(~Q(status=BaseStatus.STAUS_DISABLED)) serializer_class = TitleSerializerclass TitleDetail(generics.RetrieveUpdateDestroyAPIView): queryset = Title.objects.all().filter(~Q(status=BaseStatus.STAUS_DISABLED)) serializer_class = TitleSerializer# Author, Book implement ingnored
3.4 urls.py文件介绍
urls.py是定义操作数据表的url,每个url对应views.py中的一个类,表示支持的操作。urls.py的内容如下:
from django.urls import path, re_pathfrom rest_framework.urlpatterns import format_suffix_patternsfrom django.views.decorators.csrf import csrf_exemptfrom . import viewsurlpatterns = [ path('titles/', views.TitleList.as_view()), path('title/', views.TitleUpdate.as_view()), path('title/', views.TitleDetail.as_view()), path('authors/', views.AuthorList.as_view()), path('author/', views.AuthorUpdate.as_view()), path('author/', views.AuthorDetail.as_view()), path('books/', views.BookList.as_view()), path('book/', views.BookUpdate.as_view()), path('book/', views.BookDetail.as_view()), path('book/by_press/', views.BookByPress.as_view()),]
3.5 admin.py文件介绍
Django自带一个管理数据库的web服务,所以需要将我们需要管理的表添加到admin.py中,这样就可以通过Django自带的web服务对表进行操作了。Admin.py的内容如下:
from django.contrib import adminfrom . models import Title, Author, Book@admin.register(Title)class TitleAdmin(admin.ModelAdmin): list_display = Title.get_admin_display_fields()@admin.register(Book)class BookAdmin(admin.ModelAdmin): list_display = [*Book.get_admin_display_fields(), 'get_title', 'get_author'] def get_title(self, obj): return obj.title.name if obj.title is not None else '' get_title.admin_order_field = 'title' get_title.short_description = 'title' def get_author(self, obj): return obj.author.name if obj.author is not None else '' get_author.admin_order_field = 'author' get_author.short_description = 'author'# author implement ignored
需要注意的是BookAdmin类里边包含了外键的操作,其方法与不包含外键的操作不一样。
4应用配置开发完bm应用之后,需要将bm应用添加到django中,应用的添加在apps下的settings.py中,该文件是通过django-admin生成Django项目是生成的,添加bm服务,需要修改内容如下:添加INSTALLED_APPS,在原来的基础上添加一些其他的应用,如下图:
添加REST_FRAMEWORK的基本组件,支持权限的控制和全局数据库查询分页配置,如下:
数据库配置,可以配置不同的数据库,Django支持常见的mysql,posgres等数据库,可根据需要配置,本文实验使用sqlite3数据库。
配置一个默认数据库,用于存储Django自身相关的数据(后续会介绍包含的数据)。
在bm模块中实现了urls.py,还需要将其添加到apps/urls.py中,才可以正常访问到,代码如下:
from django.contrib import adminfrom django.urls import path, include, re_pathfrom rest_framework import routersfrom rest_framework_swagger.views import get_swagger_viewschema_view = get_swagger_view(title='api list')router = routers.DefaultRouter()urlpatterns = [ re_path(r'^', include(router.urls)), path('admin/', admin.site.urls), path('schema/', schema_view), # 添加schema模式 re_path(r'^bm/', include('apps.bm.urls')), # 添加bm/urls.py的路径。]
5服务启动和测试
配置好开发的bm应用之后,在启动Django服务之前还需要创建bm数据库表、超级用户等信息,然后才能进行测试。依次执行以下命令创建数据库表:
python manage.py makemigrations bm # 在bm模块下生成migrations文件夹,包含0001_initial.py文件
python manage.py migrate bm # 将0001_initial.py的变更更新到数据库中。
python manage.py test # 执行单元测试,单元测试是保证实现的接口没有问题一个很重要的手段,有单元测试,很多的bug都可以在单元测试阶段发现
python manage.py createsuperuser # 输入交互命令并按提示输入用户名,邮箱和密码
python manage.py runserver # 启动Django服务
启动成功后,可以看到如下信息:
打开http://127.0.0.1:8000/admin/ 并输入刚才创建的用户名和密码,可以看到创建的bm数据表。
这是Django的后台服务,看到的表的字段等信息在admin.py中定义(不一定更跟真实的数据表字段一致),这里可以手动对表进行crud操作。数据库“AUTHENTICATION AND AUTHORIZATION”和“AUTH TOKEN”的功能会在后续文章中介绍。
Django还提供了schema模式(通过api对数据库进行操作),地址为:http://127.0.0.1:8000/schema/

6
总结本文从最基础的起点介绍Django的使用,先简要介绍了Django在web框架中的地位,然后介绍了Django的应用开发环境准备,接着介绍了添加书籍管理应用的开发和配置,最后介绍了书籍管理应用的部署和启动。
在后续的文章中,会更深入的剖析Django的内部实现原理,比如migrate的原理(ORM机制),权限控制机制等等。