Django框架基础6
本节重点:
1、path方法函数定义(path(route, view, kwargs, name))
2、re_path正则表达式匹配('test/(?P<year>[0-9]{4})/', views.year_test)
3、shell方法插入数据book=Book(....);book.save()
4、create方法创建Model实例(Book.object.create(...))
5、get查询方法(Author.objects.get(....))
6、get_or_create查询(有就查询False,无就创建True)
7、原生数据库操作——raw()方法查询
8、原生数据库操作——游标cursor执行SQL语句
一、Django路由Path方法
1、初始path()方法
path 函数来进行路由的匹配,可通过以下方式进行导入:
#新的2.x版本导入path,导入简化
from django.urls import path
#原来的1.x版本url方式,conf子包
from django.conf.urls import url
但是之前的 url 模块并没有废止,只是 Django 强烈建议我们使用新模块 path 进行路由的匹配。
2、
path 函数在 Django中的的定义如下所示:
path(route, view, kwargs, name)
它可以接收 4 个参数,其中前两个是必填参数后两个为可选参数。参数解析如下:
-
-
view:指的是处理当前 url 请求的视图函数。当 Django 匹配到某个路由条目时,自动将封装的 HttpRequest 对象作为第一个参数,被“捕获”的参数以关键字参数的形式,传递给该条目指定的视图函数。
-
kwargs:指使用字典关键字传参的形式给关联的目标视图函数传递参数。
-
name:给 URL 起个别名,常用于 url 的反向解析,避免在模板中适应硬编码的方式使用嵌入 url,在后续章节会进行详细讲解。
当使用 path 方法关联视图函数时与 url 方法相比更为简化,也更容易让初学者理解。
path 方法引入了类型转化器(converter type)的概念,以此省去了较为复杂的正则表达式匹配路由的方法。
实例说明如下:
#1.x url方法
url(r'^test/(?P<year>[0-9]{4})/$', views.year_test),
#2.x path方法
path('test/<int:year>/', views.year_test),
int 支持整数类型的转化,在上述的例子中, year_test 函数接收到的 year 参数就变成整数而不是字符串,从而避免在视图中使用 year=int(year)。
path 函数定义的<int:year>
规则会捕获到 URL 中的值,映射给视图中的同名参数 year ,并根据转换器将参数值转换为指定的类型,这里对应 int 大于等于 0 的整数。
之所以使用转化器,有以下两个原因:
-
第一是可以将捕获到的字符值转换为对应的类型;
-
第二是对 URL 中传值的一种限制,避免视图处理出错;
在使用 url 函数时候,我们遇上这样一种情景:即不同的视图函数使用相同的字段作为参数,那么 url 函数也会使用相同正则表达式,只是它们关联的视图函数不同,但是当这个被关联的字段更改的是后,那么可想而知,我们也需要修改所有的正则表达式,重新匹配它,举例如下:
#views.py 视图函数
def year_test(request, year):
year = int(year) # 转换整形
urls.py 中配置路由如下所示:
from django.conf.urls import url #引入url方法
urlpatterns = [
url('test/(?P<year>[0-9]{4})/', year_tst),
url('test/(?P<id>[a-zA-Z0-9]+)/num/', num_view),
url('test/(?P<id>[a-zA-Z0-9]+)/num1/', num1_view),
url('test/(?P<id>[a-zA-Z0-9]+)/num2/', num2_view),
]
利用 path 方法中提供的类型转换器就很好的解决了这一问题。
3、
下面介绍 Django 默认支持的转换器,如下所示:
-
str:匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式;
-
int:匹配正整数,包含0;
-
slug:匹配字母、数字以及横杠、下划线组成的字符串;
-
uuid:匹配格式化的 uuid,如 075194d3-6885-417e-a8a8-6c931e272f00;
-
path:匹配任何非空字符串,包含了路径分隔符。
4、
Django 2.x 之后也支持我们使用正则表达式来捕获值,在这里需要使用 re_path(),而不是前面介绍的 path()。我们使用带命名的正则表达式分组,语法如下:
(?P<name>pattern)
其中,尖括号里的name为分组名,pattern为正则表达式。re_path()同样包含于django.urls
模块中,所以同样使用如下方式进行导入。示例如下:
from django.urls import path, re_path #导入re_path
from . import views
urlpatterns = [
re_path('test/(?P<year>[0-9]{4})/', views.year_test),
re_path('test/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/', views.month_test)]
二、Django实现数据插入
我们之前利用 Model 模型类创建了 index 应用所需的三张数据表,在本节我们介绍如何实现在 Django 项目中创建 Model 的实例对象,即向数据表中插入数据。
python manage.py shell
然后创建 Model 实例,使用 save() 方法保存数据,如下所示:
from index.models import Book #导入相关model类
#创建Book实例化对象
book=Book(title="Python",public="清华出版社",price="80.00",retail_price="80.00")
book.save()# 调用save方法进行保存
book=Book(title="Flask",public="图灵出版社",price="30.00",retail_price="30.00")
book.save()# 调用save方法进行保存
book=Book(title="Django",public="北大出版社",price="50.00",retail_price="50.00")
book.save()# 调用save方法进行保存
最后调用 save 方法进行保存。通过上述代码,我们就在数据库中添加了三条有关书籍的记录。
创建 Book 实例,其实就是填充有关 Model 实例的各个字段,如果设置了默认值或者有允许为 null 的字段可以不填,最后调用 save() 保存实例(该方法没有返回值)。在 save() 执行以后,Django 会将 book实例化数据保存到数据库中。
注意,每创建一条数据都需要调用一次 save() 方法。
2、
Book.objects.create(title="Java",public="北大出版社",price="30.00",retail_price="30.00")
然后继续插入如下数据:
Book.objects.create(title="MySQL",public="北大出版社",price="35.00",retail_price="35.00")
Book.objects.create(title="C#",public="北大出版社",price="45.00",retail_price="40.00")
Book.objects.create(title="Redis",public="北大出版社",price="25.00",retail_price="25.00")
这种创建 Model 实例对象的过程比较简单,create 执行之后就在数据库中插入了一条记录,这也是我们推荐使用的方法。
最后访问数据库可以看到最新插入的数据记录:
from index.models import Author
Author.objects.create(name="Tom",email="456789@163.com")
Author.objects.get(name="Tom")
如果执行两次下面的语句,就会有两个Tom
Author.objects.create(name="Tom",email="456789@163.com")
此时执行 Author.objects.get(name="Tom") 会报错
该方法的查询过程与 get 类似,都需要传递查询参数,但是不 get 不同的是,它返回值是一个 tuple 对象,通过举例子来说明。
Author.objects.get_or_create(name="Xiaolong")#先查询是否存在若不存在则新建该实例对象
元组中的第一个元素代表实例对象,第二个元素是布尔值,标识返回的实例对象是否是新创建的,其中 True 代表新建实例对象,False 代表原有实例对象。
所谓原生数据库操作即使用 SQL 语句来进行数据库的相关的查询操作。
那你可能会问,Django 已经有 ORM 了,为什么还会提供原生语句的操作呢?
在 Django 中,可以使用模型管理器(Marager)的 raw 方法来执行 select 语句进行数据的查询。raw 方法的返回值是一个 RawQuerySet 对象,该对象支持索引和切片,同样也可以对它进行迭代得到 Model 实例对象。但是,与 QuerySet 不同的是,它不能执行 fillter、exclude 等方法。下面通过举例说明 raw 方法如何使用。
MyModel.objects.raw('sql语句')
def BookName(request):
books=Book.objects.raw("select * from index_book") #书写sql语句
return render(request,"index/allbook.html",locals())
在 templates\index 中创建 allbook.html,代码如下:
{% for book in books %}
<p>{{book.title}}</p>
{% endfor %}
最后配置路由。
通过访问 127.0.0.1:8000/index/allbook/,可以得到所有书籍的 title。
那么执行非查询语句呢?如何使用原生的 SQL 语句呢? Django 提供了游标 cursor 对数据库进行增删改操作,在 Django 中执行非查询语句必须使用游标进行操作。游标 cursor 定义在 django.db.connection 包中,使用前用下面的方式进行导入:
from django.db import connection
用创建 cursor 类的构造函数创建 cursor 对象,再使用 cursor 对象执行 SQL 语句。为确保能够在出现异常时释放 cursor 游标,通常使用 with 语句进行创建操,如下所示:
from django.db import connection
with connection.cursor() as cur:
cur.execute('执行SQL语句')
使用示例如下:
from django.db import connection
with connection.cursor() as cur:
#调用游标对象的execute方法,更新author的名字
cur.execute('update index_author set name="Jack" where id=3;')
with connection.cursor() as cur:
# 删除id为3的一条author记录
cur.execute('delete from index_author where id=3;')
虽然 Django 提供了 raw SQL的查询方法以及 cursor 游标对象的使用,但是它们很少的被使用,应为这些方法都需要考虑不同数据库的不同特性。Django 官网建议我们尽量使用 ORM 模块来完成相关操作。