要一直走下去

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

创建表参考:

# Create your models here.
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)
    # models.ImageField也是这样用
    avatar = models.FileField(upload_to='avatars/',default='avatars/default_avatar.jpg')
    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 Blog(models.Model):
    '''博客信息表:个人站点表,每个用户对应一个博客'''
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='个人博客标题',max_length=64)
    site_name = models.CharField(verbose_name='站点名称',max_length=64)
    theme = models.CharField(verbose_name='博客主题',max_length=32)

    def __str__(self):
        return self.title

class Category(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)

    def __str__(self):
        return self.title

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)

    def __str__(self):
        return self.title

class Article(models.Model):
    '''文章表'''
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=50, verbose_name='文章标题')
    desc = models.CharField(max_length=255,verbose_name='文章描述')
    content = models.TextField(verbose_name='文章内容')
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)

    comment_count = models.IntegerField(default=0)
    up_count = models.IntegerField(default=0)
    down_count = models.IntegerField(default=0)

    user = models.ForeignKey(verbose_name='作者',to='UserInfo',to_field='nid',on_delete=models.CASCADE)
    category = models.ForeignKey(to='Category',to_field='nid',null=True,on_delete=models.CASCADE)
    tags = models.ManyToManyField(to='Tag',
                                  through='Article2Tag',
                                  through_fields=('article','tag'),)
    def __str__(self):
        return self.title
class Article2Tag(models.Model):
    nid = models.AutoField(primary_key=True)
    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: # 联合唯一
        unique_together = [
            ('article', 'tag'),
        ]
    def __str__(self):
        return self.article.title + '——' + self.tag.title

class ArticleUpDown(models.Model):
    '''点赞表'''
    nid = models.AutoField(primary_key=True)
    user = models.ForeignKey(to='UserInfo',null=True,on_delete=models.CASCADE)
    article = models.ForeignKey(to='Article',null=True,on_delete=models.CASCADE)
    is_up = models.BooleanField(default=True)

    class Meta:
        unique_together = [
            ('article', 'user'),
        ]
class Comment(models.Model):
    '''评论表'''
    nid = models.AutoField(primary_key=True)
    content = models.CharField(verbose_name='评论内容',max_length=255)
    create_time = models.DateTimeField(verbose_name='创建时间',auto_now_add=True)

    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)
    parent_comment = models.ForeignKey('self',null=True,on_delete=models.CASCADE)

    def __str__(self):
        return self.content

'''
python manage.py makemigrations时候会报错:
....
HINT: Add or change a related_name argument to the definition for 'UserInfo.user_permissions' or 'User.user_pe
rmissions'.
...
需要告诉Django,需要在settings.py里加上:
    AUTH_USER_MODEL = 'blog.UserInfo'
'''
models

 

一、单表操作

1.1创建表

1.2,单表增删改查

二,多表操作

2.1,多表操作--创建关联表

2.2,多表操作--添加,更新记录(一对多/多对多)

2.3,多表操作--基于对象的跨表查询(select嵌套)

2.4,多表操作--基于双下划线的跨表查询(join)

2.5,多表操作--聚合函数

2.6,多表操作--分组查询

2.7,多表操作--F查询与Q查询

2.8,(补)多表操作--列转行

2.9  (补)给查询结果增加字段extra 

3.0  (补)时区问题

3.1  (补)related_name, related_query_name, GenericRelation区别?

一、单表操作

字典格式的字段创建:
class UserInfo(models.Model):
...
level_choices = ((1,'T1'),(2,'T2'),(3,'T3'),)
level = models.IntegerField(verbose_name='级别',choices=level_choices)
...
显示列表页面渲染:
{%for row in UserInfo.objects.all()%}
  {{row.get_level_display}}
{%end for%}

1.1创建表

第一步、views.py里写表对应的类,例如:
from django.db import models
class Book(models.Model):
id=models.AutoField(primary_key=True)
title=models.CharField(max_length=32)
pub_date=models.DateField()
price=models.DecimalField(max_digits=8,decimal_places=2) #9999.99
publish=models.CharField(max_length=32)

第二步、settings.py里加两条
1,加项目名称app01,pycharm里面好像可以不加
2,
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'orm',
'USER': 'root',
'PASSWORD': 'mysql8',
'HOST': '127.0.0.1',
'PORT': 3306
}
}

Django的orm支持的数据库(对PostgreSQL支持最好):

  • 'django.db.backends.postgresql'
  • 'django.db.backends.mysql'
  • 'django.db.backends.sqlite3'
  • 'django.db.backends.oracle'

 

或者是DB2:要install  ibm_db and ibm_db_django

测试环境:python3.7  django2.2  ibm_db==3.0.1  ibm_db_django==1.2.0.0a0  DB2-v9.7

配置文件中必须要把:USE_TZ=False      否则进行migrate会报错,在数据库表生成的最后会报错:

ibm_db_dbi.ProgrammingError: ibm_db_dbi::ProgrammingError: Cursor cannot be closed; connection is no longer active.

原因是关闭游标前,连接已经不存在了。暂时想到的改一下源代码,将之前的那两行代码注释,应该不影响功能:

def close(self):
"""This method closes the cursor object. After this method is
called the cursor object is no longer usable. It takes no
arguments.

"""
messages = []
if self.conn_handler is None:
# self.messages.append(ProgrammingError("Cursor cannot be closed; connection is no longer active."))
# raise self.messages[len(self.messages) - 1]
print('====================DEBUG:"Cursor cannot be closed; connection is no longer active."')
return

其他数据库:https://docs.djangoproject.com/en/1.10/ref/databases/

    'db2': {
        'ENGINE'     : 'ibm_db_django',
        'NAME'       : 'SAMPLE',
        'USER'       : 'username',
        'PASSWORD'   : 'password',
        'HOST'       : '192.168.23.123',
        'PORT'       : '50000',
        'PCONNECT'   :  True,      #Optional property, by default it is false
    }

第三步、项目文件夹下的__init__.py里加:
import pymysql
pymysql.install_as_MySQLdb()

第四步、如果Python解释器是3.4以上且Django是2.0以上还要注释掉:
..\Python37\Lib\site-packages\django\db\backends\mysql\base.py里的
if version < (1, 3, 13):
  raise ImproperlyConfigured('mysqlclient 1.3.13 or newer is required; you have %s.' % Database.__version__)

如果报错:AttributeError: 'str' object has no attribute 'decode'

query = query.decode(errors=‘replace’)  将decode修改为encode即可
第五步、如果想打印ORM转换过程中的sql语句,需要在settings里写:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
第六步、在项目路径下顺序执行两条命令就把表生成好了
python manage.py makemigrations
python manage.py migrate

这时候除了类那张表Django还生成了其他表

1.2,单表增删改查

1、增加记录
有两种方式:
方式1:
from app01.models import Book
book1 = Book(title="python编程思想",price=100)
book1.save()
方式2:
# 执行后插入一条记录,返回这条记录的对象
book1 = Book.objects.create(title="python编程思想",price=100)

创建用户时,如果使用原生的Django-User表需要用create_user,如果用create创建的密码没有加密:

UserInfo.objects.create_user(username=user,password=pwd,email=email,avatar=avatar_obj)

2、查询

'''
要知道方法的返回值和方法的调用者
'''
<1> Book.objects.all(): 查询所有结果,返回一个QuerySet对象,类似于list,可以遍历切片或索引访问

<2> Book.objects.filter(**kwargs): 例如filter(price=100,title='go'),返回QuerySet对象
<3> Book.objects.get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个对象
如果符合筛选条件的对象超过一个或者没有都会抛出错误。
例如get(price=100,title='go')
<4> Book.objects.exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象,返回QuerySet对象
例如exclude(price=100)查出price<>100的
----------
(5) first()/last() 取第一个或最后一个,调用者是QuerySet,返回Book对象
(6) order_by(*field): 对查询结果排序,调用者是QuerySet,例如升序order_by("id") 降序order_by("-id")可以几个字段联合排序
(7) reverse(): 对查询结果反向排序,调用者是QuerySet
(8) count(): 返回QuerySet集合中的对象数
(9) exists(): 如果QuerySet包含数据,就返回True,否则返回False,由QuerySet调用
----------
<10> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
model的实例化对象,而是一个可迭代的字典序列,如果想取第一个:values(*field).first()
例如:拿QuerySet集合中所有对象的某几个字段,返回字典组成的QuerySet,由QuerySet对象调用
Book.objects.all().values("title","price")

<11> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列

(12) distinct(): 从返回结果中剔除重复纪录,配合values或values_list使用
.values(..).distinct()


单表查询之模糊查询
大于10且小于200
Book.objects.filter(price__gt=10, price__lt=200)
Book.objects.filter(price__range=[10,200])
以xx开头
Book.objects.filter(title__startwith="xx")
包含xx的
Book.objects.filter(title__contains="xx") 区分大小写
Book.objects.filter(title__icontains="xx") 不区分大小写
字段在集合内的
Book.objects.filter(price__in=[100,200,300])
年份等于xx的,date类型才有
Book.objects.filter(pub_date__year=2012)

 

删:对QuerySet进行操作,先查出来再删,返回删除的条数
QuerySet.delete()

改:对QuerySet进行操作
QuerySet.update(title="php")

二,多表操作

2.1,多表操作--创建关联表

一对一:(在有外键的表里加。数据库:authorDetail_id字段,关联表AuthorDetail的主键id,能使用on_delete属性)

authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE)    或者

authorDetail=models.ForeignKey(to="AuthorDetail",to_field="id",on_delete=models.CASCADE,unique=True)

一对多:(在有外键的表里加。数据库:customer_id字段,关联表Customer的主键id,能使用on_delete属性)

customer = models.ForeignKey(to="Customer",to_field="id",on_delete=models.CASCADE)

多对多:(随便在哪张表里加。生成新当前表和Order的关系表:xx2orders,只有三个字段,不能使用on_delete属性,是级联删除) 

orders = models.ManyToManyField(to="Order")

或者自己加第三张表(推荐,能使用on_delete属性):最好能给多对多关系添加联合约束

好处1,可以对某个外键设置on_delete,这样可以灵活配置通过一张表能级联删除,通过另一张表不能进行级联删除

好处2,可以设置联合主键,或者联合约束

class Order_To_Commodity(models.Model):
id = models.AutoField(primary_key=True) # 主键
order = models.ForeignKey(to="Order", to_field="id", on_delete=models.CASCADE)
commodity = models.ForeignKey(to="Commodity", to_field="id", on_delete=models.CASCADE)
comm_quantity = models.IntegerField()

on_delete字段含义:(以下都无法进行级联更新)

on_delete=models.CASCADE, # 无关联数据的,可删除;有关联数据的,可删除,是级联删除
on_delete=models.DO_NOTHING, # 无关联数据的,可删除;有关联数据的,不可删除跟PROTECT一样报错
on_delete=models.PROTECT, # 无关联数据的,可删除;有关联数据的,不可删除并引发错误ProtectedError

# models.ForeignKey('关联表', on_delete=models.SET_NULL, blank=True, null=True)
on_delete=models.SET_NULL, # 删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空,一对一同理)

# models.ForeignKey('关联表', on_delete=models.SET_DEFAULT, default='默认值')
on_delete=models.SET_DEFAULT, # 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值,一对一同理)

on_delete=models.SET, # 删除关联数据,
a. 与之关联的值设置为指定值,设置:models.SET(值)
b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

----------set可执行对象的使用------

**官方案例**
def get_sentinel_user():
return get_user_model().objects.get_or_create(username='deleted')[0]

class MyModel(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET(get_sentinel_user),
)
---------------------

2.2,多表操作--添加记录(一对多/多对多)

一对多添加记录
例如:客户表-Customer 订单表-Order

客户表:添加方法跟单表添加方法一样。
订单表:
方式1:
Order.objects.Create(addr='静安路12号',customer_id=1)
order_obj.customer # 可以访问,返回这个订单的客户对象;只有一个
方式2:
customer_obj=Customer.objects.filter(id=1).first()
order_obj = Order.object.Create(addr='静安路12号',customer=customer_obj)
order_obj.customer # 可以访问,返回这个订单的客户对象;只有一个


多对多添加记录
订单表(Order)/商品表(Comm)/(订单商品关系表Order_Comm)

给订单绑定2个商品
apple = Comm.objects.get(name="苹果")
pear = Comm.objects.get(name="梨子")
order1 = Order.object.get(order_num="2324232342")

order1.comms.add(apple, pear)
order1.comms.add(1, 2)
order1.comms.add(*[1, 2])

给订单解除商品
order1 = Order.object.get(order_num="2324232342") #先查出来
order1.comms.remove(1,2)
order1.comms.remove(*[1, 2])
order1.comms.clear() # 全解除

给订单更新商品

order1.comms.set(*[3, 4])

获取订单的所有商品
order1.comms.all() # QuerySet对象

 ---示例

def add(request): 
    G_title=request.POST.get('title')#-------值为:python书本 
    G_publish=request.POST.get('publish') #-------值为:1
    G_authors_list=request.POST.getlist('authors')#-------值为:[3,7]
 
 
    publish_obj=Publish.objects.get(id=G_publish)#查找Publish表对应id的obj   
    authors_obj_list=Author.objects.filter(id__in=G_authors_list)#查找Author表对应id的多个obj
 
    title       #-------普通字段
    publish     #-------一对多外键
    authors     #-------多对多外键
 
    book_obj=Book.objects.create(title=G_title,publish=publish_obj)#添加普通和一对多外键的值
    
 
    #添加多对多外键的值  如果添加重复的,数据库会自动忽略
方式一 book_obj.authors.add(*authors_obj_list) 方式二 for obj in authors_obj_list: book_obj.authors.add(obj) return redirect('/index/')

 多对多--反向修改:

    # 修改外键字段publish_id,赋值外键ID就行
    Book.objects.filter(id=id).update(title=title, unit_price=unit_price, publish_date=pub_date,publish_id=publish_id)
    # 获取当前要被添加书籍的作者
    authors_obj_now = Author.objects.filter(id__in=authors_id)
    # 获取之前被添加书籍的作者
    authors_obj_pre = Author.objects.filter(books__id=id)
    # 给之前的所有作者解绑当前书籍(id是书籍的主键)
    for author in authors_obj_pre:
        author.books.remove(id)
    # 给现在的所有作者绑定当前书籍
    for author in authors_obj_now:
        author.books.add(id)

 

2.3,多表操作--基于对象的跨表查询(select嵌套)

----------
A-B
外键在A表中
正向查询:A---->B 按字段
反向查询:B---->A 按表名:表名小写_set
----------

一对多:
客户表(Customer)/ 订单表(Order)
正向查询:查订单"dd123"的客户名称
c = Order.objects.filter(order_num="dd123").first()
name = c.name
反向查询:查客户"张三"的订单
c = Customer.objects.filter(name="张三").first()
orders = c.order_set.all() #QuerySet


多对多:
订单表(Order)/商品表(Comm)
class Comm(models.Model):
pass
Class Order(models.Model):
comms = models.ManyToManyField(to="Order")

正向查询:Order--->comms obj.comms.all()
反向查询:Comm--->orders obj.order_set.all()

正向查询:查订单"dd123"的所有的商品
o = Order.objects.filter(order_num="dd123").first()
comms = o.comms.all() #所有的商品
反向查询:查买了商品"苹果"的所有订单
c = Comm.objects.filter(name="苹果").first()
orders = c.order_set.all()

order= c.order_set.get(pk=1) #找其中的单个

 

一对一:
农户表(Farmer) / 农户详情表(FarmerDetail)
class Farmer(models.Model):
farmerdetail = models.OneToOneField(to="FarmerDetail",on_delete=models.CASCADE)
Class FarmerDetail(models.Model):
pass

正向查询:obj.farmerdetail
反向查询:obj.farmer

 

2.4,多表操作--基于双下划线的跨表查询(join)

正向查询按字段,反向查询按表名告诉orm引擎join哪张表。不区分一对多还是多对多还是一对一

双下划线还是单下划线?

当反向查询用表名时,

如果要查该表中的字段,就是单下划线;

如果要查该表中的外键表的字段,就是双下划线;

举例:
一对多:
查订单"dd123"的客户名称。有两种方式 (customer是字段名,order是表名)
name = Order.objects.filter(num="dd123").values("customer__name") # Order INNER JOIN Customer
name = Customer.objects.filter(order_num="dd123").values("name") # Customer INNER JOIN Order

 

多对多:
订单表(Order)/商品表(Comm)
class Comm(models.Model):
pass
Class Order(models.Model):
comms = models.ManyToManyField(to="Order")

查订单"dd123"的所有的商品名称,两种方式
Order.objects.filter(num="dd123").values(comms__name) 或者
Comm.objects.filter(order_num="dd123").values(name)

 

一对一:
农户表(Farmer) / 农户详情表(FarmerDetail)
class Farmer(models.Model):
farmerdetail = models.OneToOneField(to="FarmerDetail",on_delete=models.CASCADE)
Class FarmerDetail(models.Model):
pass

查农户"张三"的详情
Farmer.objects.filter(name="张三").values(farmerdetail__tel)
FarmerDetail.objects.filter(farmer_name="张三").values("tel")


连续跨表查询:
例如:手机号以110开头的作者出版过的所有书籍名称以及出版社名称
Book.objects.filter(authors__authordetail__telephone__startswith="110").values("title","publish__name")
或者
Author.objects.filter(authordetail__telephone__startswith="110").values("book__title","book__publish__name")

2.5,多表操作--聚合函数

from django.db.models import Avg,Max,Min,Count

Book.objects.all().aggregate(Avg("price")) #{'avg_price':151}

2.6,多表操作--分组查询

单表的分组查询
例如:查询每一个部门的名称以及员工的平均薪水
# select dep,Avg(salary) from emp group by dep
QuerySet = Emp.objects.values("dep").annotate(avg_salary=Avg("salary"))
Emp.objects.all().annotate(avg_salary=Avg("salary")) # 按所有字段分组,跟按主键分组是一样的
总结:
单表.objects.values("group by的分组字段").annotate(聚合函数("统计字段"))
在单表分组下,按主键进行group by没有意义


跨表分组查询
Book表与Publish表是一对多关系。书-出版社
示例1:查询每一个出版社的名称以及出版的书籍个数
Book.objects.filter("publish__name").annotate(c=Count("title"))
或者
Publish.objects.values("id").annotate(c=Count("book__title")).values("name","c")

示例2:查询每一个作者的名字以及出版过的书籍的最高价格
Book表(authors)与Author表是多对多关系
Author.objects.values("id").annotate(m=Max("book__price")).values("name","m")

总结:
每一个后表模型.objects.values("pk").annotate(聚合函数(关联表__统计字段))
每一个后表模型.objects.annotate(聚合函数(关联表__统计字段))

示例3:查询每一个书籍的名称以及对于的作者个数
Book.objects.values("pk").annotate(c=Count("authors__id")).values("title","c")

2.7,多表操作--F查询与Q查询

临时加字段:在类里加属性。要给默认值才行。
例如:select * from Book where comm_num > read_num
这种情况需要引用F函数
from django.db.models import F
Book.objects.filter(comm_num__gt=F("read_num"))
给所有价格+1
Book.objects.all().update(price=F("price")+1)

--更新单个实例

reporter = Reporters.objects.filter(name='Tintin')
reporter.update(stories_filed=F('stories_filed') + 1)

c = Comm.objects.filter(name="苹果").first()

order= c.order_set.get(pk=1) #找其中的单个

order.votes = F("votes") + 1

order.save()

--更新多个实例

Reporter.objects.all().update(stories_filed=F('stories_filed') + 1)


查询名字=红楼梦 或者 价格=101的书籍
Book.objects.filter(title="红楼梦", price=101) #这是且的关系
Book.objects.filter(Q(title="红楼梦")|Q(price=101)) #或的关系
Book.objects.filter(~Q(title="红楼梦")) #非的关系

2.8,(补)多表操作--列转行

例如:一本书有多个作者,按图书ID分组,每组的author列转行,用逗号分隔

先添加一个方法Concat:

from django.db.models import Aggregate, CharField

class Concat(Aggregate):
"""ORM用来分组显示其他字段 相当于group_concat"""
function = 'GROUP_CONCAT'
template = '%(function)s(%(distinct)s%(expressions)s)'

def __init__(self, expression, distinct=False, **extra):
super(Concat, self).__init__(
expression,
distinct='DISTINCT ' if distinct else '',
output_field=CharField(),
**extra)
查询:
books = Book.objects.values("id","title","unit_price","publish_date","publish__pub_name").annotate(auth_name=Concat("author__auth_name"))
print(books)

2.9  (补)给查询结果增加字段extra

假设:表table中有字段dt类型为datetime类型

有这样的SQL语句,select dt, date_format(dt,"%Y-%m-%d") from table (把datetime转换为date到新的视图字段)

Django orm如何实现呢?这就要用到extra了

  extra(select = None, where = None, params=None, tables=None, order_by = None, select_params = None)

  有些情况下,Django的查询语法难以简单的表达复杂的where子句,对于这种情况,Django提供了extra() 

  extra()的作用是对QuerySet的结果集进行修改。extra中的参数不是都必须的,但是至少要用一个。

  *参数之select: select参数可以让你在select从句中添加其他字段信息,它应该是一个字典,存放着属性名到SQL从句的映射。

  字典的value是一个SQL语句,用这个语句遍历queryResult得到结果放在字典的key(字段)里

  queryResult = models.Article.objects.extra( select = {'is_recent' : "create_time > '2017-09-05' "})

  结果集中每个Entry对象都有一个额外的属性is_recent, 它是一个布尔值,表示Article对象的create_time是否晚于2017-09-05

  上面可以这样修改:

    table.objects.extra( select = {"create_date" : "date_format(create_time,'%%Y-%%m-%%d')"} ).values("dt", "d")

 也可以这样用(官方文档):

  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')            # select month , c  

 

3.0  (补)时区问题

settings.py里:

1、数据库和前端显示时区不一致:

TIME_ZONE = 'Asia/Shanghai'

2、orm中datetime字段的create_time__month字段不好使:

USE_TZ = False

3.1  (补)related_name, related_query_name, GenericRelation区别?

class Author(models.Model):
    name = models.CharField(verbose_name='姓名', max_length=50)
    age = models.IntegerField(verbose_name='年龄')

class Book(models.Model):
    name = models.CharField(verbose_name='书名', max_length=100)
    author = models.ForeignKey(Author, verbose_name='作者', related_name='bs', related_query_name='b')  # 对OneToOneField和ManyToManyField同样适用

 

Author.objects.filter(b__name='learn_python')
#通过related_query_name查询书名为learn_python的作者

author = Author.objects.get(pk=1)
author.bs.all()
#通过related_name来查询该作者所有的书

看完上面就明白related_name与related_query_name的区别了

 

GenericRelation是GenericForeignKey的反向查询字段。只在使用了contenttypes才有用

class Course(models.Model):
    """免费课程表"""
    title = models.CharField(max_length=128, unique=True, verbose_name="课程的名称")
    
    # 只用于反向查询不生成字段
    price_policy = GenericRelation("PricePolicy")   # 用法:course_obj.price_policy.all()

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "免费课程表"
        db_table = verbose_name
        verbose_name_plural = verbose_name

 

class PricePolicy(models.Model):
    """价格策略表"""
    content_type = models.ForeignKey(ContentType, on_delete=None)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey("content_type", "object_id")
    VALID_PERIOD_CHOICES = ((1, "1天"), (3, "3天"),(7, "7天"), (14, "2周"),(30, "1个月"))
    valid_period = models.SmallIntegerField(choices=VALID_PERIOD_CHOICES)
    price = models.FloatField()

    def __str__(self):
        return "%s(%s)%s" % (self.content_object, self.get_valid_period_display(), self.price)

    class Meta:
        verbose_name = "价格策略表"
        db_table = verbose_name
        verbose_name_plural = verbose_name
        """同样的课程周期不能重复"""
        unique_together = ("content_type", "object_id", "valid_period")

 

 

 

 

 



posted on 2019-04-15 00:34  要一直走下去  阅读(491)  评论(0编辑  收藏  举报