Django ORM模型操作
Django连接MySQL
使用Django来操作MySQL,需要安装一个驱动程序。驱动程序有多重选择。比如pymysql以及mysqlclient,这里我们使用mysqlclient,mysqlclient安装非常简单
pip install mysqlclient
Django配置连接数据库,配置项目的 settings.py
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'devops', 'USER': 'root', 'PASSWORD': 'root', 'HOST': '127.0.0.1', 'PORT': 3306, 'OPTIONS': { 'init_command': 'SET default_storage_engine=INNODB;', }, } }
创建ORM模型
ORM模型一般都是放在app的models.py文件中,每个app都可以拥有自己的模型。并且为这个模型要映射到数据库中,那么这个app必须放在settings.py的INSTALL_APP中。 创建在app01中创建模型如下
from django.db import models class Book(models.Model): name = 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") create_time = models.DateTimeField(auto_now_add=True) update_time = models.DateTimeField(auto_now=True) class Publish(models.Model): name = models.CharField(max_length=32) city = models.CharField(max_length=64) email = models.EmailField() create_time = models.DateTimeField(auto_now_add=True) update_time = models.DateTimeField(auto_now=True) class Author(models.Model): gender_choices = ( (0, "女"), (1, "男"), (2, "保密") ) name = models.CharField(max_length=32) gender = models.SmallIntegerField(choices=gender_choices) addr = models.CharField(max_length=64) age = models.SmallIntegerField() birthday = models.DateField() create_time = models.DateTimeField(auto_now_add=True) update_time = models.DateTimeField(auto_now=True)
在Django中,如果一个模型没有定义主键,那么会自动生成一个自动增长的int类型的主键,并且这个主键的名字叫做id
映射模型到数据库中
- 在命令行中终端执行 python manage.py makemigrations <app_name>来生成迁移脚本,不指定app,则是所有的app
- 同样在命令行中,执行命令python manage.py migrate来将迁移脚本映射到数据库中
python manage.py makemigrations app01
python manage.py migrate
模型常用字段
CharField
在数据库层面是varchar类型,在使用的时候必须要指定最大的长度参数(max_length)
nick_name = models.CharField(max_length=50, verbose_name='昵称', default='')
IntegerField
整形。值的区间是-2147483648——2147483647
click_nums = models.IntegerField(default=0, verbose_name='点击数')
FloatField
浮点类型。映射到数据库中是float类型, 必须提供两个参数, max_digits(总位数,不包括小数点和符号), decimal_places(小数位数)
price = modes.FloatField(max_digits=5, decimal_places=2, verbose_name='价格')
BooleanField
在模型层面接收的是True/False。在数据库层面是tinyint类型。如果没有指定默认值,默认值是None
has_read = models.BooleanField(default=False, verbose_name='是否已读')
TextField
大量的文本类型。映射到数据库中是longtext类型
details = models.TextField(verbose_name='课程详情')
UUIDfield
只能存储uuid格式的字符串。uuid是一个32位的全球唯一的字符串,一般用来作为主键
import uuid
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
DateField
日期类型
birthday = models.DateField(verbose_name='生日')
DateTimeField
日期时间类型
auto_now 当对象被保存时,自动将该字段的值设置为当前时间.通常用于表示 "last-modified" 时间戳
auto_now_add 当对象首次被创建时,自动将该字段的值设置为当前时间.通常用于表示对象创建时间.
add_time = models.DateTimeField(auto_now_add=True, verbose_name='添加时间')
EmailFiled
一个带有检查Email合法性的 CharField,不接受 maxlength 参数
email = models.EmailField(verbose_name='邮箱')
URLField
类似于CharField,只不过只能用来存储url格式的字符串。并且默认的max_length是200
url = models.URLField(max_length=200, verbose_name='访问地址')
字段常用参数
verbose_name
一个详细的名称。如果没有给出详细名称,Django将使用字段的属性名称自动创建它
city = models.ForeignKey(CityDict, verbose_name='所在城市')
null
如果为True,Django将NULL在数据库中存储空值。默认是False, 避免在字符串的类型字段上使用,例如CharFiled和TextField
对于基于字符串和非基于字符串的字段,您还需要设置blank=True是否允许在表单中允许空值,因为该 null参数仅影响数据库存储
blank
标识这个字段在表单验证的时候是否可以为空。默认是False。 这个和null是有区别的,null是一个纯数据库级别的。而blank是表单验证级别的
default
默认值。可以为一个值,或者是一个函数,但是不支持lambda表达式。并且不支持列表/字典/集合等可变的数据结构
primary_key
是否为主键。默认是False
unique
在表中这个字段的值是否唯一。一般是设置手机号码/邮箱等
choices
用作此字段的选项
from django.db import models class Person(models.Model): SHIRT_SIZES = ( ('S', 'Small'), ('M', 'Medium'), ('L', 'Large'), ) name = models.CharField(max_length=60) shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES) >>> p = Person(name="Fred Flintstone", shirt_size="L") >>> p.save() >>> p.shirt_size 'L' >>> p.get_shirt_size_display() 'Large'
模型中的Meta配置
对于一些模型级别的配置。我们可以在模型中定义一个类,叫做Meta。然后在这个类中添加一些类属性来控制模型的作用。比如我们想要在数据库映射的时候使用自己指定的表名,而不是使用模型的名称。那么我们可以在Meta类中添加一个db_table的属性。示例代码如下:
class Book(models.Model): name = models.CharField(max_length=20,null=False) desc = models.CharField(max_length=100) class Meta: db_table = 'book_model'
如果没有指定db_table参数,那么在映射的时候将会使用(app名_模型名)来作为默认的表名
ordering
设置在提取数据的排序方式。比如我想在查找数据的时候根据添加的时间排序,那么示例代码如下:
class Book(models.Model): name = models.CharField(max_length=20,null=False) desc = models.CharField(max_length=100) pub_date = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['pub_date']
verbose_name
verbose_name: 对象的可读名称,单数 verbose_name_plural: 对象的可读名称,复数, 如果没有给出,Django将使用verbose_name+ "s"
class CityDict(models.Model): name = models.CharField(max_length=20, verbose_name='城市名') desc = models.CharField(max_length=200, verbose_name='描述') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') class Meta: verbose_name = '城市' verbose_name_plural = verbose_name
基本操作 (基于上面创建的模型进行操作)
前面我们创建给4给模型
- Book(图书)
- Publish(出版社)
- Author(作者)
首先给这些表插入一些测试数据
def ormDemo(request): if request.method == "GET": # 增加出版社 # Publish.objects.create(name="华山出版社", city="华山", email="hs@163.com") # Publish.objects.create(name="明教出版社", city="黑木崖", email="mj@163.com") # 增加作者 # Author.objects.create(name="令狐冲", gender=1, addr="华山", age=25, birthday="1994-5-23") # Author.objects.create(name="任我行", gender=1, addr="黑木崖", age=58, birthday="1961-8-13") # Author.objects.create(name="任盈盈", gender=0, addr="黑木崖", age=23, birthday="1996-5-20") # 增加图书 huasan_publish = Publish.objects.filter(name="华山出版社").first() mingjiao_publish = Publish.objects.filter(name="明教出版社").first() ling = Author.objects.filter(name="令狐冲").first() ying = Author.objects.filter(name="任盈盈").first() xing = Author.objects.filter(name="任我行").first() Book.objects.create(name="独孤九剑", price=200, pub_date="2019-1-7", publish=huasan_publish) Book.objects.create(name="吸星大法", price=180, pub_date="2018-10-2", publish=mingjiao_publish) Book.objects.create(name="葵花宝典", price=220, pub_date="2018-11-12", publish=mingjiao_publish) book01 = Book.objects.filter(name="独孤九剑").first() book01.authors.add(ling, ying) book02 = Book.objects.filter(name="吸星大法").first() book02.authors.add(xing) book03 = Book.objects.filter(name="葵花宝典").first() book03.authors.add(xing) return HttpResponse("ok")
1、查询 "葵花宝典" 的出版社 所在的城市
book = Book.objects.filter(name="葵花宝典").first() print(book.publish.city)
2、查询明教出版社所有的书籍名
pub_obj = Publish.objects.filter(name="明教出版社").first()
for book in pub_obj .book_set.all(): print(book.name)
3、查询所有住在华山的作者姓名
authors = Author.objects.filter(addr="华山") for author in authors: print(author.name)
4、查出独孤九剑的所有作者和年龄
book = Book.objects.filter(name="独孤九剑").first() for author in book.authors.all(): print(author.name, author.age)
5、查询"任我行"所有的书籍名称
author = Author.objects.filter(name="任我行").first() for book in author.book_set.all(): print(book.name)
基于双下划线跨表查询
# 查询明教出版社出版过的所有书籍和价格 books = Book.objects.filter(publish__name="明教出版社").values("name", "price") print(books) <QuerySet [{'name': '吸星大法', 'price': Decimal('180.00')}, {'name': '葵花宝典', 'price': Decimal('220.00')}]> # 查出"任我行"所有的书籍名字 books = Author.objects.filter(name="任我行").values("book__name") print(books) <QuerySet [{'book__name': '吸星大法'}, {'book__name': '葵花宝典'}]>