昨日内容回顾:

1. {% include '' %}
2. extend base.html: <html>
.....
.....
.....
{% block content%}
{% endblock%}
</html> index.html:
{% extend 'base.html'%}
<p>python</p>
{% block content%}
<p>hello</p>
{% endblock%} 子网页,也可以设置css和js。比如:
{% block css %}
{% endblock %} {% block js %}
{% endblock %} models:ORM class ----- 表
属性变量 ----- 字段名称
属性值 ----- 字段约束 对象 ------ 记录 创建表的流程 1. 在models里设计模型类
class Book(models.Model):
nid=models.AutoField(primary_key=True)
...
2. 更改数据库为mysql,在settings中:
2.1 先注册app
INSTALLED_APPS = [
...
'app01',
]
2.2 更改数据库引擎
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 数据库引擎mysql
'NAME': 'book', # 你要存储数据的库名,事先要创建之
'USER': 'root', # 数据库用户名
'PASSWORD': '', # 密码
'HOST': 'localhost', # 主机
'PORT': '', # 数据库使用的端口
}
} 3. 创建数据库book
4. 必须安装2个模块
pip3 install pymysql
pip3 install mysqlclient 5.
python manage.py makemigrations(同步)
python manage.py migrate(执行sql)

一、单表操作

添加表纪录

create(**kwargs) 建立新对象

返回值是添加的model对象

方式1

create方法的返回值book_obj就是插入book表中的python葵花宝典这本书籍纪录对象

book_obj=Book.objects.create(title="python葵花宝典",state=True,price=100,publish="苹果出版社",
pub_date="2012-12-12")

方式2

book_obj=Book(title="python葵花宝典",state=True,price=100,publish="苹果出版社",pub_date="2012-12-12")
book_obj.save()

举例:

修改settings.py,打印orm转换过程中的sql。最后一行,添加如下内容:

LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}

修改urls.py,增加add路径

from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('add/', views.add),
]

models.py内容如下:

class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField(max_length=32, unique=True)
price = models.DecimalField(max_digits=8, decimal_places=2)
pub_date = models.DateField()
publish = models.CharField(max_length=32)

表已经生成了,但是表记录是空的。

Pycharm有自带的工具,可以操作MySQL。点击右侧的Database

点击加号-->Data Source-->MySQL

这里提示要安装MySQL驱动,点击旁边的Download

正在下载安装

出现下面的效果,表示安装成功。

点击测试连接,出现Successful,表示连接成功。

双击展开,就可以看到app01_book表了。虽然models.py里面的类名是Book,但是实际创建的表名是应用名+models.py里面的类名。用下划线分割,大写字母会变成小写。

修改views.py,增加add视图函数。

注意,需要导入models模块

这里面的title,price...变量是和Book类的属性是一一对应的,否则会报错。

from django.shortcuts import render,HttpResponse
from app01.models import Book
# Create your views here.
def add(request):
book = Book(title="北京折叠",price="11.11",pub_date="2012-12-12",publish="苹果出版社")
book.save() return HttpResponse("添加成功")

这是第一种方式:实例化一个对象,并传参。

pub_date的值,必须是xxxx_xx_xx格式。用下划线分隔,其他符合是不可以的。

访问网页,效果如下:

双击右边的book表,查看表记录。点击刷新按钮,就可以看到数据了。

注意:只要django执行了视图函数的那2句代码,就可以插入一条记录。

并不一定,非要在views.py里面才行。具体放在哪里,是根据业务逻辑来处理。

一般请求下,是放在views.py里面。

查看控制台输出信息,会看到一条insert语句

(0.001) INSERT INTO `app01_book` (`title`, `price`, `pub_date`, `publish`) VALUES ('北京折叠', '11.11', '2012-12-12', ' 苹果出版社'); args=['北京折叠', '11.11', '2012-12-12', '苹果出版社']

那么book.save(),就是执行上面这句SQL,来插入一条记录的。

第二种方式:推荐使用
objects:表示管理器。
Book.objects:表示管理book表。
book.objects.create:表示增加操作。

def add(request):
book = Book.objects.create(title="放风筝的人", price="14.11", pub_date="2017-12-12", publish="苹果出版社")
print(book)
print(book.title) return HttpResponse("添加成功")

这种方式,一行代码,就搞定了。

create是有返回值的,create内部里面有save。

访问add页面

查看控制台

(0.002) INSERT INTO `app01_book` (`title`, `price`, `pub_date`, `publish`) VALUES ('放风筝的人', '14.11', '2017-12-12', '苹果出版社'); args=['放风筝的人', '14.11', '2017-12-12', '苹果出版社']
Book object (2)
放风筝的人

create的返回值是一个类对象,比如:Book object

book_obj.title的返回值,就是create里面的值。

create执行的SQL和save是一样的。区别是create代码更精简!

如果create少一个字段,比如price呢?测试一下

def add(request):
book_obj = Book.objects.create(title="放风筝的人2",pub_date="2018-12-12",publish="苹果出版社") return HttpResponse("添加成功")

访问页面,提示price不允许为空

更改models.py里面的price属性,设置价格属性为空

添加字段is_pub,表示是否发布

class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField(max_length=32, unique=True)
price = models.DecimalField(max_digits=8, decimal_places=2,null=True)
pub_date = models.DateField()
publish = models.CharField(max_length=32)
is_pub = models.BooleanField()

Pycharm有一个工具,不同执行繁琐的同步命令

Tools-->Run manage.py Task...

输入ma,就会有提示信息。选择makemigrations,直接回车

最后输出如下信息

意思就是is_pub字段必须设置一个默认值

重新修改models.py下的Book类,增加默认值

is_pub = models.BooleanField(default=False)

关闭下面的小窗口,重新运行命令makemigrations

输出下面信息,表示成功了

执行migrate

查看表记录,发现多了一个is_pub字段。BooleanField对应的MySQL类型是tinyint(1)

那么False对应的值是0,true对应的值是1。

再次刷新页面,就可以了

查看表记录,点击刷新按钮

再次刷新页面,会报错!因为title字段是唯一的。

修改views里面的add视图函数

book_obj = Book.objects.create(title="放风筝的人3", pub_date="2018-12-12", publish="苹果出版社")

再次刷新页面,就可以了。查看表记录,刷新一下

注意:在开发项目时,最好打开日志,这样可以查看ORM转换的SQL语句,方便后面的调试。

查询表纪录

查询API

<1> all():                  查询所有结果

<2> filter(**kwargs):       它包含了与所给筛选条件相匹配的对象

<3> get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,
如果符合筛选条件的对象超过一个或者没有都会抛出错误。 <4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象 <5> order_by(*field): 对查询结果排序 <6> reverse(): 对查询结果反向排序 <8> count(): 返回数据库中匹配查询(QuerySet)的对象数量。 <9> first(): 返回第一条记录 <10> last(): 返回最后一条记录 <11> exists(): 如果QuerySet包含数据,就返回True,否则返回False <12> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
model的实例化对象,而是一个可迭代的字典序列
<13> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 <14> distinct(): 从返回结果中剔除重复纪录

all() 查询所有结果

它返回的是QuerySet数据类型对象,它是django orm 特有的数据类型。

数据格式为:[model对象1,model对象2,model对象3 ...]

它和下面的 animal_list类似。先是一个列表,列表的元素是一个对象

class Annimal(object):
def __init__(self, name, age):
self.name = name
self.age = age def call(self):
return "汪汪汪" dog = Annimal("旺财", 3)
cat = Annimal("小雪", 4)
duck = Annimal("小黄", 5) animal_list = [dog, cat, duck]

一个对象,就是一条记录。有多少条记录,就有多少个对象。

举例:

修改urls.py,增加query路径

urlpatterns = [
path('admin/', admin.site.urls),
path('add/', views.add),
path('query/', views.query),
]

修改views.py,增加query视图函数

def query(request):
ret = Book.objects.all()
print(ret) return HttpResponse("查询成功")

访问页面,效果如下:

查看控制台输出信息:

(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` LIMIT 21; args=()
<QuerySet [<Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>, <Book: Book object (5)>]>

它执行的sql,就是select...。返回结果是一个QuerySet数据类型

它是一个列表,里面放了多个对象。个数取决于返回的行数!

QuerySet和model对象的区别:

只有model对象,才能调用属性。
queryset不能直接调用属性,因为它是一个列表。

既然是列表,就可以使用for循环,打印title属性。

修改query视图函数

def query(request):
book_list = Book.objects.all()
print(book_list)
for obj in book_list:
print(obj.title) # 打印title属性 return HttpResponse("查询成功")

刷新页面,查看控制台,就会有4个书名

北京折叠
放风筝的人
放风筝的人2
放风筝的人3

filter(**kwargs):  它包含了与所给筛选条件相匹配的对象

filter可以用指定条件来查询,它会返回一条或者多条记录。

它的返回值是QuerySet数据类型对象

举例:查看标题为北京折叠的记录

修改query视图函数

def query(request):
ret = Book.objects.filter(title='北京折叠')
print(ret) return HttpResponse("查询成功")

刷新页面,查看控制台信息

(0.001) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`title` = '北京折叠' LIMIT 21; args=('北京折叠',)
<QuerySet [<Book: Book object (1)>]>

它执行的sql,是用了where条件的。

注意,下面这行代码,不能直接执行

print(ret.price)

刷新页面,报错。QuerySet不能直接调用属性,即使它只有一个对象

虽然可以通过切片来调用属性,但是不推荐使用。
因为它的长度是不固定的。

需要使用for循环来执行。

first(): 返回第一条记录

first用来取一条记录,如果返回结果有多条,只会取第一条。

它的返回结果是model对象。

修改query视图函数

def query(request):
obj = Book.objects.all().first()
print(obj) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` ORDER BY `app01_book`.`nid` ASC LIMIT 1; args=()
Book object (1)
北京折叠

查看sql,发现它使用order by排序。对主键nid,做了升序,并且使用limit 1返回一条结果。

ret的返回结果一个是model对象,那么就可以直接调用对象了。所以输出:北京折叠

学习API接口,重要的是它的返回值是什么

last(): 返回最后一条记录

last用来取最后一条记录,如果返回结果有多条,只会取最后一条。

它的返回结果是model对象。可以直接调用属性!

修改query视图函数

def query(request):
obj = Book.objects.all().last()
print(obj)
print(obj.title) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

(0.002) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` ORDER BY `app01_book`.`nid` DESC LIMIT 1; args=()
Book object (5)
放风筝的人3

查看sql,发现它使用order by排序。对主键nid,做了降序,并且使用limit 1返回一条结果。

所以最后输出:放风筝的人3

还可以对all()进行切片操作

def query(request):
obj = Book.objects.all()[1:3]
print(obj)
for i in obj:
print(i.title) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

(0.001) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` LIMIT 2 OFFSET 1; args=()
<QuerySet [<Book: Book object (2)>, <Book: Book object (3)>]>
(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` LIMIT 2 OFFSET 1; args=()
放风筝的人
放风筝的人2

[1:3],返回2条记录。切片原则:顾头不顾尾。

get(**kwargs): 返回与所给筛选条件相匹配的对象

返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。

它的返回结果是一个model对象。

举例:查询nid为1的记录

修改query视图函数‘

def query(request):
obj = Book.objects.get(nid=2)
print(obj)
print(obj.title) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

(0.001) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`nid` = 2; args=(2,)
Book object (2)
放风筝的人

查看sql,发现它对应的where条件是nid = 2。返回结果的title属性为:放风筝的人

举例:查询结果大于1时

查看表记录,修改第3条记录的价格为14.11,并点击上面的提交按钮

修改query视图函数,使用get查询价格等于14.11的记录。

def query(request):
obj = Book.objects.get(price=14.11)
print(obj) return HttpResponse("查询成功")

刷新页面,报错!提示返回结果过多,不能大于2条。

举例:查询结果大于1时,也就是记录不存在时

修改query视图函数,查询价格等于110

def query(request):
obj = Book.objects.get(price=110)
print(obj) return HttpResponse("查询成功")

刷新页面,报错!提示查询结果不存在

下面的代码,也可以返回一条记录

obj = Book.objects.filter(nid=2).first()

但是使用first,它会执行order by。上面的代码转为SQL为:

 SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`nid` = 2 ORDER BY `app01_book`.`nid` ASC LIMIT 1;

那么它的效果不如直接使用get!就一台记录,还排序干啥?

总结:

使用get有且只有一个结果时才有意义。

推荐使用get时,利用主键查询,因为主键是唯一的。

exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象

exists用来做排除的,它的返回结果是QuerySet

举例:查询价格不等于100的

修改query视图函数

def query(request):
obj = Book.objects.exclude(price=100)
print(obj)
for i in obj:
print(i.title,i.price) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

<QuerySet [<Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>, <Book: Book object (5)>]>
(0.001) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE NOT (`app01_book`.`price` = '' AND `app01_book`.`price` IS NOT NULL); args=(Decimal(''),)
北京折叠 11.11
放风筝的人 14.11
放风筝的人2 14.11
放风筝的人3 None

查看sql,发现它对应的where条件用了Not,返回结果是QuerySet

order_by(*field): 对查询结果排序

order_by,默认是升序,它的返回结果是QuerySet

举例:查询所有书籍,按照价格排序

修改表记录,效果如下:

修改query视图函数

def query(request):
obj = Book.objects.order_by("price")
print(obj)
for i in obj:
print(i.title,i.price) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

<QuerySet [<Book: Book object (5)>, <Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>]>
(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` ORDER BY `app01_book`.`price` ASC; args=()
水浒传 11.00
北京折叠 11.11
放风筝的人 14.11
西游记 233.00

如果指定的字段值为空,则按照主键排序。

每次for循环查看结果,太麻烦了。可以在models.py里面增加一个__str__方法。

修改models.py,增加__str__方法,完整代码如下:

from django.db import models

# Create your models here.
class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField(max_length=32, unique=True)
price = models.DecimalField(max_digits=8, decimal_places=2,null=True)
pub_date = models.DateField()
publish = models.CharField(max_length=32)
is_pub = models.BooleanField(default=False) def __str__(self):
return '{}:{}'.format(self.title,self.price)

修改views.py下的query方法,代码如下:

def query(request):
obj = Book.objects.order_by("price")
print(obj) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

(0.001) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` ORDER BY `app01_book`.`price` ASC LIMIT 21; args=()
<QuerySet [<Book: 水浒传:11.00>, <Book: 北京折叠:11.11>, <Book: 放风筝的人:14.11>, <Book: 西游记:233.00>]>

可以直接看到title和价格!

注意:只有QuerySet数据类型对象,才能调用order_by

reverse():  对查询结果反向排序

它的返回结果是QuerySet

举例:

修改query方法

def query(request):
obj = Book.objects.all().order_by("price").reverse()
print(obj) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

<QuerySet [<Book: 西游记:233.00>, <Book: 放风筝的人:14.11>, <Book: 北京折叠:11.11>, <Book: 水浒传:11.00>]>
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` ORDER BY `app01_book`.`price` DESC LIMIT 21; args=()

它的sql语句用的是desc

count(): 返回数据库中匹配查询的对象数量。

它的返回结果数据类型是int

它是queryset的终止函数。为什么呢?因为它不能进行链式操作!

下面这种,就属于链式操作。因为queryset可以调用API接口,只要前一个接口的返回值是queryset,它可以可以一直调用API接口,除非遇到返回值不是queryset的情况下,链式操作,才可以终止。因为count的返回值是int,所以到这里,就结束了!不能再调用API接口了!

Book.objects.all().filter(price__gt=100).order_by("pirce").count()

举例:

修改query视图函数

def query(request):
obj = Book.objects.all().count()
print(obj) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

4
(0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.000) SELECT COUNT(*) AS `__count` FROM `app01_book`; args=()

obj的返回结果为4

exists(): 如果QuerySet包含数据,就返回True,否则返回False

它的返回结果是一个布尔值

举例:如果表里面有书,输入ok,否则输出none

修改query视图函数,使用常规方法

def query(request):
ret = Book.objects.all()
if ret:
print('ok') return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

ok
(0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.001) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book`; args=()

ret结果为ok,它使用全表查询,但是这样有一个bug

如果数据库有1000万本,这样一查,数据库就崩溃了。

修改query视图函数,使用exists

def query(request):
ret = Book.objects.all().exists()
if ret:
print('ok') return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

ok
(0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.001) SELECT (1) AS `a` FROM `app01_book` LIMIT 1; args=()

ret结果为ok,它用limit 1。它只查询了一条记录!

即使数据库记录过多,也不影响。这样才是合理的!

上述这些API方法,都是QuerySet在调用

下面即将讲到的values,values_list,distinct。是一系列操作!

values(*field): 返回一个ValueQuerySet

它是一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列

它的返回结果是一个特殊的QuerySet,列表每一个元素都是字典

除了使用for循环之外,还有一个更好的方式。使用values,它内部封装了for循环

举例:查询所有书籍名称

修改query视图函数

def query(request):
ret = Book.objects.all().values("title")
print(ret) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

(0.000) SELECT `app01_book`.`title` FROM `app01_book` LIMIT 21; args=()

<QuerySet [{'title': '北京折叠'}, {'title': '放风筝的人'}, {'title': '水浒传'}, {'title': '西游记'}]>

values返回的是QuerySet,列表的每一个元素都是字典。

values可以接收多个参数,比如

ret = Book.objects.all().values("title","price")

字典的key,就是参数。一个字典,对应一条记录。

跟上面讲的QuerySet区别就在于:

不加values,QuerySet存放的是model对象。

加了values之后,QuerySet存放的是字典。

查询某一个字段时,推荐使用values

values_list(*field):   values返回的是一个字典序列

它与values()非常相似,它返回的是一个元组序列

它的返回结果是一个特殊的QuerySet,列表每一个元素都是元组

举例:

修改query视图函数

def query(request):
book_list = Book.objects.all().values_list("title","price","pub_date")
print(book_list) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

(0.000) SELECT `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date` FROM `app01_book` LIMIT 21; args=()

<QuerySet [('北京折叠', Decimal('11.11'), datetime.date(2012, 12, 12)), ('放风筝的人', Decimal('14.11'), datetime.date(2017, 12, 12)), ('西游记', Decimal('233.00'), datetime.date(2018, 7, 1)), ('水浒传', Decimal('11.00'), datetime.date(2018, 7, 2))]>

values_list和values的区别在于:values_list的类型是元组,vallues是字典。

distinct(): 从返回结果中剔除重复纪录

它的返回结果是QuerySet,注意:是一个常规的QuerySet

修改表记录,将前2本书的价格修改为一样的。

使用原生sql查询价格,去除重复的值

mysql> select distinct(price) from app01_book;
+--------+
| price |
+--------+
| 100.00 |
| 233.00 |
| 11.00 |
+--------+
rows in set (0.00 sec)

如果使用distinct对主键做去重,是没有意义的。因为主键是唯一的!

mysql> select distinct(nid) from app01_book;
+-----+
| nid |
+-----+
| 1 |
| 2 |
| 5 |
| 3 |
+-----+
rows in set (0.01 sec)

对所有字段做去重,也是没有意义的,因为每一条记录,不可能有重复的,这不还有主键嘛

修改query视图函数

def query(request):
ret = Book.objects.all().distinct()
print(ret) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

<QuerySet [<Book: 北京折叠:100.00>, <Book: 放风筝的人:100.00>, <Book: 西游记:233.00>, <Book: 水浒传:11.00>]>
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.000) SELECT DISTINCT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` LIMIT 21; args=()

所有记录都有了,毫无意义

举例:查看所有书籍的价格,结果是不重复的

修改query视图函数

def query(request):
ret = Book.objects.all().values("price").distinct()
print(ret) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

(0.000) SELECT DISTINCT `app01_book`.`price` FROM `app01_book` LIMIT 21; args=()

<QuerySet [{'price': Decimal('100.00')}, {'price': Decimal('233.00')}, {'price': Decimal('11.00')}]>

举例:查看所有书籍的价格以及出版社,价格和出版社同时不能重复

修改query视图函数

def query(request):
ret = Book.objects.all().values("price","publish").distinct()
print(ret) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

<QuerySet [{'publish': '苹果出版社', 'price': Decimal('100.00')}, {'publish': '橘子出版社', 'price': Decimal('233.00')}, {'publish': '橘子出版社', 'price': Decimal('11.00')}]>
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.001) SELECT DISTINCT `app01_book`.`price`, `app01_book`.`publish` FROM `app01_book` LIMIT 21; args=()

发现结果只有3条,它使用了组合去重。2个字段,同时不唯一!

基于双下划线的模糊查询

Book.objects.filter(price__in=[100,200,300])
Book.objects.filter(price__gt=100)
Book.objects.filter(price__lt=100)
Book.objects.filter(price__range=[100,200])
Book.objects.filter(title__contains="python")
Book.objects.filter(title__icontains="python")
Book.objects.filter(title__startswith="py")
Book.objects.filter(pub_date__year=2012)

字段名__gt(大于)

举例:查询价格大于100的

不能这么写

ret = Book.objects.filter(price>100)

正确写法:

def query(request):
ret = Book.objects.filter(price__gt=100)
print(ret) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

<QuerySet [<Book: 西游记:233.00>]>
(0.001) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`price` > '' LIMIT 21; args=(Decimal(''),)

价格大于100的,只有西游记

字段名__lt(小于)

举例:查询价格小于100的

修改query视图函数

def query(request):
ret = Book.objects.filter(price__lte=100)
print(ret) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

<QuerySet [<Book: 北京折叠:100.00>, <Book: 放风筝的人:100.00>, <Book: 水浒传:11.00>]>
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.000) SELECT VERSION(); args=None
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`price` <= '' LIMIT 21; args=(Decimal(''),)

价格小于等于100的,有北京折叠,放风筝的人,水浒传

字段名__gte(大于等于)

举例:查询价格小于等于100的

修改query视图函数

def query(request):
ret = Book.objects.filter(price__gte=100)
print(ret) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

<QuerySet [<Book: 北京折叠:100.00>, <Book: 放风筝的人:100.00>, <Book: 西游记:233.00>]>
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.001) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`price` >= '' LIMIT 21; args=(Decimal(''),)

价格小于等于100的,有北京折叠,放风筝的人,西游记

字段名__in(支持多个选择)

举例:查询价格分别等于100,200,300的记录

修改query视图函数

def query(request):
ret = Book.objects.filter(price__in=[100,200,300])
print(ret) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`price` IN ('', '', '') LIMIT 21; args=(Decimal(''), Decimal(''), Decimal(''))
[27/Jun/2018 20:58:08] "GET /query/ HTTP/1.1" 200 12
<QuerySet [<Book: 北京折叠:100.00>, <Book: 放风筝的人:100.00>]>

价格等于100,200,300的有 北京折叠,放风筝的人

字段名__range(介于两个值之间的数据范围)

举例:查询价格在100到233之间的记录

修改query视图函数

def query(request):
ret = Book.objects.filter(price__range=[100,300])
print(ret) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

<QuerySet [<Book: 北京折叠:100.00>, <Book: 放风筝的人:100.00>, <Book: 西游记:233.00>]>
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`price` BETWEEN '' AND '' LIMIT 21;arg=(Decimal(''),Decimal(''))

价格在100到233之间的有 北京折叠,放风筝的人,西游记

字段名__startswith(以什么开头的)

举例:查询以"北京"开头的书名有哪些

修改query视图函数

def query(request):
ret = Book.objects.filter(title__startswith="北京")
print(ret) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`title` LIKE BINARY '北京%' LIMIT 21; args=('北京%',)

<QuerySet [<Book: 北京折叠:100.00>]>

以"北京"开头的书名的有  北京折叠

字段名__contains(以什么结尾)

举例:查询书名包含“传”的有哪些

修改query视图函数

def query(request):
ret = Book.objects.filter(title__contains="传")
print(ret) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

<QuerySet [<Book: 水浒传:11.00>]>
(0.001) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.001) SELECT VERSION(); args=None
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`title` LIKE BINARY '%传%' LIMIT 21; args=('%传%',)

书名包含“传”的有 水浒传

字段名__year(查询某年)

举例:查询出版日期是2018年的有哪些

修改query视图函数

def query(request):
ret = Book.objects.filter(pub_date__year="")
print(ret) return HttpResponse("查询成功")

刷新页面,查看控制台输出信息:

(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`pub_date` BETWEEN '2018-01-01' AND '2018-12-31' LIMIT 21; args=('2018-01-01', '2018-12-31')

<QuerySet [<Book: 西游记:233.00>, <Book: 水浒传:11.00>]>

出版日期是2018年的有 西游记,水浒传

删除表纪录

删除方法就是 delete()。它运行时立即删除对象而不返回任何值。例如:

model_obj.delete()

你也可以一次性删除多个对象。每个 QuerySet 都有一个 delete() 方法,它一次性删除 QuerySet 中所有的对象。

它的返回值是元组,元组第一个值,是执行状态。1表示成功,0表示失败!

例如,下面的代码将删除 pub_date 是2005年的 Entry 对象:

Entry.objects.filter(pub_date__year=2005).delete()

在 Django 删除对象时,会模仿 SQL 约束 ON DELETE CASCADE 的行为,换句话说,删除一个对象时也会删除与它相关联的外键对象。例如:

b = Blog.objects.get(pk=1)
# This will delete the Blog and all of its Entry objects.
b.delete()

要注意的是: delete() 方法是 QuerySet 上的方法,但并不适用于 Manager 本身。这是一种保护机制,是为了避免意外地调用 Entry.objects.delete() 方法导致 所有的 记录被误删除。如果你确认要删除所有的对象,那么你必须显式地调用:

Entry.objects.all().delete()  

如果不想级联删除,可以设置为:

pubHouse = models.ForeignKey(to='Publisher', on_delete=models.SET_NULL, blank=True, null=True)

举例:删除价格等于100的

修改urls.py,增加delbook路径

urlpatterns = [
path('admin/', admin.site.urls),
path('add/', views.add),
path('query/', views.query),
path('change/', views.change),
path('delbook/', views.delbook),
]

修改views.py,增加delbook视图函数

注意:修改是基于查询的结果来修改的。所以是先有查询,再有修改!

def delbook(request):
ret = Book.objects.filter(price=100).delete()
print(ret) return HttpResponse("删除成功")

访问页面

查看控制台输出信息:

(0.001) DELETE FROM `app01_book` WHERE `app01_book`.`price` = ''; args=(Decimal(''),)
(1, {'app01.Book': 1})

输出1,表示删除成功!

查看表记录,点击刷新按钮,发现少了一条记录!

QuerySet和model都可以调用delete

举例:查询价格小于100的,并将第一条记录删除

修改delbook视图函数

def delbook(request):
ret = Book.objects.filter(price__lte=100).delete()
print(ret) return HttpResponse("删除成功")

查看控制台输出信息:

(0.000) DELETE FROM `app01_book` WHERE `app01_book`.`price` <= ''; args=(Decimal(''),)
[27/Jun/2018 21:41:49] "GET /delbook/ HTTP/1.1" 200 12
(1, {'app01.Book': 1})

输出结果为1,说明删除成功了!

查看表记录,点击刷新按钮,发现少了一条记录!

举例3:根据url的id值,来删除对应的记录

如果url的id为2,就删除nid为2的记录

修改urls.py,为delbook增加有名分组

注意:要导入re_path模块,完整代码如下:

from django.contrib import admin
from django.urls import path,re_path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('add/', views.add),
path('query/', views.query),
path('change/', views.change),
re_path('delbook/(?P<id>\d+)', views.delbook),
]

修改delbook视图函数

def delbook(request,id):
ret = Book.objects.filter(nid=id).delete()
print(ret) return HttpResponse("删除成功")

访问url: http://127.0.0.1:8000/delbook/3

查看控制台输出信息:

(0.001) DELETE FROM `app01_book` WHERE `app01_book`.`nid` = 3; args=(3,)
(1, {'app01.Book': 1})

输出结果为1,说明删除成功了!

查看表记录,点击刷新按钮,发现少了一条记录!

如果删除一条不存在的记录呢?

访问url:http://127.0.0.1:8000/delbook/4

查看控制台输出信息:

(0, {'app01.Book': 0})
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.001) SELECT VERSION(); args=None
(0.001) DELETE FROM `app01_book` WHERE `app01_book`.`nid` = 4; args=(4,)

输出结果为0,说明删除失败了!

但是页面提示删除成功是不对的。

修改delbook视图函数

def delbook(request,id):
ret = Book.objects.filter(nid=id).delete()
print(ret)
print(ret,type(ret)) if ret[0]:
return HttpResponse("删除成功")
else:
return HttpResponse("删除失败")

再次访问url:http://127.0.0.1:8000/delbook/4

查看控制台输出信息:

(0, {'app01.Book': 0})
(0.001) SELECT @@SQL_AUTO_IS_NULL; args=None
(0, {'app01.Book': 0}) <class 'tuple'>
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.000) SELECT VERSION(); args=None
(0.000) DELETE FROM `app01_book` WHERE `app01_book`.`nid` = 4; args=(4,)

它的返回值是一个元组,通过取第一个元素,就可以得到数字0。那么就可以进行if判断了!

修改表纪录

Book.objects.filter(title__startswith="py").update(price=120)

  此外,update()方法对于任何结果集(QuerySet)均有效,这意味着你可以同时更新多条记录update()方法会返回一个整型数值,表示受影响的记录条数。

update的返回值为int。1表示成功,0表示失败。

举例:修改nid为1的记录,将价格修改为1000元

修改urls.py,增加change路径

urlpatterns = [
path('admin/', admin.site.urls),
path('add/', views.add),
path('query/', views.query),
path('change/', views.change),
]

修改views.py,增加change视图函数

注意:修改是基于查询的结果来修改的。所以是先有查询,再有修改!

def change(request):
nid = 1
ret = Book.objects.filter(nid=nid).update(price=1000)
print(ret) return HttpResponse("修改成功")

访问页面

查看控制台输出信息:

(0.001) UPDATE `app01_book` SET `price` = '1000.00' WHERE `app01_book`.`nid` = 1; args=('1000.00', 1)
1

举例:修改西游记的价格为133以及is_pub修改为1

修改change视图函数

def change(request):
nid = 3
ret = Book.objects.filter(nid=nid).update(price=133,is_pub=1)
print(ret) return HttpResponse("修改成功")def change(request):
nid = 3
ret = Book.objects.filter(nid=nid).update(price=133,is_pub=1)
print(ret) return HttpResponse("修改成功")

刷新页面,查看控制台输出信息:

(0.001) UPDATE `app01_book` SET `price` = '133.00', `is_pub` = 1 WHERE `app01_book`.`nid` = 3; args=('133.00', True, 3)
1

ret的返回结果为1,表示修改成功!

查看表记录,点击刷新按钮,发现价格和is_pub已经修改了!

Django基础(3)----模型层-单表操作,多表创建的更多相关文章

  1. Django基础之模型层(02)

    1 重要概念 # 多表查询 """ 正向查询 反向查询 当前查询对象是否含有外键字段 如果有就是正向 没有无则是反向 口诀: 正向查询按外键字段 多对多需要额外再加一个. ...

  2. Django基础之模型层(下)

    聚合查询 关键字:aggregate from django.db.models import Max,Min,Sum,Count,Avg 统计所有书的平均价格 models.Book.objects ...

  3. Django基础之模型层(01)

    内容概要 查询关键字 MySQL select    from    where    group by    having    order by    distinct    limit    r ...

  4. Django模型层-单表操作

    ORM介绍 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的 ...

  5. 第五章、Django之模型层---单表操作

    目录 第五章.Django之模型层---单表操作 一.ORM查询 二.Django测试环境搭建 三.单表查询 1. 增 2. 改 3. 删 4. 查 第五章.Django之模型层---单表操作 一.O ...

  6. python 全栈开发,Day71(模型层-单表操作)

    昨日内容回顾 1. {% include '' %} 2. extend base.html: <html> ..... ..... ..... {% block content%} {% ...

  7. Django之模型层第二篇:多表操作

    Django之模型层第二篇:多表操作 一 表关系回顾 ​ 在讲解MySQL时,我们提到,把应用程序的所有数据都放在一张表里是极不合理的. ​ 比如我们开发一个员工管理系统,在数据库里只创建一张员工信息 ...

  8. Django中模型层中ORM的多表操作

    ORM的多表创建(一对一.一对多,多对多): 1模型创建 实例:我们来假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄. 作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等 ...

  9. Django基础之模型(models)层(上)

    目录 Django基础之模型(models)层 单表查询 必知必会13条 神奇的双下划线查询 多表查询 外键的字段的增删改查 表与表之间的关联查询 基于双下划线的跨表查询(连表查询) 补充知识 Dja ...

随机推荐

  1. VBS错误代码释义

    VBScript 语法错误 如果 VBScript 语句结构违反了一个或多个 VBScript 脚本语言语法规则,就会产生 VBScript 语法错误.VBScript 语法错误通常在执行程序前,编译 ...

  2. 使用Rancher搭建K8S测试环境

    使用Rancher搭建K8S测试环境 http://blog.csdn.net/csdn_duomaomao/article/details/75316926 环境准备(4台主机,Ubuntu16.0 ...

  3. Log4Net日志记录介绍

    原文地址 : http://www.cnblogs.com/wolf-sun/p/3347373.html#3009010 简介 log4net库是Apache log4j框架在Microsoft . ...

  4. Poj 1338 Ugly Numbers(数学推导)

    一.题目大意 本题要求写出前1500个仅能被2,3,5整除的数. 二.题解 最初的想法是从1开始检验该数是否只能被2,3,5整除,方法是这样的,对于一个数,如果它能被2整除,就除以2,如果它能被3整除 ...

  5. BarTender SDK 实现调用模板条码打印

    Demo:MyZebraPrint 基于BatTender .Net SDK 实现调用模板进行条码打印 有需要的朋友可以拿去研究下 在已经安装了BatTender10.1的电脑里测试通过. 下载地址: ...

  6. eclipse安装M2Eclipse插件

    作者:david_zhang@sh [转载时请以超链接形式标明文章] 链接:http://www.cnblogs.com/david-zhang-index/p/7967333.html 图1: 图2 ...

  7. 大数据处理之道(十分钟学会Python)

    一:python 简介 (1)Python的由来 Python(英语发音:/ˈpaɪθən/), 是一种面向对象.解释型计算机程序设计语言,由Guido van Rossum于1989年底发明,第一个 ...

  8. SpringCloud01 服务提供者和消费者

    说明:服务消费者直接利用RestTemplate调用服务提供者,这种使用方式只是适用于微服务数量比较少的项目,如果微服务的数量比较多建议使用SpringCloud提供的Eureaka组件. 注意:实现 ...

  9. 树莓派 Learning 003 --- GPIO 000 --- GPIO引脚图

    树莓派 Learning 003 - GPIO 000 - GPIO引脚图 我的树莓派型号:Raspberry Pi 2 Model B V1.1 装机系统:NOOBS v1.9.2 Raspberr ...

  10. 使用 Chrome Timeline 来优化页面性能

    使用 Chrome Timeline 来优化页面性能 有时候,我们就是会不由自主地写出一些低效的代码,严重影响页面运行的效率.或者我们接手的项目中,前人写出来的代码千奇百怪,比如为了一个 Canvas ...