优点
缺点
ORM只是一种工具,工具确实能解决一些重复,简单的劳动。这是不可否认的。但我们不能指望某个工具能一劳永逸地解决所有问题,一些特殊问题还是需要特殊处理的。
但是在整个软件开发过程中需要特殊处理的情况应该都是很少的,否则所谓的工具也就失去了它存在的意义。
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": "欲连接的数据库名称", # 需要自己手动创建数据库
"USER": "数据库用户名",
"PASSWORD": "数据库密码",
"HOST": "数据库IP",
"POST": 3306 }
}
# python3中需要写入以下内容
import pymysql
pymysql.install_as_MySQLdb()
基本映射关系介绍
在Django中model是你数据的单一、明确的信息来源。它包含了你存储的数据的重要字段和行为。
入门示例
# 在models.py中定义了一个 **Person** 模型,包含first_name 和 last_name
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
# first_name 和 last_name 是模型的字段。每个字段被指定为一个类属性,每个属性映射到一个数据库列。上面的 Person 模型将会像这样创建一个数据库表:
CREATE TABLE myapp_person (
"id" serial NOT NULL PRIMARY KEY,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL
);
AutoField
IntegerField
CharField
DateField
DateTimeField
AutoField(Field)
BigAutoField(AutoField)
SmallIntegerField(IntegerField)
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
IntegerField(Field)
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
BigIntegerField(IntegerField)
BooleanField(Field)
NullBooleanField(Field)
CharField(Field)
TextField(Field)
EmailField(CharField)
IPAddressField(Field)
GenericIPAddressField(Field)
protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4, 如果指定为True,则输入: : ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"
URLField(CharField)
SlugField(CharField)
CommaSeparatedIntegerField(CharField)
UUIDField(Field)
FilePathField(Field)
FileField(Field)
ImageField(FileField)
DateTimeField(DateField)
DateField(DateTimeCheckMixin, Field)
TimeField(DateTimeCheckMixin, Field)
DurationField(Field)
FloatField(Field)
DecimalField(Field)
BinaryField(Field)
# 自定义Char类型字段
class FixedCharField(models.Field):
"""
自定义的char类型的字段类
"""
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super(FixedCharField, self).__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection):
"""
限定生成数据库表的字段类型为char,长度为max_length指定的值
"""
return 'char(%s)' % self.max_length
class Class(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=25)
# 使用自定义的char类型的字段
cname = FixedCharField(max_length=25)
# 对应关系:
'AutoField': 'integer AUTO_INCREMENT',
'BigAutoField': 'bigint AUTO_INCREMENT',
'BinaryField': 'longblob',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'bigint',
'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision',
'IntegerField': 'integer',
'BigIntegerField': 'bigint',
'IPAddressField': 'char(15)',
'GenericIPAddressField': 'char(39)',
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PositiveIntegerField': 'integer UNSIGNED',
'PositiveSmallIntegerField': 'smallint UNSIGNED',
'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'longtext',
'TimeField': 'time',
'UUIDField': 'char(32)',
null
unique
db_index
default
auto_now_add (用于DateField、DateTimeField)
auto_now (用于DateField、DateTimeField)
外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 ‘一对多’中’多’的一方。
ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。
- to
- 设置要关联的表
to_field
related_name
related_query_name
db_constraint
on_delete
models.CASCADE
删除关联数据,与之关联也删除
models.DO_NOTHING
删除关联数据,引发错误IntegrityError
models.PROTECT
删除关联数据,引发错误ProtectedError
models.SET_NULL
删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
models.SET_DEFAULT
删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
models.SET
删除关联数据
a. 与之关联的值设置为指定值,设置:models.SET(值)
b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
一对一字段,通常一对一字段用来扩展已有字段。
- to
- 设置要关联的表。
to_field
on_delete
用于表示多对多的关联关系。在数据库中通过第三张表来建立关联关系
- to
- 设置要关联的表
related_name
related_query_name
symmetrical
through
through_fields
db_table
**元信息
ORM对应的类里面包含另一个Meta类,而Meta类封装了一些数据库的信息。主要字段如下:**
db_table
index_together
unique_together
ordering
models.TableName.objects.all()
查询所有结果
models.TableName.objects.filter(**kwargs)
它包含了与所给筛选条件相匹配的对象
models.TableName.objects.exclude(**kwargs)
它包含了与所给筛选条件不匹配的对象
models.TableName.objects.order_by(*field)
对查询结果排序
models.TableName.objects.reverse()
对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)
models.TableName.objects.distinct()
从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)
models.TableName.objects.values(*field)
返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
models.TableName.objects.values_list(*field)
它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
models.TableName.objects.get(**kwargs)
返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
models.TableName.objects.first()
返回第一条记录
models.TableName.objects.last()
返回最后一条记录
models.TableName.objects.exists()
models.TableName.objects.count()
models.TableName.objects.filter(attr__lt=value)
获取attr小于value的值
models.TableName.objects.filter(attr__gt=value)
获取attr大于value的值
models.TableName.objects.filter(attr__in=[value1,value2,value3])
获取attr等于value1、value2、value3的值
models.TableName.objects.filter(attr__contains="substring")
获取attr字段包含”substring”的值
models.TableName.objects.filter(attr__icontains="substring")
获取attr字段包含”substring”的值(大小写不敏感)
models.TableName.objects.filter(attr__range=[value1,value3])
获取attr范围在value1至value3的值(左右都包含)
models.TableName.objects.filter(attr__startswith="substring")
获取以substring开头的值
models.TableName.objects.filter(attr__istartswith="substring")
获取以substring开头的值(大小写不敏感)
models.TableName.objects.filter(attr__enswith="substring")
获取以substring结尾的值
models.TableName.objects.filter(attr__ienswith="substring")
获取以substring结尾的值(大小写不敏感)
models.TableName.objects.filter(attr__year=num)
获取attr字段year值等于num的结果(year也可以为month、day分别获取月份、日期)
链接:https://docs.djangoproject.com/en/1.11/ref/models/querysets/
正向查找
反向查找
create()
add()
remove()
clear()
注意:
aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。
键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。
>>> models.Book.objects.all().aggregate(Avg("price"))
{'price__avg': 13.233333}
# 如果你想要为聚合值指定一个名称,可以向聚合子句提供它。
>>> models.Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 13.233333}
# 如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
>>> models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
{'price__avg': 13.233333, 'price__max': Decimal('19.90'), 'price__min': Decimal('9.90')}
为调用的QuerySet中每一个对象都生成一个独立的统计值
# 示例1:统计每一本书的作者个数
>>> book_list = models.Book.objects.all().annotate(author_num=Count("author"))
>>> for obj in book_list:
... print(obj.author_num)
...
2
1
1
# 示例2:统计出每个出版社买的最便宜的书的价格
>>> publisher_list = models.Publisher.objects.annotate(min_price=Min("book__price"))
>>> for obj in publisher_list:
... print(obj.min_price)
...
9.90
19.90
#方法二:
>>> models.Book.objects.values("publisher__name").annotate(min_price=Min("price"))
'publisher__name': '出版社0001', 'min_price': Decimal('9.90')}, {'publisher__name': '出版社002', 'min_price': Decimal('19.90')}]>
#示例3:统计不止一个作者的图书
>>> models.Book.objects.annotate(author_num=Count("author")).filter(author_num__gt=1)
001>]>
#示例4:根据一本图书作者数量的多少对查询集 QuerySet进行排序
>>> models.Book.objects.annotate(author_num=Count("author")).order_by("author_num")
002>, 003>, 001>]>
# 示例5:查询各个作者出的书的总价格
>>> models.Author.objects.annotate(sum_price=Sum("book__price")).values("name", "sum_price")
'name': '作者001', 'sum_price': Decimal('9.90')}, {'name': '作者002', 'sum_price': Decimal('29.80')}, {'name': '作者003', 'sum_price': Decimal('9.90')}]>
Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。
# 查询评论数大于收藏数的书籍
from django.db.models import F
models.Book.objects.filter(comment_num__lt=F('keep_num'))
# Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。
models.Book.objects.filter(comment_num__lt=F('keep_num')*2)
# 修改操作也可以使用F函数,比如将每一本书的价格提高30元
models.Book.objects.all().update(price=F("price")+30)
# 引申:
# 修改char字段,如:把所有书名后面加上(第一版)
>>> from django.db.models.functions import Concat
>>> from django.db.models import Value
>>> models.Book.objects.all().update(title=Concat(F("title"), Value("("), Value("第一版"), Value(")")))
filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象。
# 查询作者名是小仙女或小魔女的
models.Book.objects.filter(Q(authors__name="小仙女")|Q(authors__name="小魔女"))
#你可以组合& 和| 操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询。
# 示例:查询作者名字是小仙女并且不是2018年出版的书的书名。
>>> models.Book.objects.filter(Q(author__name="小仙女") & ~Q(publish_date__year=2018)).values_list("title")
'番茄物语',)]>
# 查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。
# 例如:查询出版年份是2017或2018,书名中带物语的所有书。
>>> models.Book.objects.filter(Q(publish_date__year=2018) | Q(publish_date__year=2017), title__icontains="物语")
, , ]>
import os
if __name__ == '__main__':
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
import django
django.setup()
import datetime
from app01 import models
try: from django.db import transaction
with transaction.atomic():
new_publisher = models.Publisher.objects.create(name="出版社001")
models.Book.objects.create(title="书籍001", publish_date=datetime.date.today(), publisher_id=10) # 指定一个不存在的出版社id
except Exception as e:
print(str(e))
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler',
},
}, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG',
},
}
}<
import os if __name__ == '__main__':
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings") import django
django.setup() from app01 import models
books = models.Book.objects.all() print(books)