Django是如今世界上python语言应用最普遍、发展最成熟的web框架。它足够完整 ,不须要依赖其余就能够开发出 很是完整的web应用。Django的主要内容以下:html
Django于2003年诞生于美国的堪萨斯州,最初是用来制做在线新闻web网站,于2005年加入了BSD许可证家族,成为开源网络框架。Django根据比利时的爵士音乐家Django Reinhardt命名。前端
相对于python的其它web框架,Django的功能是最完整的,Django定义了服务发布,路由映射,模板编程,数据处理的一整套功能。这也意味着Django模块之间紧密耦合,开发者须要学习Django本身定义的一整套技术。它的主要特色以下:java
Django是遵循MVC架构的web开发框架,主要又如下几个部分组成。python
在安装pip工具的python环境中能够直接使用pip install django命令进行安装。或者下载Django的离线包,使用python setup.py install命令进行安装。mysql
安装完成后,进入python,经过以下命令测试是否安装成功。git
import djangoweb
print(django.version)正则表达式
在进行项目开发的第一步就是要创建Django项目,创建的语法以下:sql
django-admin startproject djangotest。数据库
上述代码中的django-admin是安装好Django组件后在python目录中生成的Django项目管理工具。该命令在当前的目录下建立了项目工程文件,工程文件中的目录结构以下:
上图就是成功生成的项目文件,默认生成的几个文件很是重要,在从此的开发或者维护中要一直使用它们。各个文件简单的解释以下:
为了在项目中开发符合MVC架构的实际应用程序,咱们须要在项目中创建Django应用。每个django项目能够包含多个django应用。应用的创建语法以下。
python manage.py startapp app。
其中的manage.py是创建项目是用到的命令行工具,startapp是命令行关键字,app是创建的应用名称。命令完成后会在项目的目录下创建以下图所示的文件结构。
其中各个文件功能的说明以下:
在完成django项目和应用的创建后,就能够开始编写网站的代码了,下面简单演示一下django的路由映射功能。
(1)在app/views.py中建立一个路由响应函数,代码以下
from django.http import HttpResponse def welcome(request): return HttpResponse('<h1>你好,django</h1>')
(2)接下来,要经过URL映射将用户的HTTP访问和该函数绑定起来,在app/目录下建立一个urls.py文件,其文件的内容以下:
from django.contrib import adminfrom django.conf.urls import url from .apps import views urlpatterns = [ url(r'',views.welcome), #url(r'',views.welcome), ]
(3)在项目djangotest/urls.py文件中的urlpatterns中新增长一项,声明对应用app中的urls.py文件的引用,具体代码以下
from django.contrib import admin from django.urls import url from django.conf.urls import include urlpatterns = [ url('admin/', admin.site.urls),
url(r'app/', include('app.urls')),
]
首先导入django.conf.urls.include()函数,以后再urlpatterns列表中增长一个路径app/,将其转接到app.urls包,这样经过include()函数就能够将2个urlpatterns链接起来。
(4)上述代码书写完成后,输入python manage.py runserver 127.0.0.0:8888。命令开启web服务,在浏览其中输入网址http://127.0.0.0:8888/app,结果以下图所示。
这一节介绍的是Model层的处理,设计和开发信息发布的数据访问层。
要在django项目的setting.py文件中告诉django须要安装应用app中的模型,方法是在setting.py文件中的INSTALLED_APPS数据结构中,在其中添加应用app的 config类,代码以下:
INSTALLED_APPS = [ 'app', # 新增 ]
打开app/models.py文件,在其中新建一个模型类Mount,用来定义信息发布表,代码以下:
from django.db import models class Mount(models.Model): content = models.CharField(max_length=200) username = models.CharField(max_length=20) kind = models.CharField(max_length=20)
首先引入modoels类,全部的django模型类都是继承于它。类Mount继承了models类,在其中定义了3个字段content:消息的内容、username:发布人名称、kind:消息的类型。
django的术语“生成数据移植文件”是指将models.py中定义的数据表转换成数据库生成脚本的过程。该过程经过命令行工具manage.py完成,具体的命令输出以下:
经过输出咱们能够看到完成了模型Mount的创建。输出中的0001_initial.py是数据库生成的中间文件,经过它能够知道当前数据库的版本;该文件以及之后全部的migration文件都存储于目录migrations/中。
同时在makemigrations的过程当中,django会对比models.py中模型和已有数据库之间的差别,没有差别则不作操做,如再次执行makemigrations操做时将产生以下输出:
可是若是对models.py文件做出修改时,则在下一次makemigrations的时候会将修改的内容同步到数据库中。例如将kind字段修改成长度30后,执行操做,结果以下:
在该过程当中产生了新的中间文件0002_auto_20190526_1431.py。须要注意的是djangotest\app\migrations目录中的文件都有manage.py本身维护,开发者不宜修改其中的内容。
在模型的修改过程当中能够随时调用makemigrations生成的中间移植文件。当须要真正的修改数据库的时候,须要经过manage.py的migrate命令让修改同步到数据库。例如:
创建表单类文件djangotest/app/forms.py,在其中定义表单类MountForm,代码以下:
from django.forms import ModelForm from models import Mount class MountForm(ModelForm): class Meta: model = Mount fields = '__all__'
为了使用户可以以单选的方式设置消息类型,则须要在models.py文件中定义单选的枚举类型,而且与模型类Mount进行关联。代码以下:
from django.db import models # Create your models here. class Mount(models.Model): content = models.CharField(max_length=200) username = models.CharField(max_length=20,default='张晓琳') # 新增元祖用于设置消息枚举类型 KIND_CHOICES = (('python','python'),('java','java'),('C语言','C语言'), ('C++', 'C++'), ('mysql', 'mysql'),) kind = models.CharField(max_length=30,choices=KIND_CHOICES,default=KIND_CHOICES[0])
模板文件是python web框架中用于产生HTML、XML等文本格式文档的术语。模板文件自己也是一种文本文件,开发者须要手工进行编辑。创建目录djangotest/app/templates,在其中新建模板文件moments_input.html,文件内容以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>消息录入页面</title> </head> <body> <form action="?" method="post"> <fieldset> <legend>请输入并提交</legend> {{ form.as_p }} <input type="submit" value="提交" /> </fieldset> </form> </body> </html>
模板文件是html文件,其中的模板内容使用大括号进行标识。这里使用{{ form.as_p }}定义表单类的输入字段。
接下来开发的是视图文件,使得表单类和页面模板可以衔接起来。打开djangotest/app/views.py文件,在其中加入以下函数:
import os
from app.form import MountForm
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def moments_input(request):
if request.method == 'POST':
form = MountForm(request.POST)
if form.is_valid():
moment = form.save()
moment.save()
# return HttpResponseRedirect("app.views.welcome")
else:
form = MountForm()
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
return render(request,os.path.join(project_root,'app/templates'),'moments_input.html',{'form':form})
在urls.py文件中增长视图函数的路由映射。
urlpatterns = [
url('admin/', admin.site.urls),
url(r'^app/', include('app.urls')),
]
访问地址为http://127.0.0.1:9999/app/moments_input。
站点分为“内容发布”和“公共访问”两部分,“内容发布”的部分负责添加、修改、删除内容,开发这些重复的功能是一件单调乏味、缺少创造力的工做。为此,Django会根据定义的模型类彻底自动地生成管理模块
python manage.py createsuperuser
,按提示输入用户名、邮箱、密码
编辑settings.py文件,设置编码、时区
LANGUAGE_CODE = 'zh-Hans' TIME_ZONE = 'Asia/Shanghai'
打开booktest/admin.py文件,注册模型
from django.contrib import admin from models import BookInfo admin.site.register(BookInfo)
刷新管理页面,能够对BookInfo的数据进行增删改查操做
问题:若是在str方法中返回中文,在修改和添加时会报ascii的错误
解决:在str()方法中,将字符串末尾添加“.encode('utf-8')”
Django提供了admin.ModelAdmin类
经过定义ModelAdmin的子类,来定义模型在Admin界面的显示方式
class QuestionAdmin(admin.ModelAdmin): ... admin.site.register(Question, QuestionAdmin)
list_display = ['pk', 'btitle', 'bpub_date']
list_filter = ['btitle']
search_fields = ['btitle']
list_per_page = 10
fields = ['bpub_date', 'btitle']
fieldsets = [ ('basic',{'fields': ['btitle']}), ('more', {'fields': ['bpub_date']}), ]
对于HeroInfo模型类,有两种注册方式
按照BookInfor的注册方式完成HeroInfo的注册
接下来实现关联注册
from django.contrib import admin from models import BookInfo,HeroInfo class HeroInfoInline(admin.StackedInline): model = HeroInfo extra = 2 class BookInfoAdmin(admin.ModelAdmin): inlines = [HeroInfoInline] admin.site.register(BookInfo, BookInfoAdmin) 能够将内嵌的方式改成表格 class HeroInfoInline(admin.TabularInline)
发布性别的显示不是一个直观的结果,可使用方法进行封装
def gender(self): if self.hgender: return '男' else: return '女' gender.short_description = '性别' 在admin注册中使用gender代替hgender class HeroInfoAdmin(admin.ModelAdmin): list_display = ['id', 'hname', 'gender', 'hcontent']
Django模型层是Django框架自定义的一套独特的ORM技术,经过上几章节的总结学习,咱们已经大概了解了Django模型层的基本概念和开发流程。如今来学习模型层的技术细节和高级话题。
使用Django模型开发的首要任务就是定义模型类和类的属性。每一个模型类均可以被映射为数据库中的一个表,类属性被映射成为数据字段,除此以外,数据库中的主键、外键、约束等也能够经过类属性完成定义。
模型定义的的基本结构以下所示:
from django.db import models class ModelsName(models.Model): field1 = models.XXfield(...) field2 = models.XXfield(...) ... class Meta: db_table = ... other_metas = ...
属性 |
属性值 |
说明 |
abstract |
True or False |
标识本类是否为抽象的基类 |
app_lable |
app_lable = “myapp” |
定义本类所属的应用 |
db_table |
db_table=“mytable” |
映射的数据库表名称 说明:若是Meta中不提供db_table字段,则django会为模型自动生成数据库表名,格式为“应用名_模型名”。 |
db_tablespace |
无 |
映射的表空间名称。表空间的概念只在某些数据库中如oracle中存在,不存在表空间概念的数据库将会忽略本字段。 |
Default_related_name |
无 |
定义本模型的反向关系引用名称,默认和模型名一致。 |
get_latest_by |
无 |
定义按那个字段值排列得到模型的开始或者结束记录,本属性值一般指向一个日期或者整形的模型字段。 |
managed |
True or False |
定义django的manage.py命令行工具是否管理本模型。属性默认设置为TRUE。设置为false时,须要手动维护数据库表。 |
order_with_respect_to |
无 |
定义本模型能够按照某种外键引用的关系排序。 |
ordering |
Ordering = [“username”“-pub_data”] |
本模型记录的默认排序字段,能够设置多个字段,默认为升序排列。降序排列的话在字典前加上- |
default_permissions |
Add,change,delete |
模型的操做权限,默认如值所示。 |
proxy |
True or False |
本模型及全部继承自本模型的子类是否为代理模式。 |
required_db_features |
fequired_db_features =[“gis_enabled”] |
定义底层数据库所必须具有的特性,如值所示只将本数据模型生成在知足gis_enabled特性的数据库中 |
required_db_vendor |
SQLite、PostgreSQL、MySQL、Oracle |
定义底层数据库的类型,若是定义了本属性,则模型只能在其声明的数据库中维护。 |
unique_together |
unique_together = ((“user”,“pwd”)) |
用来设置不重复的的字段组合,必须惟一(能够将多个字段作联合惟一)。 |
index_together |
index_together=[ [“pun_data”,“deadline”]] |
定义联合索引的字段,能够定义多个。 |
verbose_name |
verbose_name = ‘资产管理’ |
定义一个易于理解和表述的单数形式的对象名称。若是不设置该值,则Django将会使用该models的类名做为它的对象表述名。 |
verbose_name_plural |
|
定义一个易于理解和表述的复数形式的对象名称。 |
Django的普通字段是指模型类中除了外键之外的数据字段属性。它为Django使用模型的时候提供以下信息:
全部的数据字段的属性必须继承自抽象类django.db.models.Field,咱们能够本身定义继承自该类的数据字段,也可使用Django预约义的一系列数据字段,常见的Django预约义字段类型描述以下表所示。
字段 |
字段说明 |
AutoField |
一个自动递增的整形字段,添加记录时它会自动增加。AutoField字段一般充当数据表的主键;若是没有添加,django会自动添加一个该字段。 |
BigIntegerField |
64位的整型字段 |
BinaryField |
二进制数据字段,经过bytes进行赋值 |
BooleanField |
布尔字段,对应<input type=“CheckBox”> |
CharField |
字符串字段,对应<input type=“text”> |
TextField |
大容量文本字段,对应<textarea> |
CommaSeparatedIntegerField |
存放逗号分隔的整数值,有特殊的表单验证要求 |
DateField |
日期字段,相对应的HTML标签是<input type=“text”>、JavaScript日历和一个today快捷按键。可选参数:auto_now:保存时,设置为当前时间;auto_now_add:首次建立时,保存为当前时间。 |
DateTimeField |
相似于DateField,可是它却支持时间的输入。 |
DurationField |
存储时间周期,用python的timedelta类型构建。 |
EmailField |
检查Email合法性的CharField。 |
FileField |
文件上传字段。在定义本字段是必须传入参数upload_to,用于保存上传下载文件的服务器文件系统的路径。这个路径必须包含strftime formatting,该格式将被上载文件的date/time替换 |
FilePathField |
按照目录的规则限制选择文件,定义本字段是必须传入参数path,用以限定目录。 |
FloatField |
浮点型字段。定义本字段时必须传入参数max_digits和decimal_places,用于定义总位数和小数位数。 |
ImageField |
相似于 FileField,同时验证上传的对象是不是一个合法图片,可选参数有2个:height_field和width_field,有这两个参数,图片按照规定的长和高进行存储。 |
IntegerField |
保存一个整数 |
IPAddressField |
一个字符串形式的IP地址 |
NullBooleanField |
相似于BooleanField,可是多出了一个None选项 |
PhoneNumberField |
带有美国风格的电话号码校验的CharField(格式为XXX-XXX-XXXX) |
PositiveIntegerField |
只能输入非负数的IntegerField |
SlugField |
只包含字母,数字,下划线和连字符的输入,一般同于URL |
SmallIntegerField |
相似于IntegerField,可是只有较小的输入范围,依赖所使用的数据库。 |
TimeField |
时间字段,相似于DateTimeField,但只能表达和输入时间。 |
URLField |
用于保存URL |
USStateField |
美国州名的缩写字段 |
XMLField |
XML字符字段,是具备XML合法性验证的TextField |
|
|
每一个字段类型都有一些特定的HTML标签和表单验证参数,好比heigth_field,path等,但同时每一个字段都有能够设置的公告方法,好比primary_key参数设置的主键字段。
from django.db import models class Comment(models.Model): # 设置主键id id = models.AutoField(primary_key=True)
from django.db import models class Comment(models.Model): # 设置主键id id = models.AutoField(primary_key=True) # 定义选择元祖 levels = (('1','Very Good'),('2','Good'),('3','Normal'),('4','Bad')) level = models.CharField(max_length=10,choices=levels)
上述代码中定义了level字段用于让用户选择满意度,其中的1,2,3,4是在数据库中实际存储的数据,而very good、Good、Normal、Bad等是在HTML页面中供选择的选项。
除了这些名称的字段外,Django中的全部字段还有一个无名参数,能够设置该字段在HTML页面的显示名称,好比:
level = models.CharField('客户满意度选择',max_length=10,choices=levels)
定义以下的Django models,用于演示Django的模型基本查询技术。
from django.db import models class Comment(models.Model): # 设置主键id id = models.AutoField(primary_key=True) # 定义选择元祖 levels = (('1','Very Good'),('2','Good'),('3','Normal'),('4','Bad')) level = models.CharField('客户满意度选择',max_length=10,choices=levels) headline = models.CharField(max_length=255) body_text = models.TextField() pub_date = models.DateTimeField() n_visits = models.IntegerField() def __str__(self): return self.headline
(1) Django有2中过滤器用于对记录进行刷选,以下:Django经过模型的objects对象查询模型的数据,例以下面的语句查询Comment模型的全部数据:Comment.objects.all()
(2)链接查询
多个filter和exclude能够连在一块儿进行查询,好比查询全部2015年非1月的n_visits不为0的记录:Comment.objects.filter(pub_date_year == 2015).exclude(pub_date_month=1).exclude(n_visits_exact=0)。
咱们能够看到代码中的pub_date_year,它并非模型中定义的一个字段,而是Django定义的一种独特的字段查询方式,本例中该查询的含义是“pub_date字段的year属性为2015”。基本的表现形式为 字段名称_谓词,既由“双下划线链接的字段名称和谓词”来表达查询条件。相似的还有不少其余的谓词查询方式,完整的Django谓词列表以下标所示。
谓词 |
含义 |
示例 |
等价的sql语句 |
exact |
精确等于 |
Com.objects.filter(id_exact=14) |
Select * from Com where id = 14; |
iexact |
大小写不敏感的等于 |
Com.objects.filter(headline_iexact=”I am ok”) |
Select * from Com where upper(headline)=” I am ok” |
contains |
模糊匹配 |
Com.objects.filter(headline_ contains =”good”) |
Select * from Com where headline like ”%good%”; |
in |
包含 |
Com.objects.filter(id_ in =[1,5,9]) |
Select * from Com where id in [1,5,9]; |
gt |
大于 |
Com.objects.filter(id_ gt=30) |
Select * from Com where id > 30; |
gte |
大于等于 |
||
lt |
小于 |
||
lte |
小于等于 |
||
startwith |
以..开头 |
Com.objects.filter(body_text_ startwith=”wl”) text_ endwith=”wl” |
Select * from Com where body_text like ”good%” ”%good”; |
endwith |
以..结尾 |
||
range |
在..范围内 |
Com.objects.filter(pub_date_range=(starttime,endtime)) |
Select * from Com where pub_date between starttime and endtime; |
year |
年 |
Com.objects.filter(pub_date_year == 2015) |
Select * from Com where pub_date between “2015-1-1 00:00:00” and “2015-12-31 23:59:59”; |
month |
月 |
||
day |
日 |
||
Week_day |
星期几 |
||
isnull |
是否为空 |
Com.objects.filter(pub_date_isnull = True) |
Select * from Com where pub_date is Null; |
(3)除了all()、filter()、exclude()等返回数据集的函数,Django还提供了get()函数用于查询单挑记录,好比查询id为3的记录:
Com.objects.get(id_exact = 1)
(4)Django还提供了用于查询指定条数的小标操做,该特性使得Django模型可以支持SQL中的limit和offset。
(5)Django还提供了order_by操做,示例以下:
Com.objects.order_by(“headline”):返回数据集,按照headline字段排序。
和传统的sql相比,Django的一个较大的优点是定义了一个统一的方法save(),用于完成模型的insert和update操做。在执行模型的save()函数时,Django会根据模型的主键,判断记录是否存在,若是存在执行update操做,不存在执行insert操做。
# 新增记录 obj = Comment(headline='i am ok',body_text='...sdjk', pub_date = datetime.datetime().now(),n_visits=0) obj.save() print(obj.id) # 打印主键id22 # 修改记录数据 obj.body_text = "this is my world, I am god!!" obj.save() print(obj.id) # 打印主键id=22,和新增后的id相同。
4.2.3 数据删除
Django模型提供了delete()方法用于删除记录,该方法能够进行单条和批量删除。示例代码以下:
# 删除id为3的记录 Comment.objects.get(id=3).delete() # 删除2015年全部的记录 Comment.objects.filter(pub_date_year = 2015).delete()
利用数据表之间的关系进行数据建模和业务开发是关系型数据库最主要的功能。Django的模型层对这三种关系模型(1:1,1:N;M:N)都有强大的支持。
在SQL语言中,一对一的关系经过在两个表之间定义相同的主键来完成。在Django的模型层,能够在任意一个模型中定义OneToOneField字段,而且定义相互之间的一对一关系。以下的代码在模型Account和Contact之间定义了一对一的关系。
class Account(models.Model): user_name = models.CharField(max_length=80) password = models.CharField(max_length=255) reg_date = models.DateTimeField() def __str__(self): return "Account:%s" % self.user_name class Contact(models.Model): account = models.OneToOneField(Account,on_delete=models.CASCADE,primary_key=True) zip_code = models.CharField(max_length=10) address = models.CharField(max_length=80) mobile = models.CharField(max_length=20) def __str__(self): return "%s,%s" % (self.account.user_name,self.mobile)
在上述一对一的关系模型中的开发代码以下所示。
a1 = Account(user_name='wltest') a1.save() # 保存一个Account记录 print(a1) # 打印a1:<Account:wltest> a2 = Account(user_name='zxlText') a2.save() # 保存一个Account记录 # 利用a1初始化Contact的account字段,并保存 a3 = Contact(account=a1,mobile='1223123123') a3.save() print(a3) # <Contact:wltest,1223123123> print(a1.contact) # <Contact:wltest,1223123123>,经过关系打印,于打印a3的结果相同 print(a3.account) # <account:wltest>,经过关系打印,于打印a1的结果相同 # a2没有和Contact创建过关系,因此没有contact字段。 a1.delete() # on_delete = models.CASCADE,因此删除a1时也删除了a3
在SQL语言中,1:N关系经过在“附表”中设置“主表”的外键引用来完成。在Django模型层,可使用models.ForeignKey()来定义外键,代码以下:
from django.db import models class Account(models.Model): user_name = models.CharField(max_length=80) password = models.CharField(max_length=255) reg_date = models.DateTimeField() def __str__(self): return "Account:%s" % self.user_name class Contact(models.Model): # account = models.OneToOneField(Account,on_delete=models.CASCADE,primary_key=True) account = models.ForeignKey(Account, on_delete=models.CASCADE) zip_code = models.CharField(max_length=10) address = models.CharField(max_length=80) mobile = models.CharField(max_length=20) def __str__(self): return "%s,%s" % (self.account.user_name,self.mobile)
上述代码于一对一关系惟一不一样的地方在于models.ForeignKey定义了Contact模型中的account字段。这样一来,每一个Account对象就能够与多个Contact对象关联了。模型的使用代码以下:
def welcome(request): a1 = Account(user_name='wl2',password='12343') a1.save() # 保存一条Account记录 # 为a1创建两个Contact关联的对象 c1 = Contact(account=a1,address='c1',mobile='12312321412') c1.save() # 保存C1记录 c2 = Contact(account=a1, address='c2', mobile='12312321412') c2.save() # 保存C2记录 data = {c1.address:str(c1.account), c2.address:str(c2.account),'a1':str([a1.contact_set,a1.contact_set.count()])} a1.delete() return JsonResponse({'status':200,'data':data})
在一对多关系中,每一个主模型对象能够关联多个子对象,因此本例中从主模型Account对象寻找附属模型Contact的属性时contact_set,经过一个集合返回关联结果。
说明:XXX_set是Django设定的经过主模型对象访问附属模型的对象集合的属性名。
在SQL语言中,M:N关系经过创建一个中间关系表来实现,该中间表中定义了到2个主表的外键。因此在Django模型层中,开发者也能够选择用这两个1:N关系来定义M:N的关系。这种方式是经过models.ForeignKey来实现。
另一种方式是在django的模型层中定义一个models.ManyToManyField字段来实现的,多对多关系的模型定义代码以下:
from django.db import models class Account(models.Model): user_name = models.CharField(max_length=80) password = models.CharField(max_length=255) # reg_date = models.DateTimeField() def __str__(self): return "Account:%s" % self.user_name class Contact(models.Model): account = models.ManyToManyField(Account) zip_code = models.CharField(max_length=10) address = models.CharField(max_length=80) mobile = models.CharField(max_length=20) def __str__(self): return "%s,%s" % (self.account.user_name,self.mobile)
上述代码经过在Contact中定义引用Account的ManyToManyField,实现了2个模型的多对多关联,对此模型的定义操做演示以下:
# 分别创建并保存Account和Contact的对象 a1 = Account(user_name='ww') a1.save() c1 = Contact(mobile='weeee3') c1.save() # t经过Contact对象创建关系 c1.account.add(a1) a2 = Account(user_name='jjj') a2.save() a2.contact_set.add(c1) # 经过Account对象创建关系 a3 = Account(user_name='jjj') # 对象未保存出错 a3.contact_set.add(c1) # 经过Account对象创建关系 a1.contact_set.remove() # 取消单个对象的关联 a1.contact_set.clear() # 取消全部对象的关联
Django模型层ORM的一个强大之处是对模型继承的支持,该技术将python面向对象的编程方法与数据库面向关系表的数据有机的结合。支持三种风格的模型集成。相面来介绍这三种继承方法。
抽象类继承是指父类继承models.Model,但不会在底层的数据库中生成相应的数据表,父类的相关属性字段存储在子类的数据表中。
它的做用是在多个表有想干的字段时,可使得开发者将这些字段统必定义在抽象基类中,免于重复定义这些字段。抽象基类的定义经过在模型的Meta中定义属性abstract=True来实现,示例代码以下:
class MessageBase(models.Model): id = models.AutoField() content = models.CharField(max_length=100) user = models.CharField(max_length=20) pub_date = models.DateTimeField() class Meta: # 定义本类为抽象基类 abstract = True class Mon(MessageBase): headline = models.CharField(max_length=50) class Com(MessageBase): life = models.CharField(max_length=30,default='wl',choices=(('1','2'),('sjdk','idi')))
在子类模型的编程中,能够直接使用父类定义的字段,例如:上述代码中定义了一个抽象基类MessageBase,用于保存消息的4个字段。子类Mom和Com继承自MessageBase,并分别定义了本身的一个字段。这3个类映射到数据后,会别定义成2个数据库表。每一个表都有5个字段
m1 = Mon(user='ds',headline='sds') m1.content = 'sddhjk' m1.save()
多表继承的模型类都在底层的数据库中生成了相应的数据表管理数据。不管是父表仍是子表都会用数据库中相对应的数据表维护模型的数据,父类中的字段不会重复的在多个子表中进行定义。从这方面来说,多表继承才是真正面向对象的ORM技术。
多表继承不须要特殊的关键字。在Django内部经过在父类和子类之间创建一对一关系来实现多表继承,示例代码以下。
from django.db import models class MessageBase(models.Model): id = models.AutoField() content = models.CharField(max_length=100) user = models.CharField(max_length=20) pub_date = models.DateTimeField() class Mon(MessageBase): headline = models.CharField(max_length=50) class Com(MessageBase): life = models.CharField(max_length=30,default='wl',choices=(('1','2'),('sjdk','idi')))
仍然能够直接引用父类定义的字段,同时子类能够经过父类对象引用访问父类的示例。上述代码在数据库中会实际生成3个数据表。同时在对模型的编程过程当中,子类
# 新建Mon对象,直接在子类中引用父类字段 m1 = Mon(user='ds',headline='sds') m1.content = 'sddhjk' m1.save() # 经过父类引用父类字段 print(m1.messagebase.content)
4.4.3 代理继承
代理模型继承指父类用于在底层数据库中管理数据表,而子类不定义数据列。只定义查询数据集的排序方式等元数据。前两种继承模型中都有实际存储数据的做用,而代理模式继承中子类只用于管理父类的数据,而不实际存储数据。设置的方法是在Meta中定义proxy=True属性来实现,示例代码以下:
class MessageBase(models.Model): id = models.AutoField() content = models.CharField(max_length=100) user = models.CharField(max_length=20) pub_date = models.DateTimeField() class Mon(MessageBase): class Meta: proxy = True ordering = ["-pub_date"]
Django视图层的主要做用是衔接HTML模板、python程序、HTTP请求等。
URL分发映射配置能够被看作Django项目的入口配置,经过URL分发能够指定用户的每个访问的后台python处理函数是什么。
每个django项目都有一个urls.py文件用于维护自身的URL dispatcher,该文件的基本内容以下:
from django.contrib import admin from django.urls import path from django.conf.urls import url from . import views urlpatterns = [ url(r'^welcome',views.welcome), url(r'^moments_input/',views.moments_input), ]
程序经过维护urlpatterns列表中的元素完成URL的映射,每一个元素都是一个django.conf.urls.url的实例,函数url()的第1个参数是HTTP路径,第2个参数是该路径映射到的python函数名。
正则表达式速查表
符号 |
说明 |
例子 |
\ |
将下一个字符标记为特殊字符 |
“\n”匹配一个换行符 “\\”匹配一个“\” “\(”匹配一个“(” |
^ |
字符串的开始位置 |
“^abc”:以abc开头 |
$ |
字符串的结束位置 |
“abc$”:以abc结尾 |
* |
前面的子表达式0或者屡次 |
“2*”匹配“”“2”“2222”等 |
+ |
前面的子表达式1或者屡次 |
“2+”匹配“1”“2”“222”等 |
? |
前面的子表达式0或者1次 |
“3?”匹配“”或者“3” |
. |
除\n之外的任意单个字符 |
|
{n} |
匹配n次 |
“o{2}”:匹配food中的两个o |
{n,} |
至少匹配n次 |
|
{n,m} |
匹配n到m次 |
|
x|y |
匹配x或者y |
Asd|sdf:匹配Asd或者sdf |
[xyz] |
匹配xyz中任一字符 |
[123]匹配1,2或者3 |
[a-z] |
匹配a-z范围内的字符 |
|
[^a-z] |
匹配不在a-z范围内的字符 |
|
5.1.3 命名URL映射
在普通的URL映射中,Django将URL中的变量参数按照路径中的出现顺序传递给被调用函数。而命名URL参数映射使得开发者能够定义这些被传递参数的名称,命名URL参数的定义方式为 ?p<param_name>pattern,示例代码以下:
from django.conf.urls import url from . import views urlpatterns = [ url(r'^year/2015/$',views.year2015), url(r'^year/?p<year>([0-9]{4})/$',views.year), url(r'^year/?p<year>([0-9]{4})/?p<month>([0-9]{2})/$',views.month), ]
上述代码中的后两个url()使用命名参数进行了定义,他们调用Views.py文件中的相关函数,调用的方式为year(request,year=xxxx)和month(request,year=xxxx,month=xx)。
当多个URL映射到一个地址是,只选择第一个映射。
在实际的大型项目开发中,一个项目可能包含多个Django应用,而每个都有本身的URL映射规则。这个时候讲全部的URL映射都保存在一个文件中很是不利于对项目进行维护,因此Django提供了include()函数来进行分布式的URL映射。在项目djangotest/djangotest/urls/py的文件中引用其余应用的URL映射文件的代码以下:
from django.contrib import admin from django.urls import path from django.conf.urls import include,url urlpatterns = [ url('admin/', admin.site.urls), url(r'^app/', include('app.urls')), ]
5.1.5 反向URL映射
除了以上介绍的几种映射方式,Django还提供了反向的从映射名到URL地址的解析功能。URL反向解析使得开发者能够用映射名代替不少须要写绝对URL路径的地方,提升了代码的可维护性。
待续。。。很是重要
视图函数是Django开发者处理HTTP请求的python函数。在一般的状况下,视图函数的功能是经过模型层对象处理数据,而后用以下所示的一种方式返回数据。
对于如下简单的页面,能够直接在视图函数中构造返回给客户端的字符串,该功能是经过HttpResponse()函数封装返回。
from django.http import HttpResponse def index(request): HttpResponse('<h2>我是你爸爸!</h2>')
from django.shortcuts import render def index(request): render(request,'index.html')
render()函数的第一个参数是HTTP Request,第二个参数是模板文件名,第三个参数是想模板文件中返回的数据,是字典的形式。
5.2.3 返回HTTP错误
HTTP的错误经过HTTP头中的status来进行表述,经过给httpResponse函数传递status参数能够返回HTTP的错误或者状态。如:
from django.http import HttpResponseRedirect,HttpResponse def index(request): HttpResponse(status=404)
经过上述的代码能够返回HTTP 404错误。可是为了方便开发者的使用,Django对经常使用的status状态进行了进一步的封装,具体的实现以下所示:
模板文件是一种文本文件,主要又目标文件的内容组成,而后辅以模板的特殊语法用于替换动态内容。下面的代码是一个功能较为齐全的模板文件。
{% extend "base.html" %} # 继承基类模板 {% block title %}title 内容{% endblock %} {% block content %} <h1>{{ section.title }}</h1> {% for i in ins %} <h3> {{ i.code | upper }} </h3> {% endfor %} {% endblock %}
{% for moment in moments %} <h3> {{ moment.user | upper }} </h3> {% endfor %} {% if moment.id < 10 %} <h3>{{ moment.headline }}</h3> {% elif moment.id < 20 %} <h3>{{ moment.headline }}</h3> {% else %} <h3>{{ moment.headline }}</h3> {% endif %}
过滤器在模板中是放在变量后面用于对变量显示的结果进行控制的技术,变量和过滤器之间用管道符号进行链接。具体的过滤器以下图所示。
过滤器 |
说明 |