<div id="content_views" class="markdown_views">
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
</svg>
<p>2017年12月2日,<a href="https://so.csdn.net/so/search?q=Django&spm=1001.2101.3001.7020" target="_blank" class="hl hl-1" data-report-click="{"spm":"1001.2101.3001.7020","dest":"https://so.csdn.net/so/search?q=Django&spm=1001.2101.3001.7020","extra":"{\"searchword\":\"Django\"}"}" data-tit="Django" data-pretit="django">Django</a>官方发布了2.0版本,成为多年来的第一次大版本提升,那么2.0对广大Django使用者有哪些变化和需要注意的地方呢?</p>
<p>一、Python兼容性 <br> Django 2.0支持Python3.4、3.5和3.6。Django官方强烈推荐每个系列的最新版本。 <br> 最重要的是Django 2.0不再支持Python2!Django 1.11.x是支持Python2.7的最后版本。</p>
<p>二、2.0新特性</p>
<p>1.简化了URL路由语法</p>
<p>django.urls.path()方法的语法更简单了。例如以前的:</p>
<pre class="prettyprint" data-index="0" name="code"><code class="hljs python has-numbering" onclick="mdcp.copyCode(event)" style="position: unset;">url(<span class="hljs-string">r'^articles/(?P<year>[0-9]{4})/$'</span>, views.year_archive),<div class="hljs-button {2}" data-title="复制"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li></ul></pre>
<p>可以写作:</p>
<pre class="prettyprint" data-index="1" name="code"><code class="hljs vbnet has-numbering" onclick="mdcp.copyCode(event)" style="position: unset;">path(<span class="hljs-comment">'articles/<span class="hljs-xmlDocTag"><int:year></span>/', views.year_archive),</span><div class="hljs-button {2}" data-title="复制"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li></ul></pre>
<p>新语法支持强制定义参数类型。例子中只接收整数型年份参数,不再接收字符串类型,同时“10000”年也是合法的(虽然是5位数字),而不像先前正则里只能接收4位数字。 <br> 以前版本的<code>django.conf.urls.url()</code>方法变成了<code>django.urls.re_path()</code>,但为了向后兼容,旧的依然保留,而不是立刻废弃。<code>django.conf.urls.include()</code>方法现在可以从django.urls导入,也就是你可以使用<code>from django.urls import include, path, re_path</code>。</p>
<p>2.admin后台对移动端更加友好 <br> Django最受大家欢迎的admin后台,具有响应式特性,支持主流的移动设备。</p>
<p>3.Window 表达式 <br> 新的Window表达式允许为查询集添加一个OVER从句。 <br> 4.小特性</p>
<h6 id="djangocontribadmin">django.contrib.admin</h6>
<p>后台新的<code>ModelAdmin.autocomplete_fields</code>属性 和<code>ModelAdmin.get_autocomplete_fields()</code>方法现在可以在外键和多对多字段上使用Select2搜索框。</p>
<h6 id="djangocontribauth">django.contrib.auth</h6>
<p>用户认证PBKDF2密码哈希默认的迭代次数从36000增加到100000。</p>
<h6 id="djangocontribgis">django.contrib.gis</h6>
<p>地理框架为AsGeoJSON、GeoHash和GeoHash方法,isvalid和distance查询增加MySQL支持;</p>
<ul><li>添加Azimuth和LineLocatePoint方法,支持PostGIS和SpatiaLite;</li><li>所有从GeoJSON导入的GEOSGeometry拥有SRID集合;</li><li>添加OSMWidget.default_zoom属性,用于自定义地图的默认缩放级别; </li><li>metadata现在是可读可编辑的;</li><li>允许在GDAL的内部虚拟文件系统中创建GDALRaster对象;</li><li>新的GDALBand.color_interp()方法返回波段的颜色说明。</li></ul>
<h6 id="djangocontribpostgres数据库">django.contrib.postgres数据库</h6>
<ul><li>ArrayAgg新增distinct参数;</li><li>新的RandomUUID函数;</li><li>django.contrib.postgres.indexes.GinIndex现在支持fastupdate和gin_pending_list_limit参数;</li><li>新的GistIndex类允许在数据库中创建GiST索引;</li><li>inspectdb现在可以内省JSONField和RangeFields。</li></ul>
<h6 id="djangocontribsitemaps站点地图">django.contrib.sitemaps站点地图</h6>
<ul><li>为GenericSitemap构造器增加protocol参数;</li></ul>
<h6 id="cache缓存">Cache缓存</h6>
<ul><li>cache.set_many()现在返回一个列表,包含了插入失败的键值;</li></ul>
<h6 id="file-storage文件存储">File Storage文件存储</h6>
<ul><li>File.open()现在可以用于上下文管理器,例如with file.open() as f:;</li></ul>
<h6 id="forms表单">Forms表单</h6>
<ul><li>SplitDateTimeWidget和SplitHiddenDateTimeWidget增加date_attrs与time_attrs参数,用于为DateInput与TimeInput指定HTML属性;</li><li>新的Form.errors.get_json_data()方法返回字典类型的表单错误,以适应JSON类型x响应;</li></ul>
<h6 id="generic-views通用视图">Generic Views通用视图</h6>
<ul><li>新的ContextMixin.extra_context属性允许在View.as_view()中添加上下文;</li></ul>
<h6 id="management-commands管理命令">Management Commands管理命令</h6>
<ul><li>inspectdb现在将MySQL的无符号整数视作PositiveIntegerField或者######PositiveSmallIntegerField;</li><li>新增makemessages –add-location选项;</li><li>loaddata现在可以从标准输入读入;</li><li>新增diffsettings –output选项;</li></ul>
<h6 id="migrations迁移">Migrations迁移</h6>
<ul><li>新增squashmigrations –squashed-name选项;</li></ul>
<h6 id="models模型">Models模型</h6>
<ul><li>新增StrIndex数据库函数;</li><li>对于Oracle数据库,AutoField和BigAutoField现在会生成identity列;</li><li>QuerySet.iterator()新增chunk_size参数;</li><li>QuerySet.earliest()、QuerySet.latest()和Meta.get_latest_by现在可以根据一些字段进行排序;</li><li>增加ExtractQuarter方法,用于DateField和DateTimeField;</li><li>新增TruncQuarter方法用于截取DateField和DateTimeField到季度的第一天;</li><li>为基于类的索引添加db_tablespace参数;</li><li>为QuerySet.select_for_update()增加of参数,但只支持PostgreSQL和Oracle数据库;</li><li>QuerySet.in_bulk()新增field_name参数;</li><li>CursorWrapper.callproc()现在接收可选的字典类型关键字参数;</li><li>QuerySet.values_list()新增named参数,用于获取命名的元组结果;</li><li>新的FilteredRelation类允许为查询集增加一个ON从句;</li><li>Pagination分页</li><li>增加Paginator.get_page(),可以处理各种非法页面参数,防止异常;</li></ul>
<h6 id="requests-and-responses请求和响应">Requests and Responses请求和响应</h6>
<ul><li>现在,runserver服务器支持HTTP 1.1;</li></ul>
<h6 id="templates模版">Templates模版</h6>
<ul><li>为了提高Engine.get_default()在第三方模块的用途,现在它将返回配置在TEMPLATES中的多个DjangoTemplates引擎中的第一个,而不是弹出ImproperlyConfigured错误;</li><li>自定义模版标签现在接收强制关键字参数;</li></ul>
<h6 id="tests测试">Tests测试</h6>
<ul><li>为LiveServerTestCase添加多线程支持;</li></ul>
<h6 id="validators验证器">Validators验证器</h6>
<ul><li>新的ProhibitNullCharactersValidator不允许CharField及其子类的表单输入为空;</li></ul>
<p>三、重要的向后不兼容</p>
<ol><li><p>某些地方删除对bytestrings的支持 <br> 例如,对于reverse(),现在使用str()代替force_text()。</p></li><li><p>AbstractUser.last_name的最大长度增加到150 <br> 如果你有一个自定义的用户模型继承了AbstractUser,你需要生成并应用一个数据库迁移,使得last_name的最大长度变为150。 <br> 如果你需要为last_name保持30个字符的限制,可以如下使用自定义表单:</p></li></ol>
<pre class="prettyprint" data-index="2" name="code"><code class="hljs haskell has-numbering" onclick="mdcp.copyCode(event)" style="position: unset;"><span class="hljs-title">from</span> django.contrib.auth.forms <span class="hljs-import"><span class="hljs-keyword">import</span> UserChangeForm</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-type">MyUserChangeForm</span><span class="hljs-container">(<span class="hljs-type">UserChangeForm</span>)</span>:
last_name = forms.<span class="hljs-type">CharField</span><span class="hljs-container">(<span class="hljs-title">max_length</span>=30, <span class="hljs-title">required</span>=<span class="hljs-type">False</span>)</span></span><div class="hljs-button {2}" data-title="复制"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li></ul></pre>
<p>如果你需要在admin中也保持这个约束,那么可以如下使用</p>
<pre class="prettyprint" data-index="3" name="code"><code class="hljs avrasm has-numbering" onclick="mdcp.copyCode(event)" style="position: unset;">UserAdmin<span class="hljs-preprocessor">.form</span>:
from django<span class="hljs-preprocessor">.contrib</span><span class="hljs-preprocessor">.auth</span><span class="hljs-preprocessor">.admin</span> import UserAdmin
from django<span class="hljs-preprocessor">.contrib</span><span class="hljs-preprocessor">.auth</span><span class="hljs-preprocessor">.models</span> import User
class MyUserAdmin(UserAdmin):
form = MyUserChangeForm
admin<span class="hljs-preprocessor">.site</span><span class="hljs-preprocessor">.unregister</span>(User)
admin<span class="hljs-preprocessor">.site</span><span class="hljs-preprocessor">.register</span>(User, MyUserAdmin)<div class="hljs-button {2}" data-title="复制"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li><li style="color: rgb(153, 153, 153);">6</li><li style="color: rgb(153, 153, 153);">7</li><li style="color: rgb(153, 153, 153);">8</li><li style="color: rgb(153, 153, 153);">9</li></ul></pre>
<p>3 . QuerySet.reverse()和last()不 <br> 能用于切片后的查询集 <br> 对切片后的查询集使用反转和获取最近对象的操作将弹出异常,如下所示:</p>
<pre class="prettyprint" data-index="4" name="code"><code class="language->>> Model.objects.all()[:2].reverse() hljs r has-numbering" onclick="mdcp.copyCode(event)" style="position: unset;">Traceback (most recent call last):
<span class="hljs-keyword">...</span>
TypeError: Cannot reverse a query once a slice has been taken.<div class="hljs-button {2}" data-title="复制"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li></ul></pre>
<p>4 . 表单的字段不再接收可选参数作为位置参数 <br> 为了防止运行时错误,提高可靠性。以前类似下面的参数传递方法,现在是错误的了: <br> <code>forms.IntegerField(25, 10)</code> <br> 要这么传递: <br> <code>forms.IntegerField(max_value=25, min_value=10)</code> <br> 5 . Index不再接收位置参数 <br> 例如下面的用法将导致异常: <br> <code>models.Index(['headline', '-pub_date'], 'index_name')</code> <br> 要提供参数关键字,改写为: <br> <code>models.Index(fields=['headline', '-pub_date'], name='index_name')</code> <br> 6 . call_command()将验证它接收的选项 <br> 对于使用选项而不是使用parser.add_argument()进行自定义的管理命令,需要添加一个stealth_options属性,如下所示:</p>
<pre class="prettyprint" data-index="5" name="code"><code class="hljs r has-numbering" onclick="mdcp.copyCode(event)" style="position: unset;">class MyCommand(BaseCommand):
stealth_options = (<span class="hljs-string">'option_name'</span>, <span class="hljs-keyword">...</span>)<div class="hljs-button {2}" data-title="复制"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li></ul></pre>
<p>7 . SQLite现在支持外键约束 <br> 另外,Django2.0还废弃和移除了一些方法和属性</p>
</div>
版权声明:本文为shclbear原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。