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中配置:

+ View Code?
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 模型层相关推荐

  1. Web开发-Django模型层

    Django模型层 简述 Django框架处理业务的逻辑一般如下(省略图,源于网络,侵删) 可以看到,Django自带了一套ORM机制,这也是Django框架的核心-"全面",将一 ...

  2. Django基础五之Django模型层(二)多表操作

    Django基础五之Django模型层(二)多表操作 一 创建模型 表和表之间的关系 一对一.多对一.多对多 # 作者表 比较常用的信息放在这个表中 class Author(models.Model ...

  3. Django 模型层(models) 复杂查询详解

    Django 模型层(models) 复杂查询详解 一般Django orm 和原生sql混合使用 1.测试文件 只单独测试django中的某一个py文件 不一定是tests.py 1.配置 在任意一 ...

  4. Django–模型层orm查询

    文章目录 Django–模型层orm查询 一.单表查询(增.删.改.查) 基本查询 下划线查询 二.外键字段(增.删.改.查) 一对多 多对多 三.多表查询 多表查询的方式 正反向的概念 基于对象的跨 ...

  5. 3.1.8 Django模型层详细应用

    在这里肯定有小伙伴会说,前面不是已经引用了模型层了吗?并且在模型层中完成了数据库的操作了呀,为什么还要讲模型层? 首先呢,前面属于我们最传统的处理方式,那种方式过于麻烦,无法很好处理数据.模型层真正应 ...

  6. python代码函数字符查询宝典书籍_Django基础五之django模型层(一)单表操作

    二 单表操作 一.创建表 创建模型 创建名为book的app,在book下的models.py中创建模型: from django.db importmodels#Create your models ...

  7. Django模型层Meta内部类详解

    Django 模型类的Meta是一个内部类,它用于定义一些Django模型类的行为特性.以下对此作一总结: abstract      这个属性是定义当前的模型类是不是一个抽象类.所谓抽象类是不会对应 ...

  8. Django 模型层(1)

    知识预览 ORM简介 单表操作 章节作业 回到顶部 ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单 ...

  9. 9 Django 模型层(2)

    多表操作 创建模型 实例:我们来假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄. 作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息.作者详情模型和作者模型之间是一对 ...

  10. 8 Django 模型层(2)

    知识预览 多表操作 创建模型 实例:我们来假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄. 作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息.作者详情模型和作者模型 ...

最新文章

  1. 专注力 化繁为简的惊人力量
  2. [剑指offer]面试题42:翻转单词顺序 VS左旋转字符串
  3. linux 编辑启动菜单,grub2的配置,linux启动菜单修改
  4. shell 常用命令
  5. 容器技术Docker K8s 3 容器技术基础-Docker
  6. weblogic12C安装
  7. 通信原理 概念 笔记
  8. 智慧工地解决方案施工升降机智能监控系统
  9. 通州区机器人比赛活动总结_机器人社团活动课总结
  10. word论文排版插件_Word排插件 一键搞定论文、标书、报告、公文等排版
  11. 批量转换文件编码(By notepad++)
  12. python package什么意思_Python模块、包(Package)概念与用法分析
  13. 最佳视频转换器:Filmage Converter Mac
  14. 模拟银行转账取款存款
  15. Java泛型类,方法使用,Java继承的歪解
  16. DIY一块DS3231的高精度时钟模块,让时钟DS3231/DS1302自动识别
  17. c语言中的牛顿割线法
  18. XSHELL搭建跳板机
  19. 带你零基础学习跨境电商!
  20. CMfg-SC(云制造服务组合)、DRL、DQN的定义

热门文章

  1. javascript读写二进制
  2. 正则表达式校验邮箱号、手机号、身份证号码等等
  3. 【 C++ 】红黑树
  4. 《无人驾驶》-了解无人驾驶最佳读物
  5. tyvj 2075 借教室 题解
  6. oracle 按照lead,Oracle之Lead和Lag偏移量函数使用详解
  7. 《div图层被鼠标划过时其背景色变色的五种方式》
  8. 云创冬日紫金山踏雪游记
  9. Mysql 的自增主键达到最大值,怎么办
  10. idea提交本地项目到oschina