django(4)ORM基础
前奏:原生SQL语句操作数据库
- 简单的图书管理系统示例:
** 虚拟环境中安装pip install mysqlclient
相应模块 **
book APP的views.py
中:from django.shortcuts import render, redirect, reverse from django.db import connection def get_cursor(): return connection.cursor() def index(request): cursor = get_cursor() cursor.execute('select id,name,author from book') books = cursor.fetchall() # books返回时列表,里面是元组 [(1, '三国演义', '罗贯中'), ··] return render(request, 'index.html', context={'books': books}) def add_book(request): if request.method == 'GET': return render(request, 'add_book.html') else: name = request.POST.get('name') author = request.POST.get('author') cursor = get_cursor() cursor.execute( "insert into book(id,name,author) values(null, '%s', '%s')" % (name, author)) return redirect(reverse('index')) def book_detail(request, book_id): cursor = get_cursor() cursor.execute("select id,name,author from book where id=%s" % book_id) book = cursor.fetchone() return render(request, 'book_detail.html', context={'book': book}) def delete_book(request): if request.method == 'POST': book_id = request.POST.get('book_id') cursor = get_cursor() cursor.execute("delete from book where id=%s" % book_id) return redirect(reverse('index')) else: raise RuntimeError("删除图书的method错误")
urls.py
中代码如下:from django.urls import path from book import views urlpatterns = [ path('', views.index, name='index'), path('add_book/', views.add_book, name='add_book'), path('book_detail/<int:book_id>/', views.book_detail, name='book_detail'), # re_path('book_detail/(?P<book_id>/d+)/',views.book_detail, name='book_detail') path('delete_book/', views.delete_book, name='delete_book'), ]
settings.py
中配置:DATABASES = { 'default': { # 数据库引擎(sqlite3/mysql/oracle等) 'ENGINE': 'django.db.backends.mysql', # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 'NAME': 'django_db2', 'USER': 'root', 'PASSWORD': '123456', 'HOST': '127.0.0.1', 'PORT': '3306', } }
ORM模型的创建和映射:
创建ORM模型:
ORM
模型一般都是放在app
的models.py
文件中。每个app
都可以拥有自己的模型。并且如果这个模型想要映射到数据库中,那么这个app
必须要放在settings.py
的INSTALLED_APP
中进行安装。以下是写一个简单的书籍ORM
模型。示例代码如下:
from django.db import models
class Book(models.Model):
name = models.CharField(max_length=20,null=False)
author = models.CharField(max_length=20,null=False)
pub_time = models.DateTimeField(default=datetime.now)
price = models.FloatField(default=0)
以上便定义了一个模型。这个模型继承自django.db.models.Model
,如果这个模型想要映射到数据库中,就必须继承自这个类。这个模型以后映射到数据库中,表名是模型名称的小写形式,为book
。在这个表中,有四个字段,一个为name
,这个字段是保存的是书的名称,是varchar
类型,最长不能超过20个字符,并且不能为空。第二个字段是作者名字类型,同样也是varchar
类型,长度不能超过20个。第三个是出版时间,数据类型是datetime
类型,默认是保存这本书籍的时间。第五个是这本书的价格,是浮点类型。
还有一个字段我们没有写,就是主键id
,在django
中,如果一个模型没有定义主键,那么将会自动生成一个自动增长的int
类型的主键,并且这个主键的名字就叫做id
。
映射模型到数据库中:
将ORM
模型映射到数据库中,总结起来就是以下几步:
- 在
settings.py
中,配置好DATABASES
,做好数据库相关的配置。 - 在
app
中的models.py
中定义好模型,这个模型必须继承自django.db.models
。 - 将这个
app
添加到settings.py
的INSTALLED_APP
中。 - 在命令行终端,进入到项目所在的路径,然后执行命令
python manage.py makemigrations
来生成迁移脚本文件。 - 同样在命令行中,执行命令
python manage.py migrate
来将迁移脚本文件映射到数据库中。
ORM对数据库的基本操作:
添加数据:
只要使用ORM模型创建一个对象。然后再调用这个ORM模型的save
方法就可以保存了。
示例代码如下:
book = Book(name='西游记',author='吴承恩',price=100)
book.save()
查找数据:
所有的查找工作都是使用模型上的objects
属性来完成的。当然也可以自定义查询对象。这部分功能会在后面讲到。
- 根据主键进行查找:使用主键进行查找。可以使用
objects.get
方法。然后传递pk=xx
的方式进行查找。示例代码如下:book = Book.objects.get(pk=2)
- 根据其他字段进行查找:可以使用
objects.filter
方法进行查找。示例代码如下:
使用books = Book.objects.filter(name='三国演义')
filter
方法返回来的是一个QuerySet
对象。这个对象类似于列表。我们可以使用这个对象的first
方法来获取第一个值。
删除数据:
首先查找到对应的数据模型。然后再执行这个模型的delete
方法即可删除。示例代码如下:
book = Book.objects.get(pk=1)
book.delete()
修改数据:
首先查找到对应的数据模型。然后修改这个模型上的属性的值。再执行save
方法即可修改完成。示例代码如下:
book = Book.objects.get(pk=2)
book.price = 200
book.save()
常用Field:
navie时间和aware时间:
什么是navie时间?什么是aware时间?
- navie时间:不知道自己的时间表示的是哪个时区的。也就是不知道自己几斤几两。比较幼稚。
- aware时间:知道自己的时间表示的是哪个时区的。也就是比较清醒。
pytz库:
专门用来处理时区的库。这个库会经常更新一些时区的数据,不需要我们担心。并且这个库在安装Django的时候会默认的安装。如果没有安装,那么可以通过pip install pytz
的方式进行安装。
astimezone方法:
将一个时区的时间转换为另外一个时区的时间。这个方法只能被aware
类型的时间调用。不能被navie
类型的时间调用。
示例代码如下:
import pytz
from datetime import datetime
now = datetime.now() # 这是一个navie类型的时间
utc_timezone = pytz.timezone("UTC") # 定义UTC的时区对象
utc_now = now.astimezone(utc_timezone) # 将当前的时间转换为UTC时区的时间
>> ValueError: astimezone() cannot be applied to a naive datetime # 会抛出一个异常,原因就是因为navie类型的时间不能调用astimezone方法
now = now.replace(tzinfo=pytz.timezone('Asia/Shanghai'))
utc_now = now.astimezone(utc_timezone)
# 这时候就可以正确的转换。
replace方法:
可以将一个时间的某些属性进行更改。
django.utils.timezone.now方法:
会根据settings.py
中是否设置了USE_TZ=True
获取当前的时间。如果设置了,那么就获取一个aware
类型的UTC
时间。如果没有设置,那么就会获取一个navie
类型的时间。
django.utils.timezone.localtime方法:
会根据setting.py
中的TIME_ZONE
来将一个aware
类型的时间转换为TIME_ZONE
指定时区的时间。
DateField:
日期类型。在Python
中是datetime.date
类型,可以记录年月日。在映射到数据库中也是date
类型。使用这个Field
可以传递以下几个参数:
-
auto_now
:在每次这个数据保存的时候,都使用当前的时间。比如作为一个记录修改日期的字段,可以将这个属性设置为True
。 -
auto_now_add
:在每次数据第一次被添加进去的时候,都使用当前的时间。比如作为一个记录第一次入库的字段,可以将这个属性设置为True
。
DateTimeField:
日期时间类型,类似于DateField
。不仅仅可以存储日期,还可以存储时间。映射到数据库中是datetime
类型。这个Field
也可以使用auto_now
和auto_now_add
两个属性。
TimeField:
时间类型。在数据库中是time
类型。在Python
中是datetime.time
类型。
navie和aware介绍以及在django中的用法:
https://docs.djangoproject.com/en/2.0/topics/i18n/timezones/
EmailField:
类似于CharField
。在数据库底层也是一个varchar
类型。最大长度是254个字符。在数据库层面并不会限制存入的数据,而是在ModelForm
中会起作用
FileField:
用来存储文件的。这个请参考后面的文件上传章节部分。
ImageField:
用来存储图片文件的。这个请参考后面的图片上传章节部分。
FloatField:
浮点类型。映射到数据库中是float
类型。
IntegerField:
整形。值的区间是-2147483648——2147483647
。
BigIntegerField:
大整形。值的区间是-9223372036854775808——9223372036854775807
。
PositiveIntegerField:
正整形。值的区间是0——2147483647
。
SmallIntegerField:
小整形。值的区间是-32768——32767
。
PositiveSmallIntegerField:
正小整形。值的区间是0——32767
。
TextField:
大量的文本类型。映射到数据库中是longtext类型。
UUIDField:
只能存储uuid
格式的字符串。uuid
是一个32位的全球唯一的字符串,一般用来作为主键。
URLField:
类似于CharField
,只不过只能用来存储url
格式的字符串。并且默认的max_length
是200。
Field常用的参数
null:
如果设置为True
,Django
将会在映射表的时候指定是否为空。默认是为False
。在使用字符串相关的Field
(CharField/TextField)的时候,官方推荐尽量不要使用这个参数,也就是保持默认值False
。因为Django
在处理字符串相关的Field
的时候,即使这个Field
的null=False
,如果你没有给这个Field
传递任何值,那么Django
也会使用一个空的字符串""
来作为默认值存储进去。因此如果再使用null=True
,Django
会产生两种空值的情形(NULL或者空字符串)。如果想要在表单验证的时候允许这个字符串为空,那么建议使用blank=True
。如果你的Field
是BooleanField
,那么对应的可空的字段则为NullBooleanField
。
blank:
标识这个字段在表单验证的时候是否可以为空。默认是False
。
这个和null
是有区别的,null
是一个纯数据库级别的。而blank
是表单验证级别的。
db_column:
这个字段在数据库中的名字。如果没有设置这个参数,那么将会使用模型中属性的名字。
default:
默认值。可以为一个值,或者是一个函数,但是不支持lambda
表达式。并且不支持列表/字典/集合等可变的数据结构。
primary_key:
是否为主键。默认是False
。
unique:
在表中这个字段的值是否唯一。一般是设置手机号码/邮箱等。
更多Field
参数请参考官方文档:https://docs.djangoproject.com/zh-hans/2.0/ref/models/fields/
模型中Meta
配置:
对于一些模型级别的配置。我们可以在模型中定义一个类,叫做Meta
。然后在这个类中添加一些类属性来控制模型的作用。比如我们想要在数据库映射的时候使用自己指定的表名,而不是使用模型的名称。那么我们可以在Meta
类中添加一个db_table
的属性。示例代码如下:
class Book(models.Model):
name = models.CharField(max_length=20,null=False)
desc = models.CharField(max_length=100,name='description',db_column="description1")
class Meta:
db_table = 'book_model'
以下将对Meta
类中的一些常用配置进行解释。
db_table:
这个模型映射到数据库中的表名。如果没有指定这个参数,那么在映射的时候将会使用模型名来作为默认的表名。
ordering:
设置在提取数据的排序方式。后面章节会讲到如何查找数据。比如我想在查找数据的时候根据添加的时间排序,那么示例代码如下:
class Book(models.Model):
name = models.CharField(max_length=20,null=False)
desc = models.CharField(max_length=100,name='description',db_column="description1")
pub_date = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'book_model'
ordering = ['pub_date']
更多的配置,参考官方文档。
官方文档:https://docs.djangoproject.com/en/2.0/ref/models/options/