• [Django笔记] models 深入学习


    对着官方文档撸一遍,顺便做点笔记

    models 定义了本应用的数据库表结构。底层可以由不同的数据库封装实现,因为不同的数据库字段类型不一样,因此,跟以往直接用单一数据库(如mysql)建立的应用有很大的区别。
    models里面定义的数据类型基本上都是基础类型,在mysql用的比较多的 timestamp 貌似需要自己去做扩展:

    class MyDateField(models.Field):
        def db_type(self, connection):
            if connection.settings_dict['ENGINE'] == 'django.db.backends.mysql':
                return 'datetime'
            else:
                return 'timestamp'
    

    DatetimeField

    auto_now_add = True; 设置添加时默认当前时间。这里并不是通过数据库来实现,而是django在添加的时候去计算时间。因此涉及到时区问题:
    settings.py 设置 USE_TZ = True 后,django会使用UTC标准时间存入数据库。这个时候取出的 datetimefield 需要转换时区才能正确显示。
    因此一般情况下,如果应用不用考虑跨时区问题,设置 USE_TZ = False 一劳永逸
    查询出来的 datetimeField 是一个 <'datetime' object>,根据自己需要进行格式化输出

    ForeignKeyField

    外键关联,如果关联的外键表已经定义(在前面),直接用class名;若还未定义(在后面),用类名字串。

    class Spider(models.Model):
        """
        爬虫信息配置
        """
        name = models.CharField('爬虫名称', max_length=50, default='', db_index=True)
        c_name = models.CharField('爬虫名称', max_length=50, default='')
        domain = models.CharField('爬虫域名', max_length=150, default='')
        n_start = models.IntegerField('起始页数', default=0)
        n_end = models.IntegerField('终止页数', default=0)
        content_type = models.ForeignKey(
            'ContentType',
            related_name='spider_content_type',
            on_delete=models.CASCADE,
        )
    
        def __str__(self):
            return '%s[%s]' % (self.c_name, self.name)
    
    class ContentType(models.Model):
        """
        抓取内容类型
        """
        ACTIVE = (
            (0, 'active'),
            (1, 'discard'),
        )
        name = models.CharField('内容类型', max_length=50, default='')
        max_item = models.IntegerField('每个爬虫最大抓取数', default=10)
        expire_time = models.IntegerField('过期时间(天)', default=30)
        active = models.BooleanField('是否废弃', choices=ACTIVE, db_index=True, default=0)
    
        def __str__(self):
            return self.name
    

    related_name 代表在外键索引表中使用的查询引用。
    举个例子,A是主表,B表关联A_id,related_name为 related_a_id
    仅当在A中查询 b_id 时,使用 A.objects.filter(related_a_id=b_id)。
    下面是更详细的举例

    >>>
    >>> Spider.objects.all()
    <QuerySet [<Spider: 知乎[zhihu1]>, <Spider: 贴吧[tieba1]>, <Spider: LOL电影天堂[ddtt]>]>
    >>>
    >>> Spider.objects.get(id=1)
    <Spider: 知乎[zhihu1]>
    >>> Spider.objects.get(id=1).content_type
    <ContentType: 图片>
    >>>
    >>> Spider.objects.filter(content_type=1)
    <QuerySet [<Spider: 知乎[zhihu1]>, <Spider: 贴吧[tieba1]>]>
    >>>
    >>> ContentType.objects.filter(active=0)
    <QuerySet [<ContentType: 图片>, <ContentType: 电影资源>, <ContentType: 影评>, <ContentType: 小说>]>
    >>> ContentType.objects.filter(spider_content_type=1)
    <QuerySet [<ContentType: 图片>]>
    >>> ContentType.objects.filter(spider_content_type=2)
    <QuerySet [<ContentType: 图片>]>
    >>> ContentType.objects.filter(spider_content_type__in=[1,2,3])
    <QuerySet [<ContentType: 图片>, <ContentType: 图片>, <ContentType: 电影资源>]>
    >>>
    

    ForeignKey 默认会联接主键,如果是关联主键,需要手动指定to_field=relate_field。并且,实际创建的字段名会自动加上 _id 后缀

    choice

    类似于枚举类型,应该是为了在admin中更加方便管理。但是在业务使用的时候个人觉得很麻烦:
    XxxModel.SomeChoice[0][0]

    Meta.db_table

    Django的models 类名必须为驼峰,然后会自动全部转成小写并且在前面加上app前缀。如果想使用下划线分割单词,需要手动指定表明

    class Meta:
        verbose_name = 'cat imgs'
        verbose_name_plural = 'cat imgs'
        db_table = 'cat_imgs'
    

    ManyToManyField

    如果两个表有n:n的对应关系,只需要在一个表里声明。这时候Django会自动建立关联表。
    但是通常关联表还会包含其他字段信息,这时候需要通过 throgh 来指定一个关系表,并且显式地声明这个表的结构

    # relationship with comment
    comments = models.ManyToManyField(
        User,
        through='PicComments',
        through_fields=('img', 'author'),
    )
    

    objects

    在使用models查询的时候会先调用一个objects对象。
    这个对象我们可以通过继承扩展封装一些自定义方法,或者对queryset进行底层的过滤封装。

    class ImgManager(models.Manager):
        '''
        custom img model manager
        '''
        def get_queryset(self):
            return super(ImgManager, self).get_queryset().filter(img_status=0)
    
        def with_info(self, offset=0, limit=30):
            from django.db import connection
            result_list = []
            with connection.cursor() as cursor:
                cursor.execute('''
                    SELECT i.id,i.img_src,i.img_from,i.img_desc,IFNULL(l.likes,0)likes,
                    IFNULL(s.comments,0)comments,IFNULL(s.stars,0)stars FROM cat_imgs i 
                    LEFT JOIN 
                    (SELECT img_id,COUNT(DISTINCT user_id) likes FROM cats_pic_likes WHERE is_like=1 GROUP BY img_id ) l
                    ON i.id=l.img_id
                    LEFT JOIN 
                    (SELECT img_id,comments,stars FROM cats_pic_stars) s 
                    ON i.id=s.img_id
                    WHERE img_status=0 LIMIT %d,%d
                    ''' % (offset, limit))
                for row in cursor.fetchall():
                    p = self.model(id=row[0], img_src=row[1], img_from=row[2], img_desc=row[3])
                    p.n_likes = row[4]
                    p.n_comments = row[5]
                    p.n_stars = row[6]
                    p.n_star = 0 if row[5]==0 else row[6]//row[5]
                    result_list.append(p)
            return result_list
    

    queryset API

    • values() 字典形式的数据
    • values_list() 列表形式的数据
    • raw() 原始sql
    • 其他复杂的都可以在官网查询
  • 相关阅读:
    JavaScript-4.2函数,变量作用域---ShinePans
    2019-8-31-C#-简单读取文件
    2019-8-31-C#-简单读取文件
    2019-8-31-C#-大端小端转换
    2019-8-31-C#-大端小端转换
    2019-6-11-C#-标准性能测试
    2019-6-11-C#-标准性能测试
    2018-2-13-win10-uwp-右击选择-GridViewItem-
    2018-2-13-win10-uwp-右击选择-GridViewItem-
    2019-8-31-NuGet-如何设置图标
  • 原文地址:https://www.cnblogs.com/dapianzi/p/8250003.html
Copyright © 2020-2023  润新知