Django是一套完整的MVC开发架构,虽然在微服务盛行的今时今日再谈MVC有些老土,不过对于python这种解决小项目的开发语言来说,MVC仍然是最优的选择。
严格来说,Django是MTC,因为其表现层用的是模板(Template)
Django的目录结构
manage.py:Django的命令行工具,可以让我们通过命令形式与Django进行交互。
templates:前台模板文件存放的目录,该目录有时也会放在项目mysite目录的里面,是在settings.py中配置的。
urls.py:路由信息,配置了url地址与代码的映射关系,像Java中的Struts的配置,小型项目一般一个路由配置文件就够了,大型的项目会配置多级路由。
wsgi.py: WSGI 兼容的Web 服务器的入口,以便运行你的项目
这里着重要了解下settings.py中的一些配置:
ROOT_URLCONF = 'mysite.urls'
对应路由信息第一级的入口,对于路由多级及详细配置,下面会解释
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'mysite/templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
这个是配置模板信息的,特别需要注意DIRS这个配置,代表着模板存放的位置,所以前面提到过templates目录的位置是可以自己按照习惯自定义的,当然必须要与这个配置匹配。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '',
'NAME': 'mysite_dev',
'USER': '',
'PASSWORD': '',
}
}
持久层数据库的配置信息,用于数据库连接
STATICFILES_DIRS = (
os.path.join(BASE_DIR, '/mysite/static'),
)
STATIC_URL = '/static/'
Js、css、图片等静态文件配置,dirs配置的是静态文件存放的位置,url配置的是请求静态文件的url前缀
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
中间件的配置,相当于java的spring中的AOP,前置加强、后置加强、循环加强、异常加强等。
INSTALLED_APPS = [
'mysite.apps.job',
'mysite.apps.product',
'mysite.apps.plan',
]
一组业务的MVC在Django中被称为一个app,INSTALLED_APPS配置的就是装在了哪些app,一个app的目录结构如下:
apps.py:代码很简单,为了完成app的声明:
from django.apps import AppConfig
class TemplateConfig(AppConfig):
name = 'cloudm.apps.plan'
models.py是持久层ormapping的代码,后面会详细介绍
urls.py是路由的详细配置信息,后面会详细介绍
view.py是属于buusiness层的代码,接收页面的request,处理业务逻辑,调用持久层入库操作结果,返回response给到前台,这个后面也会详细介绍。
路由控制URL:
urls.py是整个Django项目的筋络,也是每个app的门户。前面settings中已经介绍了DITS里配置的是路由的总入口,以2层路由为例,看下路由的配置信息。
第一层:urlpatterns = [
url(r'^$', views.index),
url(r'^job/', include("mysite.apps.job.urls")),
url(r'^product/', include("mysite.apps.product.urls")),
url(r'^template/', include("mysite.apps.template.urls")),
url(r'^plan/', include("mysite.apps.plan.urls")),
]
很好理解,根据第一层url的不同引入后续的urls
第二层,以plan为例:
urlpatterns = [
url(r'^$', views.index, name='plan-views-index'),
url(r'^name/?$', views.create, name='plan-views-name'),
url(r'^add_plan/?$', views.add_plan, name='plan-views-add'),
url(r'^add_component/?$', views.add_component, name='plan-views-add-component'),
url(r'^edit_component/(?P<plan_id>\d+)/?$', views.edit_component, name='plan-views-edit-component'),
url(r'^edit/(?P<id>\d+)/?$', views.edit, name='plan-views-edit'),
url(r'^detail/(?P<plan_id>\d+)/?$', views.detail, name='plan-views-detail'),
url(r'^update_comp/?$', views.update_component, name='plan-views-update-component'),
url(r'^delete_comp/?$', views.delete_component, name='plan-views-delete-component'),
]
每条配置有3部分,左边部分是url的内容,中间部分对应业务逻辑层views.py中的具体函数,右边部分是在该地址在Django项目中的唯一标识,内部可以直接请求这个标识而不是url发起业务请求。
Model层
django中遵循 CodeFrist 的原则,代码既数据,可以通过python manage.py migrate将改动更新到数据库。对于Java开发者理解的ORMapping来说,先建表,然后基于表写模型代码和ORMapping的配置文件。而对于Python开发者来说,模型代码就是表结构本身,写代码的过程是直接建表的过程,而不是映射的过程。
看下plan的models.pyfrom django.db import models
class Plan(models.Model):
id = models.BigAutoField(primary_key=True)
detail = models.TextField(blank=True, null=True)
create_time = models.DateTimeField(auto_now_add=True)
update_time = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10, blank=True, null=True)
name = models.CharField(max_length=40, blank=True, null=True)
class Meta:
managed = True
db_table = 'plan'
效果图:
models定义了很多种属性,涵盖了关系型数据库中的所有类型。
看下几种常用的属性:
models.BigAutoField:自增长列,一般用于主键
models.CharField:最常用的,需要定义长度;
models.BooleanField:布尔类型
models.DateField:日期类型,auto_now代表每次更新是否设置为当前时间,auto_now_add代表只有第一次创建时会设置为当前时间。这两个入参很明显一个用在createDate场景,一个用在updateDate场景。
models.Decimal:必须设置精度
models.IntegerField:整型
models.TextField:大文本类型
models.BinaryField:大二进制类型
每个model还定义了一个元数据信息:
db_table:对应在数据库中的表名
managed:是否被python manage.py来管理
index_together:联合索引
unique_together:联合唯一约束
ORMpping中最难掌握的也是唯一的难点,就是Relationship,这里只介绍常用的多对一和多对多。Django中处理多对一的关键字是ForeignKey,同理多对多也是通过桥表来转化成2个多对一。
假设我的任务表叫job,代表每个需要执行的任务。任务不见得每次都能执行成功而且可以重复执行,所以给执行结果保存在job_history中,这样1个job就对应多个job_history,每个job_history通过foreignkey与job关联。
Job_History的核心代码如下:
class JobHistory(models.Model):
job = models.ForeignKey('Job', models.DO_NOTHING)
其中foreignkey配置的是model的名字,但是在数据库层对应的是model的id。第二个参数代表job删除时关系如何维护,可选项有:
- models.CASCADE,删除关联数据,与之关联也删除
- models.DO_NOTHING,删除关联数据,引发错误IntegrityError
- models.PROTECT,删除关联数据,引发错误ProtectedError
- models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
- models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值) - models.SET,删除关联数据,
多对多可以拆解成2个多对一,假设操作人user和job是多对多的关系,一个job可以被多人经手操作,同理一个人可能参与多个job,我们可以创建一个user2job的model:
class User2Job(models.Model):
job = models.ForeignKey('Job', models.DO_NOTHING)
user= models.ForeignKey('User', models.DO_NOTHING)
class Meta:
unique_together = ("job","user")
Django对多对多还提供了ManyToManyField这种方式,我自己倾向于拆解。
增删改查:
Object.save()其实是saveOrUpdate(),object.delete()是删除,所以模型的增删改查就剩下查询比较复杂了。
常用的查询方式有:
Get:直接通过条件获取确定的model对象,例如:
resource = Resource.objects.get(id=resource_id)
Filter:相当于where条件过滤
resource = Resource.objects.filter(job_id=job_id,type_id=1).first()
查询后跟.count()是取总数,不带任何条件直接.all()是取全部,.order_by是按属性排序
批量删除:
Application.objects.filter(id=data['app_id']).delete()
范围查询:
models.Tb1.objects.filter(id__lt=10,id__gt=1)
id小于1切大于10
models.Tb1.objects.exclude(id__in=[11, 22,33])
id not in [11,22,33]
关于Django的模型先介绍到这里,注意:每个app的模型定义的python文件名是models而不是model,也就是说并不是每张表结构创建一个app,我们要把多个相关的模型定义在一个模型文件中,views.py、urls.py同理,那么问题来了,哪些表属于同一个app?这就涉及到软件开发设计领域的另一个课题DDD(领域驱动设计),建议大家学习掌握。
View层:
View要做的事情主要有2部分,第一、处理页面的request并response,第二、组织业务逻辑并调用持久层(models)。对持久层的操作就是增删改查,对于业务逻辑的编程那就是跟自己业务相关的了,没什么好介绍的,那么View层唯一需要掌握的就剩下Request和Response了。
View层函数入参是request,代表客户端传来的请求,我们需要根据http的具体请求方法(get、post、put等)来选择如何获取request中的内容。
Response一般分直接返回Json和返回页面2种。
返回Json:return JsonResponse(ret)
返回页面:
return render(request, "job/index.html", {'jobs': jobs})
obs是”job/index.html”这个前台页面需要加载的变量内容。
Template层:
这一层是概念理解上最简单,但是后期工作量最大的一层。核心思想就是block,利用模板的继承,前面flask有类似的使用,这里也不再详细描述了。
最后看下Django的常用命令:
python manage.py migrate
前面已经介绍过了,是models与数据库的同步命令。
python manage.py runserver ip:port
是项目的启动命令,ip:port是接收服务的地址,一般配置为0:8000
python manage.py createsuperuser
创建超级管理员