Django 模型层
ORM简介
- MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动。
- ORM是“对象-关系-映射”的简称。
字段与参数
每个字段有一些特有的参数,例如,CharField需要max_length参数来指定VARCHAR数据库字段的大小。还有一些适用于所有字段的通用参数。 这些参数在文档中有详细定义,这里我们只简单介绍一些最常用的:
一、字段
AutoField(Field)- int自增列,必须填入参数 primary_key=TrueBigAutoField(AutoField)- bigint自增列,必须填入参数 primary_key=True注:当model中如果没有自增列,则自动会创建一个列名为id的列from django.db import modelsclass UserInfo(models.Model):# 自动创建一个列名为id的且为自增的整数列username = models.CharField(max_length=32)class Group(models.Model):# 自定义自增列nid = models.AutoField(primary_key=True)name = models.CharField(max_length=32)SmallIntegerField(IntegerField):- 小整数 -32768 ~ 32767PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)- 正小整数 0 ~ 32767IntegerField(Field)- 整数列(有符号的) -2147483648 ~ 2147483647PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)- 正整数 0 ~ 2147483647BigIntegerField(IntegerField):- 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807自定义无符号整数字段class UnsignedIntegerField(models.IntegerField):def db_type(self, connection):return 'integer UNSIGNED'PS: 返回值为字段在数据库中的属性,Django字段默认的值为:'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)',BooleanField(Field)- 布尔值类型NullBooleanField(Field):- 可以为空的布尔值CharField(Field)- 字符类型- 必须提供max_length参数, max_length表示字符长度TextField(Field)- 文本类型EmailField(CharField):- 字符串类型,Django Admin以及ModelForm中提供验证机制IPAddressField(Field)- 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制GenericIPAddressField(Field)- 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6- 参数:protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"URLField(CharField)- 字符串类型,Django Admin以及ModelForm中提供验证 URLSlugField(CharField)- 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)CommaSeparatedIntegerField(CharField)- 字符串类型,格式必须为逗号分割的数字UUIDField(Field)- 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证FilePathField(Field)- 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能- 参数:path, 文件夹路径match=None, 正则匹配recursive=False, 递归下面的文件夹allow_files=True, 允许文件allow_folders=False, 允许文件夹FileField(Field)- 字符串,路径保存在数据库,文件上传到指定目录- 参数:upload_to = "" 上传文件的保存路径storage = None 存储组件,默认django.core.files.storage.FileSystemStorageImageField(FileField)- 字符串,路径保存在数据库,文件上传到指定目录- 参数:upload_to = "" 上传文件的保存路径storage = None 存储组件,默认django.core.files.storage.FileSystemStoragewidth_field=None, 上传图片的高度保存的数据库字段名(字符串)height_field=None 上传图片的宽度保存的数据库字段名(字符串)DateTimeField(DateField)- 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]DateField(DateTimeCheckMixin, Field)- 日期格式 YYYY-MM-DDTimeField(DateTimeCheckMixin, Field)- 时间格式 HH:MM[:ss[.uuuuuu]]DurationField(Field)- 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型FloatField(Field)- 浮点型DecimalField(Field)- 10进制小数- 参数:max_digits,小数总长度decimal_places,小数位长度BinaryField(Field)- 二进制类型
字段
二、参数
null 数据库中字段是否可以为空db_column 数据库中字段的列名db_tablespacedefault 数据库中字段的默认值primary_key 数据库中字段是否为主键db_index 数据库中字段是否可以建立索引unique 数据库中字段是否可以建立唯一索引unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引unique_for_month 数据库中字段【月】部分是否可以建立唯一索引unique_for_year 数据库中字段【年】部分是否可以建立唯一索引verbose_name Admin中显示的字段名称blank Admin中是否允许用户输入为空editable Admin中是否可以编辑help_text Admin中该字段的提示信息choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息;字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date如:{'null': "不能为空.", 'invalid': '格式错误'}validators 自定义错误验证(列表类型),从而定制想要的验证规则from django.core.validators import RegexValidatorfrom django.core.validators import EmailValidator,URLValidator,DecimalValidator,\MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator如:test = models.CharField(max_length=32,error_messages={'c1': '优先错信息1','c2': '优先错信息2','c3': '优先错信息3',},validators=[RegexValidator(regex='root_\d+', message='错误了', code='c1'),RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),EmailValidator(message='又错误了', code='c3'), ])
参数
三、元信息
class UserInfo(models.Model):nid = models.AutoField(primary_key=True)username = models.CharField(max_length=32)class Meta:# django以后再做数据库迁移时,不再为UserInfo类创建相关的表以及表结构了。# 此类可以当做"父类",被其他Model类继承。abstract = True# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名db_table = "table_name"# 联合索引index_together = [("pub_date", "deadline"),]# 联合唯一索引unique_together = (("driver", "restaurant"),)# admin中显示的表名称 verbose_name# verbose_name加s verbose_name_plural更多:https: // docs.djangoproject.com / en / 1.10 / ref / models / options /
元信息
四、连表结构
ForeignKey(ForeignObject) # ForeignObject(RelatedField)to, # 要进行关联的表名to_field=None, # 要关联的表中的字段名称on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为- 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(可执行对象)def func():return 10class MyModel(models.Model):user = models.ForeignKey(to="User",to_field="id"on_delete=models.SET(func),)related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件:# 如:- limit_choices_to={'nid__gt': 5}- limit_choices_to=lambda : {'nid__gt': 5}from django.db.models import Q- limit_choices_to=Q(nid__gt=10)- limit_choices_to=Q(nid=8) | Q(nid__gt=10)- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')db_constraint=True # 是否在数据库中创建外键约束parent_link=False # 在Admin中是否显示关联数据 OneToOneField(ForeignKey)to, # 要进行关联的表名to_field=None # 要关联的表中的字段名称on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为###### 对于一对一 ####### 1. 一对一其实就是 一对多 + 唯一索引# 2.当两个类之间有继承关系时,默认会创建一个一对一字段# 如下会在A表中额外增加一个c_ptr_id列且唯一:class C(models.Model):nid = models.AutoField(primary_key=True)part = models.CharField(max_length=12)class A(C):id = models.AutoField(primary_key=True)code = models.CharField(max_length=1)ManyToManyField(RelatedField)to, # 要进行关联的表名related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件:# 如:- limit_choices_to={'nid__gt': 5}- limit_choices_to=lambda : {'nid__gt': 5}from django.db.models import Q- limit_choices_to=Q(nid__gt=10)- limit_choices_to=Q(nid=8) | Q(nid__gt=10)- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')symmetrical=None, # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段# 做如下操作时,不同的symmetrical会有不同的可选字段 models.BB.objects.filter(...)# 可选字段有:code, id, m1class BB(models.Model):code = models.CharField(max_length=12)m1 = models.ManyToManyField('self',symmetrical=True)# 可选字段有: bb, code, id, m1class BB(models.Model):code = models.CharField(max_length=12)m1 = models.ManyToManyField('self',symmetrical=False)through=None, # 自定义第三张表时,使用字段用于指定关系表through_fields=None, # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表 db_constraint = True, # 是否在数据库中创建外键约束db_table = None, # 默认创建第三张表时,数据库中表的名称from django.db import modelsclass Person(models.Model):name = models.CharField(max_length=50)class Group(models.Model):name = models.CharField(max_length=128)members = models.ManyToManyField(Person,through='Membership',through_fields=('group', 'person'),)class Membership(models.Model):group = models.ForeignKey(Group, on_delete=models.CASCADE)person = models.ForeignKey(Person, on_delete=models.CASCADE)inviter = models.ForeignKey(Person,on_delete=models.CASCADE,related_name="membership_invites",)invite_reason = models.CharField(max_length=64)""" 与普通的多对多不一样,使用自定义中间表的多对多不能使用add(), create(),remove(),和set()方法来创建、删除关系 beatles = Group.objects.create(name="The Beatles") >>> # 无效 >>> beatles.members.add(john) >>> # 无效 >>> beatles.members.create(name="George Harrison") >>> # 无效 >>> beatles.members.set([john, paul, ringo, george]) 但是,clear()方法是有效的,它能清空所有的多对多关系。 >>> # 有效 >>> beatles.members.clear() 一旦通过创建中间模型实例的方法建立了多对多的关联,你立刻就可以像普通的多对多那样进行查询操作: """
连表结构
五、双下划线
# 获取个数# # models.Tb1.objects.filter(name='seven').count()# 大于,小于# # models.Tb1.objects.filter(id__gt=1) # 获取id大于1的值# models.Tb1.objects.filter(id__gte=1) # 获取id大于等于1的值# models.Tb1.objects.filter(id__lt=10) # 获取id小于10的值# models.Tb1.objects.filter(id__lte=10) # 获取id小于10的值# models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值# in# # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据# models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in# isnull# Entry.objects.filter(pub_date__isnull=True)# contains# # models.Tb1.objects.filter(name__contains="ven")# models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感# models.Tb1.objects.exclude(name__icontains="ven")# range# # models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and# 其他类似# # startswith,istartswith, endswith, iendswith,# order by# # models.Tb1.objects.filter(name='seven').order_by('id') # asc# models.Tb1.objects.filter(name='seven').order_by('-id') # desc# group by# # from django.db.models import Count, Min, Max, Sum# models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))# SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"# limit 、offset# # models.Tb1.objects.all()[10:20]# regex正则匹配,iregex 不区分大小写# # Entry.objects.get(title__regex=r'^(An?|The) +')# Entry.objects.get(title__iregex=r'^(an?|the) +')# date# # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))# Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))# year# # Entry.objects.filter(pub_date__year=2005)# Entry.objects.filter(pub_date__year__gte=2005)# month# # Entry.objects.filter(pub_date__month=12)# Entry.objects.filter(pub_date__month__gte=6)# day# # Entry.objects.filter(pub_date__day=3)# Entry.objects.filter(pub_date__day__gte=3)# week_day# # Entry.objects.filter(pub_date__week_day=2)# Entry.objects.filter(pub_date__week_day__gte=2)# hour# # Event.objects.filter(timestamp__hour=23)# Event.objects.filter(time__hour=5)# Event.objects.filter(timestamp__hour__gte=12)# minute# # Event.objects.filter(timestamp__minute=29)# Event.objects.filter(time__minute=46)# Event.objects.filter(timestamp__minute__gte=29)# second# # Event.objects.filter(timestamp__second=31)# Event.objects.filter(time__second=2)# Event.objects.filter(timestamp__second__gte=31)
进阶操作
# extra# # extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)# Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))# Entry.objects.extra(where=['headline=%s'], params=['Lennon'])# Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])# Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])# F# # from django.db.models import F# models.Tb1.objects.update(num=F('num')+1)# Q# # 方式一:# Q(nid__gt=10)# Q(nid=8) | Q(nid__gt=10)# Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')# 方式二:# con = Q()# q1 = Q()# q1.connector = 'OR'# q1.children.append(('id', 1))# q1.children.append(('id', 10))# q1.children.append(('id', 9))# q2 = Q()# q2.connector = 'OR'# q2.children.append(('c1', 1))# q2.children.append(('c1', 10))# q2.children.append(('c1', 9))# con.add(q1, 'AND')# con.add(q2, 'AND')# # models.Tb1.objects.filter(con)# 执行原生SQL# # from django.db import connection, connections# cursor = connection.cursor() # cursor = connections['default'].cursor()# cursor.execute("""SELECT * from auth_user where id = %s""", [1])# row = cursor.fetchone()
其他操作
单表操作
一、创建表
1、创建模型
创建名为app01的app,在app01下的models.py中创建模型:
1
2
3
4
5
6
7
8
9
10
11
|
from django.db import models
# Create your models here.
class Book(models.Model):
id = models.AutoField(primary_key = True )
title = models.CharField(max_length = 32 ,unique = True )
pub_date = models.DateField()
price = models.DecimalField(max_digits = 8 ,decimal_places = 2 ) # 999999.99
publish = models.CharField(max_length = 32 )
def __str__( self ):
return self .title
|
2、settings配置:DATABASES
若想将模型转为mysql数据库中的表,需要在settings中配置:
1
2
3
4
5
6
7
8
9
10
|
DATABASES = {
'default' : {
'ENGINE' : 'django.db.backends.mysql' ,
'NAME' : 'orm9' , # 要连接的数据库,连接前需要创建好
'USER' : 'root' , # 连接数据库的用户名
'PASSWORD' :'', # 连接数据库的密码
'HOST' : '127.0.0.1' , # 连接主机,默认本级
'PORT' : 3306 , # 端口 默认3306
}
}
|
3、settings配置:INSTALLED_APPS
确保配置文件中的INSTALLED_APPS中写入我们创建的app名称
1
2
3
4
5
6
7
8
9
|
INSTALLED_APPS = [
'django.contrib.admin' ,
'django.contrib.auth' ,
'django.contrib.contenttypes' ,
'django.contrib.sessions' ,
'django.contrib.messages' ,
'django.contrib.staticfiles' ,
"app01" ,
]
|
4、项目名文件下的__init__配置
django默认导入的驱动是MySQLdb,可是MySQLdb 对于py3有很大问题,我们需要的驱动是PyMySQL 所以,我们只需要找到项目名文件下的__init__,在里面写入:
1
2
|
import pymysql
pymysql.install_as_MySQLdb()
|
5、数据库迁移命令
1
2
|
python manage.py makemigrations
python manage.py migrate
|
6、静态文件配置:
1
2
3
4
5
|
#在settings.py中:
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static' ),
)
|
7、打印orm转换过程中的sql,在settings中配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
LOGGING = {
'version' : 1 ,
'disable_existing_loggers' : False ,
'handlers' : {
'console' :{
'level' : 'DEBUG' ,
'class' : 'logging.StreamHandler' ,
},
},
'loggers' : {
'django.db.backends' : {
'handlers' : [ 'console' ],
'propagate' : True ,
'level' : 'DEBUG' ,
},
}
}
|
8、常见报错
- 报错:no module named MySQLdb 。这是因为django默认你导入的驱动是MySQLdb,可是MySQLdb 对于py3有很大问题,所以我们需要的驱动是PyMySQL 所以,我们只需要找到项目名文件下的__init__,在里面写入:
1
2
|
import pymysql
pymysql.install_as_MySQLdb()
|
- 报错:django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.3 or newer is required; you have 0.7.11.None
- MySQLclient目前只支持到python3.4,因此如果使用的更高版本的python,需要修改如下: 通过查找路径C:\Programs\Python\Python36-32\Lib\site-packages\Django-2.0-py3.6.egg\django\db\backends\mysql 这个路径里的文件把下面代码注释掉就OK了。
1
2
|
if version < ( 1 , 3 , 3 ):
raise ImproperlyConfigured( "mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)
|
二、增
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
#app01.views.py
from django.shortcuts import render,HttpResponse
from app01.models import Book
def index(request):
# ==================================添加表记录 ==================================
# 方式1:
# book_obj=Book(id=1,title="python",price=100,pub_date="2012-12-12",publish="人民出版社")
# book_obj.save()
#方式2: create返回值就是当前生成的对象纪录
book_obj = Book.objects.create(title = "php2" ,price = 100 ,pub_date = "2013-12-12" ,publish = "人民出版社" )
print (book_obj.title)
print (book_obj.price)
print (book_obj.pub_date)
return HttpResponse( "OK" )
#方式3: 批量导入:
book_list = []
for i in range ( 100 ):
book = Book(title = "book_%s" % i,price = i * i)
book_list.append(book)
Book.objects.bulk_create(book_list)
|
三、删
- 在 Django 删除对象时,会模仿 SQL 约束 ON DELETE CASCADE 的行为,换句话说,删除一个对象时也会删除与它相关联的外键对象。
- 如果不想级联删除,可以设置为:pubHouse = models.ForeignKey(to='Publisher', on_delete=models.SET_NULL, blank=True, null=True)
- delete() 方法是 QuerySet 上的方法,但并不适用于 Manager 本身。这是一种保护机制,是为了避免意外地调用 Entry.objects.delete() 方法导致 所有的 记录被误删除。如果你确认要删除所有的对象,那么你必须显式地调用:Entry.objects.all().delete()
1
2
3
4
5
6
7
8
9
10
11
|
#app01.views.py
from django.shortcuts import render,HttpResponse
from app01.models import Book
def index(request):
# ==================================删除表纪录=================================
# delete: 调用者: queryset对象 model对象
ret = Book.objects. filter (price = 100 ).delete()
print (ret)
ret2 = Book.objects. filter (price = 100 ).first().delete()
print (ret2)
return HttpResponse( "OK" )
|
四、改
update()方法对于任何结果集(QuerySet)均有效,你可以同时更新多条记录update()方法会返回一个整型数值,表示受影响的记录条数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#app01.views.py
from django.shortcuts import render,HttpResponse
from app01.models import Book
def index(request):
# ==================================修改表纪录 =================================
# update : 调用者: queryset对象
#方式1
book_obj = Book.objects.get(pk = 1 )
book_obj.title = '新值'
book_obj.save()
#方式2
ret = Book.objects. filter (title = "php2" ).update(title = "php" )
return HttpResponse( "OK" )
|
五、查
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
#app01.views.py
from django.shortcuts import render,HttpResponse
from app01.models import Book
def index(request):
# ================================== 查询表记录API ==================================
#(1) all方法: 返回值一个queryset对象 ## 查询所有结果
#book_list=Book.objects.all()
#print(book_list) # [obj1,obj2,.....]
# for obj in book_list:
# print(obj.title,obj.price)
#print(book_list[1].title)
#(2) first,last : 调用者:queryset对象 返回值:model对象 ## first:返回第一条记录 last:返回最后一条记录
#book=Book.objects.all().first()
#book=Book.objects.all()[0]
#(3) filter() 返回值:queryset对象 ## 它包含了与所给筛选条件相匹配的对象
# book_list=Book.objects.filter(price=100) # [obj1,obj2,....]
# print(book_list) #<QuerySet [<Book: python>, <Book: php>]>
# book_obj=Book.objects.filter(price=100).first()
# ret=Book.objects.filter(title="go",price=200)
# print(ret)
#(4) get() 有且只有一个查询结果时才有意义 返回值:model对象 ## 如果符合筛选条件的对象超过一个或者没有都会抛出错误。
# book_obj=Book.objects.get(title="go")
# book_obj=Book.objects.get(price=100)
# print(book_obj.price)
# (5) exclude 返回值:queryset对象 ##它包含了与所给筛选条件不匹配的对象 与filter() 相反
# ret=Book.objects.exclude(title="go")
# print(ret)
# (6) order_by 调用者: queryset对象 返回值: queryset对象 ## 对查询结果排序
# ret=Book.objects.all().order_by("-id")
# ret=Book.objects.all().order_by("price","id")
# print(ret)
# (7) count() 调用者: queryset对象 返回值: int ##返回数据库中匹配查询(QuerySet)的对象数量。
# ret=Book.objects.all().count()
# print(ret)
# (8) exist() ##如果QuerySet包含数据,就返回True,否则返回False
# ret=Book.objects.all().exists()
#
# if ret:
# print("ok")
# (9) values 方法 调用者: queryset对象 返回值:queryset对象
# ret=Book.objects.all()
# for i in ret:
# print(i.title)
# ret=Book.objects.all().values("price","title")
# print(ret)
'''
values:
temp=[]
for obj in Book.objects.all()
temp.append({
"price"=obj.price
"title"=obj.title
})
return temp
'''
# <QuerySet [{'price': Decimal('100.00')}, {'price': Decimal('100.00')}, {'price': Decimal('200.00')}]>
#print(ret[0].get("price")) # 100.00
# (10) values_list 方法 调用者: queryset对象 返回值:queryset对象
# ret=Book.objects.all().values_list("price","title")
# # print(ret) #<QuerySet [(Decimal('100.00'),), (Decimal('100.00'),), (Decimal('200.00'),)]>
# print(ret)
'''
values:
<QuerySet [{'title': 'python红宝书', 'price': Decimal('100.00')}, {'title': 'php', 'price': Decimal('100.00')}, {'title': 'go', 'price': Decimal('200.00')}]>
values_list:
<QuerySet [(Decimal('100.00'), 'python红宝书'), (Decimal('100.00'), 'php'), (Decimal('200.00'), 'go')]>
'''
# 11 distinct ##从返回结果中剔除重复纪录 reverse对查询结果反向排序
# ret=Book.objects.all().distinct() #没有意义
# ret=Book.objects.all().values("price").distinct()
#Book.objects.all().filter().order_by().filter().reverse().first()
# ================================== 基于双下划线的模糊查询 ==================================
# ret=Book.objects.filter(price__gt=10,price__lt=200)
# ret=Book.objects.filter(title__startswith="p")
#ret=Book.objects.filter(title__contains="h")
#ret=Book.objects.filter(title__icontains="h") #忽略大小写
#ret=Book.objects.filter(price__in=[100,200,300])
#ret=Book.objects.filter(price__range=[200,300])
#ret=Book.objects.filter(pub_date__year=2018,pub_date__month=5)
return HttpResponse( "OK" )
|
六、聚合查询与分组查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
# app01.models.py
from django.db import models
class Emp(models.Model):
name = models.CharField(max_length = 32 )
age = models.IntegerField()
salary = models.DecimalField(max_digits = 8 , decimal_places = 2 )
dep = models.CharField(max_length = 32 )
province = models.CharField(max_length = 32 )
# app01.views.py
from django.shortcuts import render, HttpResponse
from app01.models import *
from django.db.models import Avg, Max , Min , Count
def query(request):
# -------------------------单表 聚合与分组查询---------------------------
# ------------------------->聚合 aggregate:返回值是一个字典,不再是queryset
# 查询所有书籍的平均价格
ret = Book.objects. all ().aggregate(avg_price = Avg( "price" ), max_price = Max ( "price" ))
print (ret) # {'avg_price': 151.0, 'max_price': Decimal('301.00')}
ret = Book.objects.aggregate(Avg( 'price' ), Max ( 'price' ), Min ( 'price' ))
print (ret) # {'price__avg': 151.0, 'price__max': Decimal('301.00'), 'price__min': Decimal('12.99')}
# ------------------------->分组查询 annotate ,返回值依然是queryset
# 单表分组查询的ORM语法: 单表模型.objects.values("group by的字段").annotate(聚合函数("统计字段"))
# 在单表分组下, 按着主键进行group by是没有任何意义的.
# 查询每一个部门的名称以及员工的平均薪水
# select dep,Avg(salary) from emp group by dep
ret = Emp.objects.values( "dep" ).annotate(avg_salary = Avg( "salary" ))
print (ret) # <QuerySet [{'avg_salary': 5000.0, 'dep': '保安部'}, {'avg_salary': 51000.0, 'dep': '教学部'}]>
# 查询每一个省份的名称以及员工数
ret = Emp.objects.values( "province" ).annotate(c = Count( "id" ))
print (ret) # <QuerySet [{'province': '山东省', 'c': 2}, {'province': '河北省', 'c': 1}]>
# 补充知识点:
# ret=Emp.objects.all()
# print(ret) # select * from emp
# ret=Emp.objects.values("name")
# print(ret) # select name from emp
return HttpResponse( 'OK' )
|
多表操作
一、创建表
- id字段是自动添加的
- 对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名
- 外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
from django.db import models
# Create your models here.
from django.db import models
'''
Book ---- Publish 一对多
'''
class Author(models.Model):
nid = models.AutoField(primary_key = True )
name = models.CharField( max_length = 32 )
age = models.IntegerField()
# 一对一
authordetail = models.OneToOneField(to = "AuthorDetail" ,to_field = "nid" ,on_delete = models.CASCADE)
def __str__( self ):
return self .name
# 作者详情表
class AuthorDetail(models.Model):
nid = models.AutoField(primary_key = True )
birthday = models.DateField()
telephone = models.BigIntegerField()
addr = models.CharField( max_length = 64 )
# 出版社表
class Publish(models.Model):
nid = models.AutoField(primary_key = True )
name = models.CharField( max_length = 32 )
city = models.CharField( max_length = 32 )
email = models.EmailField()
def __str__( self ):
return self .name
class Book(models.Model):
nid = models.AutoField(primary_key = True )
title = models.CharField( max_length = 32 )
publishDate = models.DateField()
price = models.DecimalField(max_digits = 5 ,decimal_places = 2 )
# 一对多关系
publish = models.ForeignKey(to = "Publish" ,to_field = "nid" ,on_delete = models.CASCADE,)
'''
publish_id INT ,
FOREIGN KEY (publish_id) REFERENCES publish(id)
'''
#多对多
authors = models.ManyToManyField(to = "Author" )
'''
CREATE TABLE book_authors(
id INT PRIMARY KEY auto_increment ,
book_id INT ,
author_id INT ,
FOREIGN KEY (book_id) REFERENCES book(id),
FOREIGN KEY (author_id) REFERENCES author(id)
)
'''
# class Book2Author(models.Model):
#
# nid = models.AutoField(primary_key=True)
# book=models.ForeignKey(to="Book")
# author=models.ForeignKey(to="Author")
def __str__( self ):
return self .title
|
二、增
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
from django.shortcuts import render, HttpResponse
from app01.models import *
def add(request):
# -------------------------一对多的关系-------------------------
#方式1:
#为book表绑定出版社: book --- publish
book_obj = Book.objects.create(title = "红楼梦" ,price = 100 ,publishDate = "2012-12-12" ,publish_id = 1 )
print (book_obj.title)
#方式2:
#pub_obj = Publish.objects.get(nid=1)
pub_obj = Publish.objects. filter (nid = 1 ).first()
book_obj = Book.objects.create(title = "三国演绎" ,price = 100 ,publishDate = "2012-12-12" ,publish = pub_obj)
print (book_obj.publish) # 与这本书籍关联的出版社对象
print (book_obj.publish_id)
# -------------------------多对多的关系-------------------------
book_obj = Book.objects.create(title = "python全栈开发" ,price = 100 ,publishDate = "2012-12-12" ,publish_id = 1 )
egon = Author.objects.get(name = "egon" )
alex = Author.objects.get(name = "alex" )
#绑定多对多关系的API
book_obj.authors.add(egon,alex)
book_obj.authors.add( 1 , 2 , 3 )
book_obj.authors.add( * [ 1 , 2 , 3 ])
#解除多对多关系
book_obj = Book.objects. filter (nid = 4 ).first()
book_obj.authors.remove( 2 )
#book_obj.authors.remove(*[1,2]) # 将某个特定的对象从被关联对象集合中去除。
book_obj.authors.clear() # 清空被关联对象集合
book_obj.authors. set () # 先清空再设置
return HttpResponse( "OK" )
|
三、删
1
2
3
|
def delete_book(request,delete_book_id):
Book.objects. filter (pk = delete_book_id).delete()
return redirect( "/books/" )
|
四、改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
def change_book(request,edit_book_id):
edit_book_obj = Book.objects. filter (pk = edit_book_id).first()
if request.method = = "POST" :
title = request.POST.get( "title" )
price = request.POST.get( "price" )
pub_date = request.POST.get( "pub_date" )
# 多对一
publish_id = request.POST.get( "publish_id" )
#多对多
authors_id_list = request.POST.getlist( "authors_id_list" ) # checkbox,select
Book.objects. filter (pk = edit_book_id).update(title = title,price = price,publishDate = pub_date,publish_id = publish_id)
# edit_book_obj.authors.clear()
# edit_book_obj.authors.add(*authors_id_list)
#多对多
edit_book_obj.authors. set (authors_id_list)
return redirect( "/books/" )
publish_list = Publish.objects. all ()
author_list = Author.objects. all ()
return render(request, "editbook.html" ,{ "edit_book_obj" :edit_book_obj, "publish_list" :publish_list, "author_list" :author_list})
|
五、查
1、基于对象的跨表查询(子查询)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
A - B
关联属性在A表中
正向查询: A - - - - - - >B
反向查询: B - - - - - - >A
基于对象的跨表查询(子查询)
# 一对多查询
正向查询:按字段
反向查询:表名小写_set. all ()
book_obj.publish
Book(关联属性:publish)对象 - - - - - - - - - - - - - - > Publish对象
< - - - - - - - - - - - - - -
publish_obj.book_set. all () # queryset
# 多对多查询
正向查询:按字段
反向查询:表名小写_set. all ()
book_obj.authors. all ()
Book(关联属性:authors)对象 - - - - - - - - - - - - - - - - - - - - - - - - > Author对象
< - - - - - - - - - - - - - - - - - - - - - - - -
author_obj.book_set. all () # queryset
# 一对一查询
正向查询:按字段
反向查询:表名小写
author.authordetail
Author(关联属性:authordetail)对象 - - - - - - - - - - - - - - - - - - - - - - - - >AuthorDetail对象
< - - - - - - - - - - - - - - - - - - - - - - - -
authordetail.author
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
from django.shortcuts import render, HttpResponse
from app01.models import *
def query(request):
# -------------------------基于对象的跨表查询(子查询)-----------------------
# 一对多查询的正向查询 : 查询python全栈开发这本书的出版社的名字
book_obj = Book.objects. filter (title = "python全栈开发" ).first()
print (book_obj.publish) # 与这本书关联的出版社对象
print (book_obj.publish.name)
# 一对多查询的反向查询 : 查询人民出版社出版过的书籍名称
publish = Publish.objects. filter (name = "人民出版社" ).first()
ret = publish.book_set. all ()
print (ret)
# 多对多查询的正向查询 : 查询python全栈开发这本书的所有作者的名字
book_obj = Book.objects. filter (title = "python全栈开发" ).first()
author_list = book_obj.authors. all () # queryset对象 [author_obj1,...]
for author in author_list:
print (author.name)
# 多对多查询的反向查询 : 查询alex出版过的所有书籍名称
alex = Author.objects. filter (name = "alex" ).first()
book_list = alex.book_set. all ()
for book in book_list:
print (book.title)
# 一对一查询的正向查询 : 查询alex的手机号
alex = Author.objects. filter (name = "alex" ).first()
print (alex.authordetail.telephone)
# 一对一查询的反向查询 : 查询手机号为110的作者的名字和年龄
ad = AuthorDetail.objects. filter (telephone = "110" ).first()
print (ad.author.name)
print (ad.author.age)
return HttpResponse( "ok" )
|
2、基于双下划线的跨表查询
1
2
3
4
5
6
7
8
|
A - B
关联属性在A表中
正向查询: A - - - - - - >B
反向查询: B - - - - - - >A
基于双下划线的跨表查询(join查询)
key:正向查询按字段,反向查询按表名小写
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
from django.shortcuts import render, HttpResponse
from app01.models import *
def query(request):
# -------------------------基于双下划线的跨表查询(join查询)-----------------------
'''
正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表
'''
# 一对多查询 : 查询python全栈开发这本书的出版社的名字
# 方式1:
ret = Book.objects. filter (title = "python全栈开发" ).values( "publish__name" )
print (ret) # <QuerySet [{'publish__name': '南京出版社'}]>
# 方式2:
ret = Publish.objects. filter (book__title = "python全栈开发" ).values( "name" )
print (ret)
# 多对多查询 : 查询python全栈开发这本书的所有作者的名字
# 方式1:
# 需求: 通过Book表join与其关联的Author表,属于正向查询:按字段authors通知ORM引擎join book_authors与author
ret = Book.objects. filter (title = "python全栈开发" ).values( "authors__name" )
print (ret) # <QuerySet [{'authors__name': 'alex'}, {'authors__name': 'egon'}]>
# 方式2:
# 需求: 通过Author表join与其关联的Book表,属于反向查询:按表名小写book通知ORM引擎join book_authors与book表
ret = Author.objects. filter (book__title = "python全栈开发" ).values( "name" )
print (ret) # <QuerySet [{'name': 'alex'}, {'name': 'egon'}]>
# 一对一查询的查询 : 查询alex的手机号
# 方式1:
# 需求: 通过Author表join与其关联的AuthorDetail表,属于正向查询:按字段authordetail通知ORM引擎join Authordetail表
ret = Author.objects. filter (name = "alex" ).values( "authordetail__telephone" )
print (ret) # <QuerySet [{'authordetail__telephone': 110}]>
# 方式2:
# 需求: 通过AuthorDetail表join与其关联的Author表,属于反向查询:按表名小写author通知ORM引擎join Author表
ret = AuthorDetail.objects. filter (author__name = "alex" ).values( "telephone" )
print (ret) # <QuerySet [{'telephone': 110}]>
# 进阶练习:(连续跨表)
# 练习: 手机号以110开头的作者出版过的所有书籍名称以及书籍出版社名称
# 方式1:
# 需求: 通过Book表join AuthorDetail表, Book与AuthorDetail无关联,所以必需连续跨表
ret = Book.objects. filter (authors__authordetail__telephone__startswith = "110" ).values( "title" , "publish__name" )
print (ret)
# 方式2:
ret = Author.objects. filter (authordetail__telephone__startswith = "110" ).values( "book__title" , "book__publish__name" )
print (ret)
return HttpResponse( "OK" )
|
3、聚合和分组查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
from django.shortcuts import render, HttpResponse
from app01.models import *
def query(request):
# ------------------------->聚合 aggregate:返回值是一个字典,不再是queryset
# 查询所有书籍的平均价格
from django.db.models import Avg, Max , Min , Count
ret = Book.objects. all ().aggregate(avg_price = Avg( "price" ), max_price = Max ( "price" ))
print (ret) # {'avg_price': 151.0, 'max_price': Decimal('301.00')}
ret = Book.objects.aggregate(Avg( 'price' ), Max ( 'price' ), Min ( 'price' ))
print (ret) # {'price__avg': 151.0, 'price__max': Decimal('301.00'), 'price__min': Decimal('12.99')}
# ------------------------->多表分组查询 annotate ,返回值依然是queryset
# 单表总结: objects.values("group by的字段").annotate(聚合函数("统计字段"))
# 多表总结:跨表的分组查询的模型:
# 方式1:每一个后的表模型.objects.values("pk").annotate(聚合函数(关联表__统计字段)).values("表模型的所有字段以及统计字段")
# 方式2:每一个后的表模型.objects.annotate(聚合函数(关联表__统计字段)).values("表模型的所有字段以及统计字段")
#################### 方式1: 跨表分组查询####################
#查询每一个出版社的名称以及出版的书籍个数
#法1:
ret = Publish.objects.values( "name" ).annotate(c = Count( "book__title" ))
print (ret) # <QuerySet [{'name': '人民出版社', 'c': 3}, {'name': '南京出版社', 'c': 1}]>
ret = Publish.objects.values( "nid" ).annotate(c = Count( "book__title" ))
print (ret) # <QuerySet [{'nid': 1, 'c': 3}, {'nid': 2, 'c': 1}]>
# 法2:
ret = Publish.objects.values( "nid" ).annotate(c = Count( "book__title" )).values( "name" , "c" )
print (ret) # <QuerySet [{'name': '人民出版社', 'c': 3}, {'name': '南京出版社', 'c': 1}]>
#查询每一个作者的名字以及出版过的书籍的最高价格
ret = Author.objects.values( "pk" ).annotate(max_price = Max ( "book__price" )).values( "name" , "max_price" )
print (ret)
#查询每一个书籍的名称以及对应的作者个数
ret = Book.objects.values( "pk" ).annotate(c = Count( "authors__name" )).values( "title" , "c" )
print (ret)
#################### 方式2: 跨表分组查询####################
# 示例1 查询每一个出版社的名称以及出版的书籍个数
# ret=Publish.objects.values("nid").annotate(c=Count("book__title")).values("name","email","c")
# ret=Publish.objects.all().annotate(c=Count("book__title")).values("name","c","city")
ret = Publish.objects.annotate(c = Count( "book__title" )).values( "name" , "c" , "city" )
print (ret)
##################### 练习 ####################
# 统计每一本以py开头的书籍的作者个数:
# 每一个后的表模型.objects.values("pk").annotate(聚合函数(关联表__统计字段)).values("表模型的所有字段以及统计字段")
ret = Book.objects. filter (title__startswith = "py" ).values( "pk" ).annotate(c = Count( "authors__name" )).values( "title" , "c" )
# 统计不止一个作者的图书
ret = Book.objects.values( "pk" ).annotate(c = Count( "authors__name" )). filter (c__gt = 1 ).values( "title" , "c" )
print (ret)
#根据一本图书作者数量的多少对查询集 QuerySet进行排序:
ret = Book.objects.annotate(num_authors = Count( 'authors' )).order_by( 'num_authors' )
return HttpResponse( "查询成功" )
|
4、F 与 Q查询
使用F表达式引用模型的字段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
from django.shortcuts import render, HttpResponse
from app01.models import *
from django.db.models import F,Q
def query(request):
#################### F查询####################
#两个字段的值做比较, F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。
# 查询评论数大于收藏数的书籍
Book.objects. filter (commnetNum__lt = F( 'keepNum' ))
# 查询评论数大于收藏数2倍的书籍
Book.objects. filter (commnetNum__lt = F( 'keepNum' ) * 2 )
#修改操作也可以使用F函数,比如将每一本书的价格提高30元:
Book.objects. all ().update(price = F( "price" ) + 30 )
####################Q查询####################
#filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q 对象。
#Q对象可以使用& 和| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。
bookList = Book.objects. filter (Q(authors__name = "yuan" ) | Q(authors__name = "egon" ))
#sql ...WHERE name ="yuan" OR name ="egon"
#Q对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询:
bookList = Book.objects. filter (Q(authors__name = "yuan" ) & ~Q(publishDate__year = 2017 )).values_list( "title" )
#混合使用Q对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。
bookList = Book.objects. filter (Q(publishDate__year = 2016 ) | Q(publishDate__year = 2017 ),
title__icontains = "python"
)
return HttpResponse( "查询成功" )
|
5、extra
有些情况下,Django的查询语法难以简单的表达复杂的 WHERE 子句,对于这种情况, Django 提供了 extra() QuerySet修改机制 它能在 QuerySet生成的SQL从句中注入新子句,extra可以指定一个或多个 参数,例如 select, where or tables.这些参数都不是必须的,但是你至少要使用一个!要注意这些额外的方式对不同的数据库引擎可能存在移植性问题.(因为你在显式的书写SQL语句),除非万不得已,尽量避免这样做.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
# 每一个后的表模型.objects.values("pk").annotate(聚合函数(关联表__统计字段)).values("表模型的所有字段以及统计字段")
# 查询每一个分类名称以及对应的文章数
ret = models.Category.objects.values( "pk" ).annotate(c = Count( "article__title" )).values( "title" , "c" )
# 查询当前站点的每一个分类名称以及对应的文章数
cate_list = models.Category.objects. filter (blog = blog).values( "pk" ).annotate(c = Count( "article__title" )).values_list( "title" , "c" )
# 查询当前站点的每一个标签名称以及对应的文章数
tag_list = models.Tag.objects. filter (blog = blog).values( "pk" ).annotate(c = Count( "article" )).values_list( "title" , "c" )
# 查询当前站点每一个年月的名称以及对应的文章数
"""
extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
参数之select
The select 参数可以让你在 SELECT 从句中添加其他字段信息,它应该是一个字典,存放着属性名到 SQL 从句的映射。
queryResult=models.Article
.objects.extra(select={'is_recent': "create_time > '2017-09-05'"})
结果集中每个 Entry 对象都有一个额外的属性is_recent, 它是一个布尔值,表示 Article对象的create_time 是否晚于2017-09-05.
"""
ret = models.Article.objects.extra(select = { "is_recent" : "create_time > '2018-09-05'" }).values( "title" , "is_recent" )
# 方式1:
# mysql
date_list = models.Article.objects. filter (user = user).extra(select = { "y_m_date" : "date_format(create_time,'%%Y/%%m')" }
).values( "y_m_date" ).annotate(c = Count( "nid" )).values_list( "y_m_date" , "c" )
# sqlite
date_list = models.Article.objects. filter (user = user).extra(select = { "y_m_date" : "strftime('%%Y/%%m',create_time)" }
).values( "y_m_date" ).annotate(c = Count( "nid" )).values_list( "y_m_date" , "c" )
# 方式2:
from django.db.models.functions import TruncMonth
ret = models.Article.objects. filter (user = user).annotate(month = TruncMonth( "create_time" )).values( "month" ).annotate(c = Count( "nid" )).values_list( "month" , "c" )
# 日期归档查询的方式2
from django.db.models.functions import TruncMonth
"""
Sales.objects
.annotate(month=TruncMonth('timestamp')) # Truncate to month and add to select list
.values('month') # Group By month
.annotate(c=Count('id')) # Select the count of the grouping
.values('month', 'c') # (might be redundant, haven't tested) select month and count
"""
"""
参数之where
"""
val = "2018-10"
# mysql
all_count = models.Article.objects. filter (blog = blog).extra(
where = [ 'date_format(create_time,"%%Y-%%m")=%s' ], params = [val, ]).count()
article_list = models.Article.objects. filter (blog = blog).extra(
where = [ 'date_format(create_time,"%%Y-%%m")=%s' ], params = [val, ])[page_info.start():page_info.end()]
# sqlite
all_count = models.Article.objects. filter (blog = blog).extra(
where = [ 'strftime("%%Y-%%m",create_time)=%s' ], params = [val, ]).count()
article_list = models.Article.objects. filter (blog = blog).extra(
where = [ 'strftime("%%Y-%%m",create_time)=%s' ], params = [val, ])[page_info.start():page_info.end()]
#直接写sql语句
# mysql
cursor = connection.cursor()
sql = 'select count(1) as nm,date_format(create_time,"%%Y-%%m") as ctime from article where blog_id= %s group by date_format(create_time,"%%Y-%%m")'
cursor.execute(sql,(blog.nid,))
date_list = cursor.fetchall()
# sqlite
date_list = models.Article.objects.raw(
'select nid, count(1) as num,strftime("%Y-%m",create_time) as ctime from article group by strftime("%Y-%m",create_time)' )
|
6、pk
主键的快捷查询方式:pk
7、blog
from django.db import models# from django.contrib.auth.models import AbstractUser # class UserInfo(AbstractUser): # """ # 用户信息 # """ # nid = models.AutoField(primary_key=True) # telephone = models.CharField(max_length=11, null=True, unique=True) # avatar = models.FileField(upload_to='avatars/', default="avatars/default.png") # create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True) # # blog = models.OneToOneField(to='Blog', to_field='nid', null=True, on_delete=models.CASCADE) # # def __str__(self): # return self.username # # class Meta: # verbose_name = '个人博客信息' # verbose_name_plural = '博客信息'class UserInfo(models.Model):"""用户表"""nid = models.BigAutoField(primary_key=True)username = models.CharField(verbose_name='用户名', max_length=32, unique=True)password = models.CharField(verbose_name='密码', max_length=64)nickname = models.CharField(verbose_name='昵称', max_length=32)email = models.EmailField(verbose_name='邮箱', unique=True)avatar = models.FileField(verbose_name='头像',upload_to='avatars/', default="avatars/default.png")# 被传到`MEDIA_ROOT/uploads/2015/01/30`目录,增加了一个时间划分# avatar = models.FileField(upload_to='uploads/%Y/%m/%d/') create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)fans = models.ManyToManyField(verbose_name='粉丝们',to='UserInfo',through='UserFans',related_name='f',through_fields=('user', 'follower'))class Meta:verbose_name = '个人博客信息'verbose_name_plural = '博客信息'class Blog(models.Model):"""博客信息"""nid = models.BigAutoField(primary_key=True)title = models.CharField(verbose_name='个人博客标题', max_length=64)site = models.CharField(verbose_name='站点名称', max_length=32, unique=True)theme = models.CharField(verbose_name='博客主题', max_length=32)user = models.OneToOneField(to='UserInfo', to_field='nid',on_delete=models.CASCADE)theme_choices = [('default', "默认主题"),('bule', "蓝色主题"),('red', "红色主题"),]def __str__(self):return self.titleclass Meta:verbose_name = '个人博客信息'verbose_name_plural = '博客信息'class UserFans(models.Model):"""互粉关系表"""user = models.ForeignKey(verbose_name='博主', to='UserInfo', to_field='nid', related_name='users',on_delete=models.CASCADE)follower = models.ForeignKey(verbose_name='粉丝', to='UserInfo', to_field='nid', related_name='followers',on_delete=models.CASCADE)class Meta:verbose_name = '互粉关系'verbose_name_plural = '互粉关系'unique_together = [('user', 'follower'),]class Category(models.Model):"""博主个人文章分类表"""nid = models.AutoField(primary_key=True)title = models.CharField(verbose_name='分类标题', max_length=32)parent = models.ForeignKey(verbose_name='父ID', to='Category', to_field='nid', on_delete=models.CASCADE, null=True)blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid',on_delete=models.CASCADE)class Meta:verbose_name = '文章分类'verbose_name_plural = '文章分类'class ArticleDetail(models.Model):"""文章详细表"""content = models.TextField(verbose_name='文章内容', )article = models.OneToOneField(verbose_name='所属文章', to='Article', to_field='nid',on_delete=models.CASCADE)class Meta:verbose_name = '文章详细'verbose_name_plural = '文章详细'class UpDown(models.Model):"""文章顶或踩"""article = models.ForeignKey(verbose_name='文章', to='Article', to_field='nid',on_delete=models.CASCADE)user = models.ForeignKey(verbose_name='赞或踩用户', to='UserInfo', to_field='nid',on_delete=models.CASCADE)up = models.BooleanField(verbose_name='是否赞')class Meta:verbose_name = '文章顶踩'verbose_name_plural = '文章顶踩'unique_together = [('article', 'user'),]class Comment(models.Model):"""评论表"""nid = models.BigAutoField(primary_key=True)content = models.CharField(verbose_name='评论内容', max_length=255)create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)reply = models.ForeignKey(verbose_name='回复评论', to='self', related_name='back', null=True,on_delete=models.CASCADE)article = models.ForeignKey(verbose_name='评论文章', to='Article', to_field='nid',on_delete=models.CASCADE)user = models.ForeignKey(verbose_name='评论者', to='UserInfo', to_field='nid',on_delete=models.CASCADE)class Meta:verbose_name = '文章评论'verbose_name_plural = '文章评论'class Tag(models.Model):nid = models.AutoField(primary_key=True)title = models.CharField(verbose_name='标签名称', max_length=32)blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid',on_delete=models.CASCADE)class Meta:verbose_name = '文章标签'verbose_name_plural = '文章标签'class Article(models.Model):nid = models.BigAutoField(primary_key=True)title = models.CharField(verbose_name='文章标题', max_length=128)summary = models.CharField(verbose_name='文章简介', max_length=255)read_count = models.IntegerField(default=0)comment_count = models.IntegerField(default=0)up_count = models.IntegerField(default=0)down_count = models.IntegerField(default=0)create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid',on_delete=models.CASCADE)category = models.ForeignKey(verbose_name='文章类型', to='Category', to_field='nid', null=True,on_delete=models.CASCADE)type_choices = [(1, "编程语言"),(2, "操作系统"),(3, "Web前端"),(4, "数据库"),(5, "English"),(6, "其他分类"),]article_type_id = models.IntegerField(choices=type_choices, default=None)tags = models.ManyToManyField(to="Tag",through='Article2Tag',through_fields=('article', 'tag'),)class Meta:verbose_name = '文章信息'verbose_name_plural = '文章信息'class Article2Tag(models.Model):article = models.ForeignKey(verbose_name='文章', to="Article", to_field='nid',on_delete=models.CASCADE)tag = models.ForeignKey(verbose_name='标签', to="Tag", to_field='nid',on_delete=models.CASCADE)class Meta:verbose_name = '文章与标签'verbose_name_plural = '文章与标签'unique_together = [('article', 'tag'),]class Tpl(models.Model):user = models.ForeignKey(UserInfo, on_delete=models.CASCADE)title = models.CharField(max_length=32)content = models.TextField()class Trouble(models.Model):title = models.CharField(max_length=32)detail = models.TextField()user = models.ForeignKey(UserInfo,related_name='u',on_delete=models.CASCADE)# ctime = models.CharField(max_length=32) # 1491527007.452494ctime = models.DateTimeField()status_choices = ((1,'未处理'),(2,'处理中'),(3,'已处理'),)status = models.IntegerField(choices=status_choices,default=1)processer = models.ForeignKey(UserInfo,related_name='p',null=True,blank=True,on_delete=models.CASCADE)solution = models.TextField(null=True)ptime = models.DateTimeField(null=True)pj_choices = ((1, '不满意'),(2, '一般'),(3, '很满意'),)pj = models.IntegerField(choices=pj_choices,null=True,default=2)""" form中: from django.forms import fieldstheme = fields.ChoiceField(choices=models.Blog.theme_choices,widget=widgets.Select(attrs={'class': 'form-control'})) 模板中: {{ form.theme }}models中:status_choices = ((1,'未处理'),(2,'处理中'),(3,'已处理'),)status = models.IntegerField(choices=status_choices,default=1)ptime = models.DateTimeField(null=True,blank=True)views中:dic['ptime'] = datetime.datetime.now()模板中: {% for row in result %} <td>{{ row.get_status_display }}</td> {% endfor %}models中:type_choices = [(1, "编程语言"),(2, "操作系统"),(3, "Web前端"),(4, "数据库"),(5, "English"),(6, "其他分类"),]views:article_type_list = models.Article.type_choices"""
blog models
import osif __name__ == "__main__":os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_contenttype.settings")import djangodjango.setup()from app01.models import Post, Picture, Commentfrom django.contrib.auth.models import User# 准备测试数据user_1 = User.objects.create_user(username='aaa', password='123')user_2 = User.objects.create_user(username='bbb', password='123')user_3 = User.objects.create_user(username='ccc', password='123')post_1 = Post.objects.create(author=user_1, title='Python入门教程')post_2 = Post.objects.create(author=user_2, title='Python进阶教程')post_3 = Post.objects.create(author=user_1, title='Python入土教程')picture_1 = Picture.objects.create(author=user_1, image='小姐姐01.jpg')picture_2 = Picture.objects.create(author=user_1, image='小姐姐02.jpg')picture_3 = Picture.objects.create(author=user_3, image='小哥哥01.jpg')# 给帖子创建评论数据comment_1 = Comment.objects.create(author=user_1, content='好文!', content_object=post_1)# 给图片创建评论数据comment_2 = Comment.objects.create(author=user_2, content='好美!', content_object=picture_1)
django.setup()
六、模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
<!--查看所有 views.py 传过来的book_list book_list=Book.objects.all()-->
< tbody >
{% for book in book_list %}
< tr >
< td >{{ forloop.counter }}</ td >
< td >{{ book.title }}</ td >
< td >{{ book.price }}</ td >
< td >{{ book.publishDate|date:"Y-m-d" }}</ td >
< td >
{{ book.publish.name }}
</ td >
< td >
{% for author in book.authors.all %}
{% if forloop.last %}
< span >{{ author.name }}</ span >
{% else %}
< span >{{ author.name }}</ span >,
{% endif %}
{% endfor %}
</ td >
< td >
< a href="/books/{{ book.pk }}/change/" class="btn btn-warning">编辑</ a >
< a href="/books/{{ book.pk }}/delete/" class="btn btn-danger">删除</ a >
</ td >
</ tr >
{% endfor %}
</ tbody >
<!--编辑 views.py 传过来的edit_book_obj publish_list=Publish.objects.all() author_list=Author.objects.all()-->
< form action="" method="post">
{% csrf_token %}
< div class="form-group">
< label for="">名称</ label >
< input type="text" name="title" class="form-control" value="{{ edit_book_obj.title }}">
</ div >
< div class="form-group">
< label for="">价格</ label >
< input type="text" name="price" class="form-control" value="{{ edit_book_obj.price }}">
</ div >
< div class="form-group">
< label for="">出版日期</ label >
< input type="date" name="pub_date" class="form-control"
value="{{ edit_book_obj.publishDate|date:'Y-m-d' }}">
</ div >
< div class="form-group">
< label for="">出版社</ label >
< select name="publish_id" id="" class="form-control">
{% for publish in publish_list %}
{% if edit_book_obj.publish == publish %}
< option selected value="{{ publish.pk }}">{{ publish.name }}</ option >
{% else %}
< option value="{{ publish.pk }}">{{ publish.name }}</ option >
{% endif %}
{% endfor %}
</ select >
</ div >
< div class="form-group">
< label for="">作者</ label >
< select type="text" name="authors_id_list" multiple class="form-control">
{% for author in author_list %}
{% if author in edit_book_obj.authors.all %}
< option selected value="{{ author.pk }}">{{ author.name }}</ option >
{% else %}
< option value="{{ author.pk }}">{{ author.name }}</ option >
{% endif %}
{% endfor %}
</ select >
</ div >
< input type="submit" class="btn btn-default">
</ form >
|
七、返回新QuerySets的API
方法名 | 解释 |
---|---|
filter() | 过滤查询对象。 |
exclude() | 排除满足条件的对象 |
annotate() | 使用聚合函数 |
order_by() | 对查询集进行排序 |
reverse() | 反向排序 |
distinct() | 对查询集去重 |
values() | 返回包含对象具体值的字典的QuerySet |
values_list() | 与values()类似,只是返回的是元组而不是字典。 |
dates() | 根据日期获取查询集 |
datetimes() | 根据时间获取查询集 |
none() | 创建空的查询集 |
all() | 获取所有的对象 |
union() | 并集 |
intersection() | 交集 |
difference() | 差集 |
select_related() | 附带查询关联对象 |
prefetch_related()
|
预先查询 |
extra() | 附加SQL查询 |
defer() | 不加载指定字段 |
only() | 只加载指定的字段 |
using() | 选择数据库 |
select_for_update()
|
锁住选择的对象,直到事务结束。 |
raw() | 接收一个原始的SQL查询 |
八、不返回QuerySets的API
方法名 | 解释 |
---|---|
get() | 获取单个对象 |
create() | 创建对象,无需save() |
get_or_create() | 查询对象,如果没有找到就新建对象 |
update_or_create() | 更新对象,如果没有找到就创建对象 |
bulk_create()
|
批量创建对象 |
count() | 统计对象的个数 |
in_bulk()
|
根据主键值的列表,批量返回对象 |
iterator()
|
获取包含对象的迭代器 |
latest() | 获取最近的对象 |
earliest() | 获取最早的对象 |
first() | 获取第一个对象 |
last() | 获取最后一个对象 |
aggregate() | 聚合操作 |
exists() | 判断queryset中是否有对象 |
update() | 批量更新对象 |
delete() | 批量删除对象 |
as_manager() | 获取管理器 |
九、字段查询参数及聚合函数
字段查询是指如何指定SQL WHERE子句的内容。它们用作QuerySet的filter(), exclude()和get()方法的关键字参数。
字段名 | 说明 |
---|---|
exact | 精确匹配 |
iexact | 不区分大小写的精确匹配 |
contains | 包含匹配 |
icontains | 不区分大小写的包含匹配 |
in | 在..之内的匹配 |
gt | 大于 |
gte | 大于等于 |
lt | 小于 |
lte | 小于等于 |
startswith | 从开头匹配 |
istartswith | 不区分大小写从开头匹配 |
endswith | 从结尾处匹配 |
iendswith | 不区分大小写从结尾处匹配 |
range | 范围匹配 |
date | 日期匹配 |
year | 年份 |
month | 月份 |
day | 日期 |
week | 第几周 |
week_day | 周几 |
time | 时间 |
hour | 小时 |
minute | 分钟 |
second | 秒 |
isnull | 判断是否为空 |
search | 1.10中被废弃 |
regex | 区分大小写的正则匹配 |
iregex | 不区分大小写的正则匹配 |
转载于:https://www.cnblogs.com/bubu99/p/10256917.html
Django 模型层相关推荐
- Web开发-Django模型层
Django模型层 简述 Django框架处理业务的逻辑一般如下(省略图,源于网络,侵删) 可以看到,Django自带了一套ORM机制,这也是Django框架的核心-"全面",将一 ...
- Django基础五之Django模型层(二)多表操作
Django基础五之Django模型层(二)多表操作 一 创建模型 表和表之间的关系 一对一.多对一.多对多 # 作者表 比较常用的信息放在这个表中 class Author(models.Model ...
- Django 模型层(models) 复杂查询详解
Django 模型层(models) 复杂查询详解 一般Django orm 和原生sql混合使用 1.测试文件 只单独测试django中的某一个py文件 不一定是tests.py 1.配置 在任意一 ...
- Django–模型层orm查询
文章目录 Django–模型层orm查询 一.单表查询(增.删.改.查) 基本查询 下划线查询 二.外键字段(增.删.改.查) 一对多 多对多 三.多表查询 多表查询的方式 正反向的概念 基于对象的跨 ...
- 3.1.8 Django模型层详细应用
在这里肯定有小伙伴会说,前面不是已经引用了模型层了吗?并且在模型层中完成了数据库的操作了呀,为什么还要讲模型层? 首先呢,前面属于我们最传统的处理方式,那种方式过于麻烦,无法很好处理数据.模型层真正应 ...
- python代码函数字符查询宝典书籍_Django基础五之django模型层(一)单表操作
二 单表操作 一.创建表 创建模型 创建名为book的app,在book下的models.py中创建模型: from django.db importmodels#Create your models ...
- Django模型层Meta内部类详解
Django 模型类的Meta是一个内部类,它用于定义一些Django模型类的行为特性.以下对此作一总结: abstract 这个属性是定义当前的模型类是不是一个抽象类.所谓抽象类是不会对应 ...
- Django 模型层(1)
知识预览 ORM简介 单表操作 章节作业 回到顶部 ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单 ...
- 9 Django 模型层(2)
多表操作 创建模型 实例:我们来假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄. 作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息.作者详情模型和作者模型之间是一对 ...
- 8 Django 模型层(2)
知识预览 多表操作 创建模型 实例:我们来假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄. 作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息.作者详情模型和作者模型 ...
最新文章
- 专注力 化繁为简的惊人力量
- [剑指offer]面试题42:翻转单词顺序 VS左旋转字符串
- linux 编辑启动菜单,grub2的配置,linux启动菜单修改
- shell 常用命令
- 容器技术Docker K8s 3 容器技术基础-Docker
- weblogic12C安装
- 通信原理 概念 笔记
- 智慧工地解决方案施工升降机智能监控系统
- 通州区机器人比赛活动总结_机器人社团活动课总结
- word论文排版插件_Word排插件 一键搞定论文、标书、报告、公文等排版
- 批量转换文件编码(By notepad++)
- python package什么意思_Python模块、包(Package)概念与用法分析
- 最佳视频转换器:Filmage Converter Mac
- 模拟银行转账取款存款
- Java泛型类,方法使用,Java继承的歪解
- DIY一块DS3231的高精度时钟模块,让时钟DS3231/DS1302自动识别
- c语言中的牛顿割线法
- XSHELL搭建跳板机
- 带你零基础学习跨境电商!
- CMfg-SC(云制造服务组合)、DRL、DQN的定义