zoukankan      html  css  js  c++  java
  • Django --ORM

    创建表参考:

    # 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以上还要注释掉:
    ..Python37Libsite-packagesdjangodbackendsmysqlase.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")


  • 相关阅读:
    SQL Server 2008 R2英文版安装图解
    浅析在C#里面抛出SAP里面自定义的异常信息
    JavaScript中的函数基础
    《冷眼看IT》读书笔记IT将成为服务行业
    JavaScript入门
    IT成为第五个服务业
    JavaScript中匿名函数的困惑
    自定义的html radio button的样式
    探索客户端JavaScript
    JavScript中的循环
  • 原文地址:https://www.cnblogs.com/staff/p/10708429.html
Copyright © 2011-2022 走看看