Django(十)模型:django模型类对数据库的:增/删/改/查、自关联、管理器、元选项(指定表名)
一、插入、更新和删除
- 调用一个模型类对象的save方法的时候就可以实现对模型类对应数据表的插入和更新。
- 调用一个模型类对象的delete方法的时候就可以实现对模型类对应数据表数据的删除。
二、自关联
自关联是一种特殊的一对多的关系。
【案例】:显示广州市的上级地区和下级地区。
- 地区表:
id, atitle, aParent_id;
- mysql终端中批量执行sql语句:
source areas.sql;
第1步,添加地区模型类 app1/models.py
【关系属性】,代表当前地区的父级地区
class AreaInfo(models.Model):
'''地区模型类'''
# 地区名称
atitle = models.CharField(max_length=20)
# 【关系属性】,代表当前地区的父级地区
aParent = models.ForeignKey('self', null=True, blank=True)
# class Meta:
# db_table = 'areas'
第2步,创建迁移,应用迁移创建对应表
D:\a\django-app\project1>py manage.py makemigrations
Migrations for 'app1':
app1\migrations\0004_auto_20200107_1148.py
- Alter field btitle on bookinfo
- Create model AreaInfo
D:\a\django-app\project1>py manage.py migrate
Operations to perform:
Apply all migrations: admin, app1, auth, contenttypes, sessions
Running migrations:
Applying app1.0004_auto_20200107_1148... OK
查看表mysql命令窗:
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sakila |
| spiders |
| sys |
| test888 |
| world |
+--------------------+
8 rows in set (0.07 sec)
mysql> use test888
Database changed
mysql> show tables;
+----------------------------+
| Tables_in_test888 |
+----------------------------+
| app1_areainfo |
| app1_bookinfo |
| app1_heroinfo |
| auth_group |
| auth_group_permissions |
| auth_permission |
| auth_user |
| auth_user_groups |
| auth_user_user_permissions |
| django_admin_log |
| django_content_type |
| django_migrations |
| django_session |
+----------------------------+
13 rows in set (0.00 sec)
mysql> desc app1_areainfo;
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| atitle | varchar(20) | NO | | NULL | |
| aParent_id | int(11) | YES | MUL | NULL | |
+------------+-------------+------+-----+---------+----------------+
3 rows in set (0.11 sec)
第3步,把地区数据表导入刚建的表
- 表位置:q网盘\源码【area.sql】
- 把例如:
INSERT INTO app1_areainfo VALUES ('110000', '北京市', NULL);
中的【app1_】改成 【对应的表名_】
进入sql命令窗:即可导入(路径不要有中文空格等)
use test888; #使用对应的表
source E:/pro_sql/test.sql; #导入数据
#执行效果: Query OK, 1 row affected (0.12 sec)
查询刚导入的表效果
select * from app1_areainfo;
| 659000 | 省直辖行政单位 | 650000 |
| 659001 | 石河子市 | 659000 |
| 659002 | 阿拉尔市 | 659000 |
| 659003 | 图木舒克市 | 659000 |
| 659004 | 五家渠市 | 659000 |
| 990000 | 新疆建设兵团 | NULL |
| 990100 | 第一师 | 990000 |
| 990200 | 第二师 | 990000 |
| 990300 | 第三师 | 990000 |
| 990400 | 第四师 | 990000 |
| 990500 | 第五师 | 990000 |
| 990600 | 第六师 | 990000 |
| 990700 | 第七师 | 990000 |
| 990800 | 第八师 | 990000 |
| 990900 | 第九师 | 990000 |
| 991000 | 第十师 | 990000 |
| 991100 | 建工师 | 990000 |
| 991200 | 第十二师 | 990000 |
| 991300 | 第十三师 | 990000 |
| 991400 | 第十四师 | 990000 |
+--------+-----------------------------------------------+------------+
第4步,app1/views.py 编辑对应函数,读取地区信息
from booktest.models import BookInfo,AreaInfo
def areas(request):
'''获取广州市的上级地区和下级地区'''
# 1.获取广州市的信息
area = AreaInfo.objects.get(atitle='广州市')
# 2.查询广州市的上级地区
parent = area.aParent
# 3.查询广州市的下级地址
children = area.areainfo_set.all()
# 使用模板
return render(request, 'app1/areas.html', {'area':area,'parent':parent, 'children':children})
第5步,配置app1/urls.py
展示对应省市区信息
from django.urls import path,re_path
from . import views
urlpatterns=[
path('app1/',views.index),
path('books/',views.books),
# 书详情页,通过url接收参数2种写法以下两种都可:
# path(r"detail/<int:bookId>",views.detail), #参数用尖括号包起来<>
re_path(r"^detail/(\d+)",views.detail), #参数必须要带括号
path('addInfo/',views.addInfo), #添加三国书
path(r'delete/<int:bid>',views.deleteInfo), #删除对应图书
path(r'area/',views.areas), #展示对应省市区信息
]
第6步,添加展示模板templates/app1/areas.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>自关联案例</title>
</head>
<body>
<h1>当前地区</h1>
{{ area.atitle }}<br/>
<h1>父级地区</h1>
{{ parent.atitle }}<br/>
<h1>下级地址</h1>
<ul>
{% for child in children %}
<li>{{ child.atitle }}</li>
{% endfor %}
</ul>
</body>
</html>
效果:
当前地区:
广州市
父级地区:
广东省
下级地址:
荔湾区
越秀区
海珠区
天河区
白云区
黄埔区
番禺区
花都区
南沙区
萝岗区
增城市
从化市
三、管理器(Manager)
问:BookInfo.objects.all()->objects是一个什么东西呢?
- 答:objects是Django帮我自动生成的管理器对象,通过这个管理器可以实现对数据的查询。
- objects是models.Manger类的一个对象。自定义管理器之后Django不再帮我们生成默认的objects管理器。
py manage.py shell
>>> from app1.models import BookInfo,HeroInfo
>>> type(BookInfo.objects)
<class 'django.db.models.manager.Manager'>
1 自定义模型管理器类
1)自定义一个管理器类,这个类继承models.Manger类。
2)再在具体的模型类里定义一个自定义管理器类的对象。
例1:在app1/models.py下定义一个管理器类
自定一个Manager类对象,管理器对象 book = models.Manager()
# 一类
# booktest2_bookinfo
class BookInfo(models.Model):
'''图书模型类'''
# 图书名称
btitle = models.CharField(max_length=20, db_column='title')
# 图书名字唯一
# btitle = models.CharField(max_length=20, unique=True, db_index=True)
# 价格,最大位数为10,小数为2
# bprice = models.DecimalField(max_digits=10, decimal_places=2)
# 出版日期
bpub_date = models.DateField()
# bpub_date = models.DateField(auto_now_add=True) # 创建时间
# bpub_date = models.DateField(auto_now=True) # 更新时间
# 阅读量
bread = models.IntegerField(default=0)
# 评论量
bcomment = models.IntegerField(default=0)
# 删除标记
isDelete = models.BooleanField(default=False)
book = models.Manager() # 自定一个Manager类对象,管理器对象
#objects = BookInfoManager() # 自定义一个BookInfoManager类的对象
自定义管理器类之后再查询数据就变成如下
由:BookInfo.objects.all()
变:BookInfo.book.all()
>>> quit()
D:\a\django-app\project1>py manage.py shell
Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 14:57:15) [MSC v.1915 64 bit (AMD6
4)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from app1.models import BookInfo
>>> BookInfo.book.all() #【变】
<QuerySet [<BookInfo: 天龙八部>, <BookInfo: 三国演义>, <BookInfo: 红楼梦>, <Book
Info: 水浒传>]>
>>> BookInfo.objects.all() #【原】
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: type object 'BookInfo' has no attribute 'objects'
2 自定义管理器类的应用场景
1)改变查询的结果集。
- 比如调用BookInfo.books.all()返回的是没有删除的图书的数据。
例2:自定义Manager类
【1】自定义一个BookInfoManager类,实现查寻数据只返回isDelete=False(删除标记(伪删除))的书
【2】使用自定义的manager类
from django.db import models
# 设计和表对应的类,模型类
#【1】自定义一个BookInfoManager类
class BookInfoManager(models.Manager): #继承自models.Manager
'''图书模型管理器类'''
# 1.改变原有查询的结果集
def all(self):
# 1.调用父类的all方法,获取所有数据
books = super().all() # QuerySet
# 2.对books中的数据进行过滤
books = books.filter(isDelete=False)
# 返回books
return books
# 一类
# 图书类
class BookInfo(models.Model):
'''图书模型类'''
# 图书名称,CharField说明是一个字符串,max_length指定字符串的最大长度
btitle = models.CharField(max_length=20,unique=True) #该字段不能重复,db_column='title'
# 出版日期,DateField说明是一个日期类型
bpub_date = models.DateField()
# 阅读量
bread = models.IntegerField(default=0)
# 评论量
bcomment = models.IntegerField(default=0)
# 删除标记
isDelete = models.BooleanField(default=False)
#book = models.Manager() # 自定一个Manager类对象,管理器对象
objects = BookInfoManager() # 自定义一个BookInfoManager类的对象 【2】使用自定义的manager类
2)添加额外的方法。
- 管理器类中定义一个方法帮我们操作模型类对应的数据表。
- 使用self.model()就可以创建一个跟自定义管理器对应的模型类对象。
例3,把插入图书各个语句封装成一个BookInfo类的函数:
app1/models.py
1.【封装插入图书方法为BookInfo的函数】
2.使用时只需要 BookInfo.create_book(书标题,日期)
即可使用详情:
'''使用下一步封装的函数'''
from app1.models import BookInfo
BookInfo.create_book('test','1991-1-1')
book.btitle #(返回刚插入的标题)
'''定义类的封装插入图书函数'''
from django.db import models
# 一类
# booktest2_bookinfo
class BookInfo(models.Model):
'''图书模型类'''
# 图书名称
btitle = models.CharField(max_length=20, db_column='title')
# 图书名字唯一
# btitle = models.CharField(max_length=20, unique=True, db_index=True)
# 价格,最大位数为10,小数为2
# bprice = models.DecimalField(max_digits=10, decimal_places=2)
# 出版日期
bpub_date = models.DateField()
# bpub_date = models.DateField(auto_now_add=True) # 创建时间
# bpub_date = models.DateField(auto_now=True) # 更新时间
# 阅读量
bread = models.IntegerField(default=0)
# 评论量
bcomment = models.IntegerField(default=0)
# 删除标记
isDelete = models.BooleanField(default=False)
# book = models.Manager() # 自定一个Manager类对象,管理器对象
#objects = BookInfoManager() # 自定义一个BookInfoManager类的对象
@classmethod #【封装插入图书方法为BookInfo的函数】
def create_book(cls, btitle, bpub_date):#cls即类名
'''添加一本图书'''
# 创建一个cls类的对象
obj = cls()
obj.btitle = btitle
obj.bpub_date = bpub_date
# 添加进数据库
obj.save()
# 返回obj
return obj
例4,一般把增、删、改、查自定义函数写到Manger自定义类里
2.封装方法,操作模型类对应的数据表(增删改查)
class BookInfoManager(models.Manager):
'''图书模型管理器类'''
# 1.改变原有查询的结果集
def all(self):
# 1.调用父类的all方法,获取所有数据
books = super().all() # QuerySet
# 2.对books中的数据进行过滤
books = books.filter(isDelete=False)
# 返回books
return books
# 2.封装方法,操作模型类对应的数据表(增删改查)
def create_book(self, btitle, bpub_date):
'''添加一本图书'''
# 1.创建一个图书对象
# 获取self所在的模型类
model_class = self.model
book = model_class()
# book = BookInfo()
book.btitle = btitle
book.bpub_date = bpub_date
# 2.添加进数据库
book.save()
# 3.返回book
return book
调用:
from app1.models import BookInfo
#必须通过关键字传参
BookInfo.objects.create(btitle='test3',bpub_ date='1990-10-10' )
<BookInfo:BookInfo object>
上一步写的自定义函数先注释掉:
# @classmethod
# def create_book(cls, btitle, bpub_date):
# '''添加一本图书'''
# # 创建一个cls类的对象
# obj = cls()
# obj.btitle = btitle
# obj.bpub_date = bpub_date
# # 添加进数据库
# obj.save()
# # 返回obj
# return obj
小结:
【模型管理器对象】
- 改变原有查询的结果集。
- 封装方法,用户操作管理器对象所在模型类对应的数据表。
3. 模型管理器类、模型类间关系
四、元选项(指定表名)
Django默认生成的表名: 应用名小写_模型类名小写。
元选项:
需要在模型类中定义一个元类Meta,在里面定义一个类属性db_table就可以指定表名。
应用场景:应用名(app1)和表名不一致情形
【问题】比如对应用名不满意想换个别的名字,此时表名已经生成了,这时应该怎么办呢?
- 【解决】就可通过元选项解决。
实战app1/models.py
【1】指定表的名字
class AreaInfo(models.Model):
'''地区模型类'''
# 地区名称
atitle = models.CharField(max_length=20)
# 关系属性,代表当前地区的父级地区
aParent = models.ForeignKey('self', null=True, blank=True)
class Meta: #【1】指定表的名字
db_table = 'areas'