小程序开发笔记(六)Django ORM

2022/3/19 pythonDjango

# 一、单表实例

  • 创建App:django-admin.py startproject Test_App

  • 在settings.py中找到INSTALLED_APPS这一项:

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'Test_App',               # 添加此项
)
  • 使用pymysql模块连接mysql数据库:
# 在与 settings.py 同级目录下的 __init__.py 中引入模块和进行配置 
import pymysql
pymysql.install_as_MySQLdb()

# 1.1创建模型

  • 在刚刚创建的App中的models.py中添加类:
class Book(models.Model): 
    id = models.AutoField(primary_key=True) # id 会自动创建,可以手动写入
    title = models.CharField(max_length=32) # 书籍名称
    price = models.DecimalField(max_digits=5, decimal_places=2) # 书籍价格 
    publish = models.CharField(max_length=32) # 出版社名称 
    pub_date = models.DateField() # 出版时间
  • 执行命令:
$ python manage.py makemigrations
$ python manage.py migrate 

模型创建完成

# 1.2数据库操作

# 1.2.1添加

  • 方法一:模型类实例化对象

新建py文件添加

# 添加
def add_book(request):
    # 创建对象
    book = Book(
        title='TestBook',
        price=12,
        publish='TestPublish',
        pub_date="2008-8-8"
    )
    # 保存对象至数据库
    book.save()
    # 反馈
    return HttpResponse("<p>OK</p>")

写入路由器中,对Url进行访问后在数据库内可以查询到已经增加

202203181815547
  • 方法二:通过 ORM 提供的 objects 提供的方法 create 来实现**(推荐)**
# 添加(通过create)
def add_book_02(request):
    # 存储对象
    Book.objects.create(
        title='TestBook02',
        price=21,
        publish='TestPublish02',
        pub_date="2022-8-8"
    )
    # 反馈
    return HttpResponse("<p>OK</p>")

写入路由器中,对Url进行访问后在数据库内可以查询到已经增加

# 1.2.2查找

  • 查询所有

使用**objects.all()**方法来查询所有内容

返回的是QuerySet类型数据,类似于 list,里面放的是一个个模型类的对象,可用索引下标取出模型类的对象

# 查询所有
def find_all(request):
    books = Book.objects.all()
    print(books)
    return HttpResponse("<p>OK</p>")

可以发现返回的数据类型如下:

202203181842099
  • 条件查询

**filter()**方法用于查询符合条件的数据

pk=3 的意思是主键 primary key=3,相当于 id=3。

因为 id 在 pycharm 里有特殊含义,是看内存地址的内置函数 id(),因此用 pk

同样返回的是QuerySet类型数据

# 条件查询
def find_id(request):
    book = Book.objects.filter(pk=1)
    print(book)
    return HttpResponse("<p>OK</p>")

通过filter查询还可以通过内置的一些方法进行范围查询

注意:filter 中运算符号只能使用等于号 = ,不能使用大于号 > ,小于号 < ,等等其他符号

__in用于读取区间,= 号后面为列表:books = models.Book.objects.filter(price__in=[200,300])

__gt大于号 ,= 号后面为数字:books = models.Book.objects.filter(price__gt=200)

__gte大于等于,= 号后面为数字:books = models.Book.objects.filter(price__gte=200)

__lt小于,=号后面为数字:books=models.Book.objects.filter(price__lt=300)

__lte小于等于,= 号后面为数字:books=models.Book.objects.filter(price__lte=300)

__range在 ... 之间,左闭右闭区间,= 号后面为两个元素的列表:books=models.Book.objects.filter(price__range=[200,300])

__contains包含,= 号后面为字符串:books=models.Book.objects.filter(title__contains="x")

__icontains不区分大小写的包含,= 号后面为字符串:books=models.Book.objects.filter(title__icontains="python")不区分大小写

__year是 DateField 数据类型的年份,= 号后面为数字:books=models.Book.objects.filter(pub_date__year=2008)

__month是DateField 数据类型的月份,= 号后面为数字

__day是DateField 数据类型的天数,= 号后面为数字

  • 非条件查询

**exclude()**方法用于查询不符合条件的数据

返回的是QuerySet类型数据,类似于list,里面放的是不满足条件的模型类的对象,可用索引下标取出模型类的对象

# 非条件查询
def find_exclude(request):
    books = Book.objects.exclude(pk=5)
    print(books)
    books = Book.objects.exclude(publish='TestPubish', price=300)
    print(books)
    return HttpResponse("<p>ok</p>")
  • 单一查询

**get()**方法用于查询符合条件的返回模型类的对象符合条件的对象只能为一个,如果符合筛选条件的对象超过了一个或者没有一个都会抛出错误

# 单一查询
def find_one(request):
    book = Book.objects.get(pk=1)
    print(book)
    return HttpResponse("<p>ok</p>")
  • 排序

order_by() 方法用于对查询结果进行排序。

返回的是 QuerySet类型数据,类似于list,里面放的是排序后的模型类的对象,可用索引下标取出模型类的对象。

# 排序
def oder(request):
    # 升序查询
    Book.objects.order_by("price")
    # 降序查询
    Book.objects.order_by("-price")
    return HttpResponse("<p>ok</p>")
  • 反转

reverse() 方法用于对查询结果进行反转

返回的是 QuerySet类型数据,类似于list,里面放的是反转后的模型类的对象,可用索引下标取出模型类的对象

  • 词条数目查询

**count()**方法用于查询数据的数量返回的数据是整数

def add_book(request):
    # 查询所有数据的数量 
    books = models.Book.objects.count()
    # 查询符合条件数据的数量
    books = models.Book.objects.filter(price=200).count()
    return HttpResponse("<p>ok</p>")

# 1.2.3删除

  • 方法一:使用模型类的对象.delete()

books = models.Book.objects.filter(pk=8).first().delete()

  • 方式二:使用QuerySet类型数据.delete()(推荐)

books=models.Book.objects.filter(pk__in=[1,2]).delete()

# 1.2.4修改

  • 方法一:save()方法

模型类的对象.属性 = 更改的属性值

模型类的对象.save()

books = models.Book.objects.filter(pk=7).first() 
books.price = 400 
books.save()
  • 方法二:QuerySet类型数据.update(字段名=更改的数据)(推荐)
def add_book(request):
    books = models.Book.objects.filter(pk__in=[7,8]).update(price=888)
    return HttpResponse(books)

# 二、多表实例

创建App名为Multi_App,在其中的models.py文件中进行修改

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    pub_date = models.DateField()
    publish = models.ForeignKey("Publish", on_delete=models.CASCADE)
    authors = models.ManyToManyField("Author")


class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=64)
    email = models.EmailField()


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.SmallIntegerField()
    au_detail = models.OneToOneField("AuthorDetail", on_delete=models.CASCADE)


class AuthorDetail(models.Model):
    gender_choices = (
        (0, "女"),
        (1, "男"),
        (2, "保密"),
    )
    gender = models.SmallIntegerField(choices=gender_choices)
    tel = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)
    birthday = models.DateField()

示意图如下所示:

202203182001198

说明:

  • EmailField 数据类型是邮箱格式,底层继承 CharField,进行了封装,相当于MySQL中的varchar
  • 一般不需要设置联级更新
  • 外键在一对多的多中设置:models.ForeignKey("关联类名", on_delete=models.CASCADE)
  • OneToOneField = ForeignKey(...,unique=True)设置一对一
  • 若有模型类存在外键,创建数据时,要先创建外键关联的模型类的数据,不然创建包含外键的模型类的数据时,外键的关联模型类的数据会找不到

# 2.1添加

# 2.1.1一对多

  • 方法一:传对象的形式,返回值的数据类型是对象,书籍对象

先创建publish对象,然后直接将该对象传给新建对象

def add_book(request):
    # 获取出版社
    publish = models.Publish.objects.filter(pk=1).first()
    # 将publish信息传给新建的book
    book = models.Book.objects.create(
        title="菜鸟教程",
        price=200,
        pub_date="2010-10-10",
        publish=publish
    )
    return HttpResponse("<p>ok</p>")
  • 方法二:传id的方式
def add_book_02(request):
    # 获取出版社
    publish = models.Publish.objects.filter(pk=1).first()
    #  获取出版社对象的id
    pk = publish.pk
    #  给书籍的关联出版社字段 publish_id 传出版社对象的id
    book = models.Book.objects.create(
        title="冲灵剑法",
        price=100,
        pub_date="2004-04-04",
        publish_id=pk
    )
    return HttpResponse(book)

# 2.1.2多对多

  • 方式一:传对象形式,无返回值

分别获取两个对象后,给书籍对象的 authors 属性用 add 方法传作者对象

def add_book_03(request):
    #  获取作者对象
    chong = models.Author.objects.filter(name="甲").first()
    ying = models.Author.objects.filter(name="乙").first()
    #  获取书籍对象
    book = models.Book.objects.filter(title="test").first()
    #  给书籍对象的 authors 属性用 add 方法传作者对象
    book.authors.add(chong, ying)
    return HttpResponse(book)
  • 方式二:传id
def add_book_04(request):
    #  获取作者对象
    chong = models.Author.objects.filter(name="甲").first()
    #  获取作者对象的id
    pk = chong.pk
    #  获取书籍对象
    book = models.Book.objects.filter(title="冲灵剑法").first()
    #  给书籍对象的 authors 属性用 add 方法传作者对象的id
    book.authors.add(pk)

# 2.1.3关联管理器

def object_management(request):
    # 方式一:传对象
    book_obj = models.Book.objects.get(id=10)
    author_list = models.Author.objects.filter(id__gt=2)
    book_obj.authors.add(*author_list)  # 将 id 大于2的作者对象添加到这本书的作者集合中
    # 方式二:传对象 id
    book_obj.authors.add(*[1, 3])  # 将 id=1 和 id=3 的作者对象添加到这本书的作者集合中
    return HttpResponse("ok")

反向添加

ying = models.Author.objects.filter(name="甲").first()
book = models.Book.objects.filter(title="test").first()
ying.book_set.add(book)
return HttpResponse("ok")

# 2.2查询

# 2.2.1一对多

正向查询:查询主键为 1 的书籍的出版社所在的城市

def find_01(request):
    book = models.Book.objects.filter(pk=1).first()
    res = book.publish.city
    return HttpResponse("<p>ok</p>")

反向查询:查询一个出版社出版的所有书

pub = models.Publish.objects.filter(name="武大出版社").first()
res = pub.book_set.all()
for i in res:
    print(i.title)
return HttpResponse("ok")

# 2.2.2一对一

查询作者对应的作者表详情

author = models.Author.objects.filter(name="甲").first()
res = author.au_detail.tel
print(res, type(res))
return HttpResponse("ok")

# 2.2.3多对多

通过all的方式进行全部查询

def find_03(request):
    book = models.Book.objects.filter(title="test").first()
    res = book.authors.all()
    for i in res:
        print(i.name, i.au_detail.tel)
    return HttpResponse("ok")