随笔 - 18  文章 - 1  评论 - 0  阅读 - 19397

Django模型(数据库)

Django模型

Django对各种数据库提供了很好的支持,包括:PostgreSQL、MySQL、SQLite、Oracle。Django为这些数据库提供了统一的调用API,可按需选择不同数据库。

Django模型使用自带的ORM(对象关系映射Object Relational Mapping)用于实现面向对象编程语言里不同类型系统的数据之间的转换。

ORM 在业务逻辑层和数据库层之间充当了桥梁的作用。ORM 是通过使用描述对象和数据库之间的映射的元数据,将程序中的对象自动持久化到数据库中。

ORM解析过程:

  1. ORM将Python代码转换成SQL语句
  2. SQL语句通过pymysql传送到数据库服务端
  3. 在数据库中执行SQL语句并将结果返回
  • 使用ORM优点:提高开发效率、不同数据库可以平滑切换。
  • 使用ORM缺点:ORM代码转换为SQL语句时,需花费一定时间,执行效率会有所降低; 长期写ORM代码,会降低编写SQL语句的能力。

1. MySQL安装

  官网:https://dev.mysql.com/

选择安装版下载:https://dev.mysql.com/downloads/mysql/ ,点击No thanks, just start my download.可立即下载。下载完后解压到本地目录,如 E:\soft\mysql8023

初始化配置:

解压后,在目录E:\soft\mysql8023\mysql-8.0.23-winx64下,

  • 新建一个Data文件夹,用于mysql数据库的数据存放,
  • 新建一个 my.ini 配置文件(新建文本,重命名为my.ini),内容如下:

E:\soft\mysql8023\mysql-8.0.23-winx64\my.ini 文件:

查看代码
[mysqld]
# 设置3306端口
port = 3306

# 设置mysql的安装目录
basedir = E:\\soft\\mysql8023\\mysql-8.0.23-winx64

# 设置mysql数据库的数据存放目录
datadir = E:\\soft\\mysql8023\\mysql-8.0.23-winx64\\Data

# 允许最大连接数
max_connections = 200

# 允许连接失败的次数。这是为了防止有人从该主机试图攻击数据库系统
max_connect_errors = 10

# 服务端使用的字符集默认为UTF8
character-set-server = utf8

# 创建新表时将使用的默认存储引擎
default-storage-engine = INNODB

# 默认使用“mysql_native_password”插件认真
default_authentication_plugin = mysql_native_password

[mysql]
# 设置mysql客户端默认字符集
default-character-set = utf8

[client]
# 设置mysql客户端连接服务端时默认使用的端口
port = 3306
default-character-set = utf8

接下来初始化数据,找到cmd,右键以管理员权限打开cmd:

cd到bin目录: cd /d E:\soft\mysql8023\mysql-8.0.23-winx64\bin

执行命令(初始化数据库):mysqld –initialize –console

执行完成后,会输出root用户的初始密码,如:2021-03-14T10:27:59.584362Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: YQDfWiiKU0;Z

YQDfWiiKU0;Z就是初始密码,后续登录需要用到,你也可以在登陆后修改密码。

注:要是关掉了或没记住,可删掉初始化的datadir目录(即建的Data文件夹),再执行一遍初始化命令mysqld –initialize –console,又会重新生成。

安装mySQL或执行以上命令时报错找不到vcruntime140_1.dll的解决方案:缺少了动态链接库(.ddl文件), 跟mysql无关, 下载一份即可。下载地址:https://pan.baidu.com/s/1QriqbRAA4l_40Kc0-007jQ 提取码:uyp7

https://cn.dll-files.com/download/6fe223ce568d919f80bea233738d0628/vcruntime140_1.dll.html?c=RE5hVFFwZFVkVk16MlY3dW43NDkyQT09

64位,解压后将vcruntime140_1.dll复制到C:\Windows\System32,而32位版本的需要复制到C:\Windows\SysWOW64下

安装&启动mysql服务

接着在bin目录下执行安装命令:mysqld installmysqld –install mysql

再执行启动命令:net start mysql

通过命令net stop mysql 可停止服务。

登录MySQL

当 MySQL 服务已经运行时, 我们可以通过 MySQL 自带的客户端工具登录到 MySQL 数据库中, 首先打开命令提示符, 输入以下格式的命名:

mysql -h 主机名 -u 用户名 -p
  • -h:  指定客户端所要登录的 MySQL 主机名, 登录本机(localhost 或0.0.1)该参数可以省略;
  • -u:  登录的用户名;
  • -p:  告诉服务器将会使用一个密码来登录, 如果所要登录的用户名密码为空, 可以忽略此选项。

登录本机的MySQL,只需输入:mysql –u root –p 按回车后提示输入密码(若密码存在, 输入密码登录, 不存在则直接按回车登录。)

登录成功后你将会看到 Welcome to the MySQL monitor... 的提示语,然后命令提示符会一直以 mysq> 加一个闪烁的光标等待命令的输入, 输入 exit quit 退出登录。

修改密码(注意命令结尾一定要有;):在MySQL安装目录bin目录下执行命令:mysql –u root –p 会提示输入密码,

输入前面安装时的密码YQDfWiiKU0;Z 填入即可登录成功,进入mysql交互模式。

在MySQL中执行命令:ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '123456';

2. navicat连接mysql

  navicat是一个连接数据库的可视化工具,可以连接mysql和oracle做一些简单增删改查。

navicat安装

  版本多,正版收费。链接: https://pan.baidu.com/s/17L_yV9ikcOFUrbVJmiNnFw 提取码: hrah

一路傻瓜式安装,到注册页面,名和组织随便写,注册码网上找

连接mysql

  mysql是本地安装的,先启动mysql服务(任务管理器找到mysql启动,或命令 net start mysql

  • 连接名:mytest(随便取)
  • 主机名或IP地址:本机搭建就是localhost,

         其他机器上就是对应的host地址

  • 端口:3306(默认端口)
  • 用户名:root
  • 密码:123456(上面修改的密码)

 

配置好之后点击【连接测试】,连接成功后进入。

新建表

点mytest,右键-打开连接:展开连接的mysql库 --> 右键-新建数据库:新建数据库testdb

点testdb,右键-打开数据库:展开testdb数据库 --> 点testdb下的【表】,右键-新建表:user

【添加栏位】可添加多个字段

【主键】可设置某个字段为主键,如id

3. django连接mysql

常见的Mysql驱动介绍:

  • MySQL-python:即MySQLdb。是对C语言操作MySQL的简单封装。只支持Python2,不支持python3。
  • mysqlclient:是MySQL-python的另外一个分支。支持Python3并且修复了一些bug。是一个C扩展模块,编译安装可能会导致报各种错误。
  • pymysql:纯Python实现的一个驱动。因为是纯Python编写的,因此执行效率不如MySQL-python。并且也因为是纯Python编写的,因此可以和Python代码无缝衔接。
  • MySQL Connector/Python:MySQL官方的纯Python连接MySQL的驱动。因纯Python开发的效率不高。

大型项目用MySQLclient,性能比较优异。中小项目用pyMySQLPython写的契合度更高。

mysqlclient或pymysql安装:

  django连接mysql需要先安装驱动,使用pip安装:

  mysqlclient安装:pip install mysqlclient     或  pip install mysqlclient==2.0.3

  pymysql安装:  pip install pymysql

3.1 创建数据库

(ORM无法操作到数据库级别,只能操作到数据表):

1.使用navicat创建( 见  2. navicat连接mysql

2.登录mysql命令创建(cd到mysql的bin目录,或将bin目录添加到环境变量PATH里):登录mysql命令:mysql –u root -p

create database 数据库名称;  
create database 数据库名称 default charset=utf8;     -- 防止编码问题指定为 utf8
CREATE DATABASE [IF NOT EXISTS] <数据库名>	    -- 创建之前判断,只有该数据库不存在时才能执行
[[DEFAULT] CHARACTER SET <字符集名>] 		    -- 指定数据库的字符集,防止编码问题,指定为 utf8
[[DEFAULT] COLLATE <校对规则名>];		    -- 指定字符集的默认校对规则,即排序规则

 COLLATE在国内比较常用的是utf8mb4_general_ci(默认)、utf8mb4_unicode_ci、utf8mb4_bin 这三个,建议使用utf8mb4_unicode_ci。

从mysql 8.0开始,mysql默认的CHARSET改为了utf8mb4,默认的COLLATE也改为了utf8mb4_0900_ai_ci。

mysql> CREATE DATABASE IF NOT EXISTS testdb2

-> DEFAULT CHARACTER SET utf8mb4

-> DEFAULT COLLATE utf8mb4_0900_ai_ci;

3.2 django配置数据库

  setting.py文件中找到 DATABASES 配置项,django默认连接 sqllite 。

ENGINE:是指连接数据库驱动的名称,有以下几种情况:

  • db.backends.postgresql 连接PostgreSQL
  • db.backends.mysql 连接mysql
  • db.backends.sqlite3 连接sqlite
  • db.backends.oracle 连接oracle

这里连接mysql需要账户密码,也就是之前安装mysql的用户名root和设置的密码123456 ,NAME是数据库名称,连接配置如下:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'testdb',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': 'localhost',
        'PORT': '3306',
    }
}

 如果使用pymysql,需告诉 Django 使用 pymysql 模块连接 mysql 数据库:

HelloWorld/ HelloWorld /__init__.py   # 在与settings.py同级目录下的__init__.py中引入模块和进行配置

import pymysql
pymysql.install_as_MySQLdb()

3.3 创建表,同步到mysql

  创建了APP应用(需settings.py 中INSTALLED_APPS添加应用名),应用下有个models.py文件,

修改HelloWorld/helloApp/models.py文件:

from django.db import models
class Person(models.Model):
    name = models.CharField(max_length=30)
    pwd = models.CharField(max_length=50)
    mail = models.EmailField(max_length=30)
    iphone = models.BigIntegerField(max_length=24)
    update_time = models.DateTimeField(auto_now=True)
    create_time = models.DateTimeField(auto_now_add=True)

类名代表了数据库表名,且继承了models.Model ,类里面的字段代表数据表中的字段(name),数据类型则由CharField(相当于varchar)、DatetTmeField(相当于datetime),max_length参数限定长度。

先创建表结构,在数据库里面新增一些表。再cd到django的根目录(即项目所在目录,如E:\PyCharm\HelloWorld),执行以下命令进行同步:

$ python manage.py migrate                 # 创建表结构

$ python manage.py makemigrations helloApp       # 让 Django 知道我们在我们的模型有一些变更

$ python manage.py migrate helloApp                # 创建表结构

看到几行 "Creating table…" 的字样,你的数据表就创建好了。

表名组成结构为:应用名_类名(如类名为Person,数据库表名为helloapp_person)

注意:尽管我们没有在 models 给表设置主键,但是 Django 会自动添加一个 id 作为主键。

makemigrations 这一步执行后,会在当前app目录下生成一个 migrations 目录,该目录下的内容就是数据库要执行的内容。

migrate 就是执行之前生成的 migrations 文件,这一步才是操作数据库的一步,执行完成后,数据库里会新增一张表helloapp_person。

  • 新建表名是app名称_class类名称的组合,自动转换小写,即helloapp_person
  • name字段是字符串类型,最大长度30个字符串
  • age字段是int类型
  • id是默认的主键

3.4 表的字段类型和字段参数

字段类型:

  1.  models.AutoField    自增列=int(11) 如果没有的话,默认会生成一个名称为id的列,如果要显示为一个自定义自增列,必须将列设置为主键 primary_key=True
  2.  models.CharField    字符串字段,必须给max_length参数
  3.  models.TextField     字符串=longtext
  4.  models.BlooleanField          布尔型字段=tinyint(1) 不能为空,blank=True
  5.  models.NullBooleanField    允许为空的布尔类型
  6.  models.CommaSeparatedIntegerField    用逗号分割的数字=varchar。继承CharField,所以必须给max_length参数
  7.  models.DateField            日期类型date,参数:auto_now=True则每次都会更新这个时间;auto_now_add=True则是第一次创建添加,之后的更新不会改变
  8.  models.DateTimeField    日期类型datetime,同DateField的参数
  9.  models.TimeField            时间   HH:MM:[ss[.uuuuuu]]
  10.  models.EmailField           字符串类型(正则表达式邮箱)=varchar  对字符串进行正则表达式
  11.  models.URLField             字符串,地址正则表达式
  12.  models.FloatField            浮点类型=double
  13.  models.IntegerField              整型(-2147483648,2147483647)
  14.  models.BigIntegerField         长整型(-9223372036854775808, 9223372036854775807)
  15.  models.SmallIntegerField      数字(-32768,32767)   数据库中的字段有:tinyint、smallint、int、bigint
  16.  models.PositiveIntegerField              正Integer(0,32767)
  17.  models.PositiveSmallIntegerField     正smallInteger(0, 2147483647)
  18.  models.SlugField                 减号、下划线、字母、数字
  19.  models.IPAddressField                     字符串类型(ip4正则表达式)
  20.  models.GenericIPAddressField         字符串类型(ip4和ip6是可选的)。参数:protocol可以是:'both'  'ipv4'  'ipv6'  验证时会根据设置报错
  21.  models.DecimalField           十进制小数类型=decimal。必须指定整数位max_digits和小数位decimal_places
  22.  models.BinaryField              二进制
  23.  models.ImageField              图片
  24.  models.FileField                  文件

字段参数:

  1.  null=True        数据库中字段是否可以为空
  2.  blank=True     django的Admin中添加数据时是否可以允许空值
  3.  primary_key=False         主键,对AutoField设置主键后,就会代替原来的自增id列
  4.  auto_now=True             自动创建—无论添加或修改,都是当前操作时间
  5.  auto_now_add=True     自动创建—永远是创建时的时间
  6.  choice        选项框,定义一个元组变量,参数值取该变量
    GENDER_CHOICE = ((u'M',u'Male'),(u'F',u'Female'))
    gender= models.BigIntegerField(choices=GENDER_CHOICE)
  7.  max_length
  8.  default             默认值
  9.  verbose_name        Admin中字段的现实名称
  10.  db_column             数据库中的字段名称
  11.  unique=True          不允许重复
  12.  db_index=True       数据库索引
  13.  editable=True        在Admin里是否可编辑
  14.  error_messages=None     错误提示
  15.  auto_created=False          自动创建
  16.  help_text                在Admin中提示帮助信息
  17.  validators=[]
  18.  upload-to

自主设置 主键primary_key 例子:

django的models新增数据库表时,如果不设置主键,会默认新增一个id为主键,想自己设置一个字段为主键,需加个参数primary_key=True

HelloWorld/helloApp/models.py文件:

from django.db import models
#新增产品表,设置产品名称为主键,让产品名不重复
class Prouct(models.Model):
    product_name = models.CharField(max_length=20,primary_key=True)
    person_email = models.EmailField(max_length=30)

4. 连接已有的mysql数据库

跟以上一样配置连接数据库,只不过不需要在models.py文件新建表。而是直接集成已有的数据库和应用,生成models,复制到应用app的models.py中。

在项目的manage.py所在路径下使用命令:

python manage.py inspectdb > E:\PyCharm\HelloWorld\helloApp\models.py

命令结束返回无报错即成功,类名即数据库表名,会自动转大写,继承自models.Model,每个类定义有数据表内的字段名。之后的操作就没区别了。

5. 数据库操作

5.1. 新增数据

  在setting.py同一级目录新建一个testdb.py文件

HelloWorld/ HelloWorld /testdb.py

# -*- coding:utf-8 -*-
from django.http import HttpResponse
from helloApp.models import Person
# 数据库操作
def add_user(request):
    test1 = Person(name='叶凡' ,age=1000)
    test1.save()
    return HttpResponse("数据库helloApp_Person用户添加成功")

HelloWorld/ HelloWorld /urls.py 配置访问地址

from django.conf.urls import url
from django.urls import re_path,path
from . import views,testdb
from helloApp import views as view      #引入文件名同名,可重命名
urlpatterns = [
    url(r'^adduser$',testdb.add_user)
]

浏览器打开http://127.0.0.1:8000/adduser 每访问一次,数据库里面就会新增一条记录

5.2 查询数据

5.2.1 关于查询的几种方法

  • 通过objects这个模型管理器的 all() 获取所有数据行,相当于SQL中的select * from
    a = Person.objects.all()
    res = ''
    for var in a:
        res = res + var.name + " "
    response = res
  • filter() 相当于SQL中的where,可设置条件过滤结果, 结果为list
    b = Person.objects.filter(name='叶凡')
  • get() 获取单个对象
    c = Person.objects.get(name='叶凡')
  • 索引 限制返回的数据,相当于SQL中的offset 0 limit 2; 如下返回2条
    d = Person.objects.order_by('name')[0:2]
  • order_by()查询结果排序
    e = Person.objects.order_by('id')
  • 上面的方法可以连着使用
    d = Person.objects.filter(name='帝尊').order_by('id')[0:2]

5.2.2 查询数据

  还是在setting.py同一级目录的testdb.py文件

HelloWorld/ HelloWorld /testdb.py

# -*- coding:utf-8 -*-
from django.http import HttpResponse
from helloApp.models import Person
# 查询数据方法
def select_age(request):
    # 方法一:通过objects模型管理器的get()获取name='叶凡'的数据行,直接取age的值
    ag = Person.objects.get(name='叶凡').age
    # 方法二:filter相当于SQL中的where,可设置条件过滤结果,
     # 查询结果是list,取下标后,获取age字段的值
    test4 = Person.objects.filter(name='叶凡')
    ag = test4[0].age
    return HttpResponse("<p>查询结果:%s</p>" %ag)

HelloWorld/ HelloWorld /urls.py 配置访问地址

from django.conf.urls import url
from django.urls import re_path,path
from . import views,testdb
from helloApp import views as view      #引入文件名同名,可重命名
urlpatterns = [
    url(r'^adduser',testdb.add_user),
    url(r'^selectuser$',testdb.select_age)
]

浏览器打开http://127.0.0.1:8000/selectuser 每访问一次,就会按里面的方法查询一次。

5.3 更新数据

  还是在setting.py同一级目录的testdb.py文件

HelloWorld/ HelloWorld /testdb.py

# -*- coding:utf-8 -*-
from django.http import HttpResponse
from helloApp.models import Person
# 更新数据方法
def update_user(request):
    # 方法一:通过objects模型管理器的get()获取指定数据行,修改再save,相当于SQL中的update
    test2 = Person.objects.get(name='无始')
    test2.age = '120000'
    test2.save()
    # 方法二:通过objects模型管理器的filter()获取id=2的数据行,再update指定字段
    Person.objects.filter(id=2).update(age='3000')
    # 修改所有行: 通过objects模型管理器的all()获得所有数据行,相当于SQL中的SELECT * FROM, 
    Person.objects.all().update(age='100')
    return HttpResponse("<p>年龄修改成功</p>")

 HelloWorld/ HelloWorld /urls.py 配置访问地址

from django.conf.urls import url
from django.urls import re_path,path
from . import views,testdb
from helloApp import views as view      #引入文件名同名,可重命名
urlpatterns = [
    url(r'^adduser',testdb.add_user),
    url(r'^selectuser$',testdb.select_age),
    url(r'^updateuser$',testdb.update_user)
]

浏览器打开http://127.0.0.1:8000/updateuser  每访问一次,就会按里面的方法更新一次。

5.4 删除数据

  还是在setting.py同一级目录的testdb.py文件

HelloWorld/ HelloWorld /testdb.py

# -*- coding:utf-8 -*-
from django.http import HttpResponse
from helloApp.models import Person
# 更新数据方法
def delete_user(request):
    # 方法一:通过objects模型管理器的get()获取name='叶凡'的数据行,再delete该行
    test3 = Person.objects.get(name='叶凡')
    test3.delete()
    # 方法二:通过objects模型管理器的filter()获取id=1的数据行,再delete该行
    Person.objects.filter(id=1).delete()
    # 删除所有数据:通过objects模型管理器的all()获取所有数据行,再delete
    Person.objects.all().delete()
    return HttpResponse("<p>数据删除成功</p>")

HelloWorld/ HelloWorld /urls.py 配置访问地址

from django.conf.urls import url
from django.urls import re_path,path
from . import views,testdb
from helloApp import views as view      #引入文件名同名,可重命名
urlpatterns = [
    url(r'^adduser',testdb.add_user),
    url(r'^selectuser$',testdb.select_age),
    url(r'^updateuser$',testdb.update_user),
    url(r'^deleteuser$',testdb.delete_user)
]

浏览器打开http://127.0.0.1:8000/deleteuser 每访问一次,就会按里面的方法删除一次。

备注:要是表里没有要删除的数据,会报错:Person matching query does not exist.

5.5 查询表结果详解

django查询数据库的方法很多,不同的方法返回的结果也不太一样,以下13个查询方法:

  • 返回对象是对象列表的:all()   filter()    exclude()    order_by()    reverse()    values()    values_list()    distince()
  • 返回结果是对象的:get() first()  last()
  • 返回结果是布尔值的:exists()
  • 返回结果是数字的:count()

准备数据(之前的helloapp_person表)

get()    从数据看取得唯一一个匹配的结果,返回一个对象。调用者是objects管理器,返回查询到model对象(查询结果有且只有一个才执行)。

  查询结果有多个,会报错MultipleObjectsReturned,如果查询结果有0个,会报错DoesNotExist。

    r = Person.objects.get(name='叶凡').age()
    ret = Person.objects.get(name='叶凡')
    r = ret.name + str(ret.age)

first() 和 last()    返回第一条记录和返回最后一条记录,返回的是一个对象。调用者是queryset,返回model对象

    #同 fir = Person.objects.all().orderby('age')[0]
    fir = Person.objects.all().order_by("age").first()
    f = fir.age
    fir = Person.objects.all().order_by("age").first().age
    las = Person.objects.all().order_by("age").last().age

exists()          如果queryset包含数据,就返回True,否则返回False。调用者是queryset,返回布尔值

    is_exist = Person.objects.all().exists()

count()          数数,由queryset对象调用,返回int

    ret = Person.objects.all().count()

可迭代对象queryset  all()

查询整张表sql:select * from helloapp_person;

django里查询数据库不需写sql语句,而是objects模型管理器,ret=helloapp_person.objects.all() 返回的是整个表的内容,这里返回的是可迭代对象queryset,要取出数据,需要用for循环读取。

HelloWorld/ HelloWorld /testdb.py  setting.py同级

from django.http import HttpResponse
from helloApp.models import Person
def select_all(request):
    ids,names,ages = '',"",""
    ret = Person.objects.all()
    for i in ret:
        ids += " " + str(i.id)
        names += " " + i.name
        ages += " " + str(i.age)
    return HttpResponse("<p>查询id结果:%s</p><p>查询name结果:%s</p><p>查询age结果:%s</p>"%(ids,names,ages))

HelloWorld/ HelloWorld /urls.py 配置访问地址

    url(r'^selectall$',testdb.select_all)

浏览器打开http://127.0.0.1:8000/selectall,访问结果如图一,结果按列汇总展示。当然,也可以读取记录,按每行展示,如图2

for i in ret:
    names += "<p>id:" + str(i.id) + ",name:" + i.name + ",age:" + str(i.age) + "</p>"
return HttpResponse(names)

图一   

筛选条件 filter()

类似SQL中的where语句:select * from helloapp_person where id=7 and name='叶凡';

filter()查询结果也是可迭代对象,如果只有一个,可以通过下标取值。找不到的时候给个默认值null。

HelloWorld/ HelloWorld /testdb.py  setting.py同级

# -*- coding:utf-8 -*-
from django.http import HttpResponse
from helloApp.models import Person
def filter_user(request):
    r = ""
    ret = Person.objects.filter(id=7,name='叶凡')
    try:
        r = ret[0].age
    except:
        r = "null"
    return HttpResponse("<p>查询结果:%s</p>" %r)

HelloWorld/ HelloWorld /urls.py 配置访问地址

    url(r'^filteruser$',testdb.filter_user)

浏览器打开http://127.0.0.1:8000/filteruser ,找得到展示结果,找不到展示null

   

可迭代的字典序列 values()

all()filter()返回的都是可迭代的queryset序列,平常我们习惯获取字典的对象,可用values()方法获取。

Person.objects.all().values(“id”,”name”) 类似于SQL语句:select id,name from helloapp_person

HelloWorld/ HelloWorld /testdb.py  setting.py同级

from django.http import HttpResponse
from helloApp.models import Person
def values_user(request):
    r = ''
    ret = Person.objects.all().values("id","name","age")
    for i in ret:
        r += str(i)
    return HttpResponse("<p>查询结果:%s</p>" %r)

HelloWorld/ HelloWorld /urls.py 配置访问地址

    url(r'^valuesuser$',testdb.values_user)

浏览器打开http://127.0.0.1:8000/valuesuser 展示结果:

其他可迭代对象:

exclude()       它包含了与所给筛选条件不匹配的对象。由objects管理器调用,返回queryset。

    #查找用户名不是“叶凡”的数据:
    ret = Person.objects.exclude(name="叶凡")

order_by()        对查询结果排序。由queryset对象调用,返回值是queryset。默认是降序,在前面加 – 是代表降序。

# 查询所有数据,按age字段排序,默认升序
    ret = Person.objects.all().order_by("age")
    # 查询name='曹雨生'的数据,按age字段降序排序
    ret = Person.objects.filter(name='曹雨生').order_by("-age")

reverse()           对查询结果反向排序。由queryset对象调用,返回值是queryset

    # 查询所有数据,按age排序,默认升序,再反向排序,功能与-age一样
    ret = Person.objects.all().order_by('age').reverse()
    #查询name='曹雨生'的数据,再反向排序 
    ret = Person.objects.filter(name='曹雨生').reverse()

values_list()     和values()差不多,返回是元组。由queryset对象调用,返回值是queryset

    ret = Person.objects.all().values_list("id","name")

distinct()       从返回结果中剔除重复记录。由queryset对象调用,返回值是queryset。 和SQL中的distinct去重一样。

    ret = Person.objects.all().values("id","name","age").distinct()

5.6 查询结果转json(serializers)

django查询数据返回的是可迭代的queryset序列,如果不习惯这种数据,可以用serializers方法转成json数据,更直观。

返回json数据,需要用到JsonResponse。django查询数据库返回json有3种方法:

  • serializers转json
  • model_to_dict转字典
  • values()转list (最简单,推荐!)

JsonResponse是HttpResponse的一个子类,用来帮助用户创建JSON编码的响应。源码:

class JsonResponse(data,encoder=DjangoJSONEncoder,safe=True,json_dumps_params=None,**kwargs):
  • data:      应该传递一个标准的python字典给它,它将其转换成json格式数据。
  • encoder:默认为django.core.serializers.json.DjangoJSONEncoder,用于序列化data。
  • safe:       默认为True。如果为True但data不是dict对象,将抛出一个Typeerror;如果为False,可以传递任何对象进行序列化。
  • json_dumps_params:可以传递一个python标准的json库中,json.dump()方法处理后的对象给它,用于生成一个响应。

另外:它默认Content-Type头部设置为application/json。以下为JsonResponse类源码:

 

serializers 转json

  django里有个serializers方法可以,直接把查询的结果转换成json数据。

HelloWorld/ HelloWorld /testdb.py  setting.py同级

from django.http import HttpResponse,JsonResponse
from helloApp.models import Person
from django.core import serializers
import json
def get_json(request):
    data = {}
    allPer = Person.objects.all()
    data['result'] = json.loads(serializers.serialize("json",allPer))
    return JsonResponse(data)

然后在urls.py配置访问地址,如下:

    url(r'^get_json$',testdb.get_json)

 访问地址http://127.0.0.1:8000/get_json  展示如下:

{"result": [{"model": "helloApp.person", "pk": 6, "fields": {"name": "\u66f9\u96e8\u751f", "age": 5000}}, {"model": "helloApp.person", "pk": 7, "fields": {"name": "\u53f6\u51e1", "age": 2000}}, {"model": "helloApp.person", "pk": 8, "fields": {"name": "\u66f9\u96e8\u751f", "age": 2000}}, {"model": "helloApp.person", "pk": 9, "fields": {"name": "\u5e1d\u5c0a", "age": 120000}}, {"model": "helloApp.person", "pk": 10, "fields": {"name": "\u5e1d\u5c0a", "age": 120000}}]}

 serializers方法虽然可以直接转换成json数据,但是上面返回的结果有一些多余的字段model和pk,不是我们想要的。

 model_to_dict 转字典

  用model_to_dict方法把查询的queryset序列结果转成字典序列。

HelloWorld/ HelloWorld /testdb.py  setting.py同级

from django.http import HttpResponse,JsonResponse
from helloApp.models import Person 
from django.forms.models import model_to_dict
def to_dict(request):
    ret = Person.objects.all()
    json_list = []
    for i in ret:
        json_dict = model_to_dict(i)
        json_list.append(json_dict)
    return JsonResponse(json_list,safe=False)

然后在urls.py配置访问地址,如下:

    url(r'^to_dict$',testdb.to_dict)

访问地址http://127.0.0.1:8000/to_dict 展示如下:

[{"id": 6, "name": "\u66f9\u96e8\u751f", "age": 5000}, {"id": 7, "name": "\u53f6\u51e1", "age": 2000}, {"id": 8, "name": "\u66f9\u96e8\u751f", "age": 2000}, {"id": 9, "name": "\u5e1d\u5c0a", "age": 120000}, {"id": 10, "name": "\u5e1d\u5c0a", "age": 120000}]

values() 转list

  第三种:不需要导入方法,先用values()方法获取一个可迭代的dict序列,再用list函数转成list对象。

HelloWorld/ HelloWorld /testdb.py  setting.py同级

from django.http import HttpResponse,JsonResponse
from helloApp.models import Person
def json_data(request):
    data = {}
    ret = Person.objects.all().values()
    data["data"] = list(ret)
    return JsonResponse(data,safe=False)

然后在urls.py配置访问地址,如下:

    url(r'^json_data$',testdb.json_data),

访问地址http://127.0.0.1:8000/json_data 展示如下:

{"data": [{"id": 6, "name": "\u66f9\u96e8\u751f", "age": 5000}, {"id": 7, "name": "\u53f6\u51e1", "age": 2000}, {"id": 8, "name": "\u66f9\u96e8\u751f", "age": 2000}, {"id": 9, "name": "\u5e1d\u5c0a", "age": 120000}, {"id": 10, "name": "\u5e1d\u5c0a", "age": 120000}]}

5.7 JsonResponse返回中文

  django查询到的结果,用JsonResponse返回在页面上显示类似于"\u66f9\u96e8\u751f",这是unicode编码,python3默认返回的编码。解决:加上参数 json_dumps_params={'ensure_ascii':False}

HelloWorld/ HelloWorld /testdb.py  setting.py同级

from django.http import HttpResponse,JsonResponse
from helloApp.models import Person
def json_data(request):
    data = {}
    ret = Person.objects.all().values()
    data["data"] = list(ret)
    return JsonResponse(data,safe=False,
                        json_dumps_params={'ensure_ascii':False})

这样再访问地址http://127.0.0.1:8000/json_data 展示如下:

{"data": [{"id": 6, "name": "曹雨生", "age": 5000}, {"id": 7, "name": "叶凡", "age": 2000}, {"id": 8, "name": "曹雨生", "age": 2000}, {"id": 9, "name": "帝尊", "age": 120000}, {"id": 10, "name": "帝尊", "age": 120000}]}

5.8 数据库查询延伸

  django对数据库进行条件查询格式:字段名+两个下划线+查询方法。这些查询方法get和filter都可以使用,但get每次返回的值是惟一的否则报错。

  • all 返回全部数据,为queryset对象          Person.objects.all()
  • lt 返回小于目标值的queryset; lte 返回小于等于目标值的queryset。           Person.objects.filter(id__lt=5)                  Person.objects.filter(id__lte=5)
  • gt 返回大于目标值的queryset; gte 返回大于等于目标值的queryset。        Person.objects.filter(id__gt=4)                 Person.objects.filter(id__gte=4)
  • 包含:contains区分大小写; icontains不区分大小写。              Person.objects.filter(name__contains=’ab’)    Person.objects.filter(name__icontains=’ab’)
  • 精确匹配:exact区分大小写;iexact不区分大小写。                  Person.objects.filter(name__exact=’Dog’)      Person.objects.filter(name__iexact=’Dog’)
  • 起始匹配:startswith区分大小写;istartswith不区分大小写。   Person.objects.filter(name__startswith=’At’)           Person.objects.filter(name__istartswith=’At’)
  • 末尾匹配:endswith区分大小写;iendswith不区分大小写。      Person.objects.filter(name__endswith=’by’)   Person.objects.filter(name__iendswith=’by’)
  •                  startswith、endswith混合:Person.objects.filter(name__startswith=’A’,name__endswith=’y’)
  • in:同时查找多个符合条件的数据,相当于批量的精确查找。      Person.objects.filter(id__in=[101,102,103])
  • range:取范围内的值(两边都是闭合,两侧包含)只要是包含这个范围内的值否返回。              Person.objects.filter(id__range=[220,290])
  • isnull:返回是空值的数据,True为空,False非空。          Person.objects.filter(id__isnull=True)   # 返回[]          Person.objects.filter(id__isnull=False)   # 返回非空数据
  • Q:多条件联合查询,使用前需导入Q模块 from django.db.models import Q
q1 = Q(create_time__year__in=[2018,2019])
q2 = Q(create_time__month=2)
blogs = BologModel.objects.filter(q1,q2)

使用Q()传入相应条件,然后把Q传入查询的函数中,可以传多个Q然后进行查询。q1,q2中间是逗号时取交集,中间是 | 时取并集。

 

posted on   云初见  阅读(261)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!

点击右上角即可分享
微信分享提示