十六、Django的ORM(二)

1、DecimalField

DecimalField保存浮点型数据比FloatField精确,因为它是以字符串来保存,而FloatField,数据越长,保存得越不精确。

2、索引

(命中索引) 正确使用SQL语言,使查找数据时,用到索引

username=models.CharField(
        ...
        # db_index=True  数据库中字段是否可以建立索引   在数据库中数据很大时,建立该索引,可以查找得更快(加速查找)
        # unique= 数据库中字段是否可以建立唯一索引 加速查找 && 限制列值唯一
        # primary_key=  加速查找 && 限制列值唯一 && 不能为空
        # unique_for_date=  数据库中字段【日期】部分是否可以建立唯一索引
        # unique_for_month=  数据库中字段【月】部分是否可以建立唯一索引
        # unique_for_year=  数据库中字段【年】部分是否可以建立唯一索引
    	...
    )

3、一对一

使foreignkey唯一 或使用oneToOneField

4、ForeignKey

a、关联删除

"""
	on_delete = 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(可执行对象)
"""
related_name='b', # 反向查找时,用obj.b
related_query_name='b', # 反向查找时,用obj.b_set
limit_choices_to={'id__gt':1}, # Admin中关联的部门id要求大于1 (只在Admin中生效)

5、联合唯一

class UserToTag(models.Model):
    u = models.ForeignKey(to='User')
    t = models.ForeignKey(to='Tag')
    ctime=models.DateField()
    ...

    class Meta:
        # 联合唯一 即两条记录中 u和t 不能重复
        unique_together=[
            ('u','t'),
        ]

6、多对多的高级方式

通过through属性 指定第三张表 为自己创建的表
这样,第三张表就可以有不只三列数据
但这时候,.add .set .remove等方法不能使用了 .all .filter 还可以使用
因此,这种通过through属性关联起来的第三张表多对多方式 不推荐。
推荐:普通manyTomany 或 自创建第三张表但不through关联

class Tag(models.Model):
    title = models.CharField(max_length=16)
    # 使用ManyToManyField只能在第三张表中创建三列数据
    m = models.ManyToManyField(
        to='UserInfo',
        through='UserToTag', # 通过through指定第三张表就可以有三列以上的数据
        through_fields=['u','t'] 
    )

7、自关联

(ManyToMany)自关联时,related_name必须设置,方便反向查询

8、extra

9、Using :指定使用的数据库


10、raw

# 执行原生SQL语句
models.UserInfo.objects.raw('select * from userinfo')
# 其它
...

11、dates查询

12、批量创建bulk_create

13、in_bulk

models.UserInfo.objects.in_bulk([1,2,3]) #查询主键为1,2,3的记录

一些实践中的笔记

1、

classifications = models.Classification.objects.filter(direction__id=d)
# 拿到id集合的方法
ids = list(zip(*classifications.values_list('id')))[0]

2、

class video(models.Model):
    title = models.CharField(max_length=32)
    href = models.CharField(max_length=256)
    img = models.FileField(upload_to='statics/videos/img/') #指定admin中存放图片的位置
    summary = models.CharField(max_length=256)
    weight = models.IntegerField(verbose_name='权重(按从大到小排列)', default=0)
    create_date = models.DateTimeField(auto_now_add=True)

    status_choices = ((0, '下线'),(1, '上线'),)
    status = models.SmallIntegerField(choices=status_choices, default=1, verbose_name='状态')
    # SET_NULL外键为空时,这个字段设为空,需要设置blank=True,null=True
    level = models.ForeignKey("Level", on_delete=models.SET_NULL, blank=True,null=True) 
    classification = models.ForeignKey('Classification', on_delete=models.CASCADE)

    class Meta:
        verbose_name_plural = '视频'

    def __str__(self):
        return self.title

    def img_url(self): #外面.img时是statics/...的路径。但项目设置了别名static,所以这里需要转换。
        return self.img.name.replace('statics', 'static')

3、

userInfo = models.UserInfo.objects.filter(name=name,password=pwd)
if userInfo.exists(): # 使用exists()优化,不需查询用户信息处理
    # site = userInfo.first().blog.first().site  # 这种方式查询site,会查询两次数据,1:查询用户信息;2:查询博客信息
    site = models.Blog.objects.filter(user__name=name).values_list('site').first()[0] #这种正向查询,只需查询一次数据
    request.session['UserInfo'] = {'name': name, 'blog_site': site}

4、多对多、反向查询:

class UserFans(models.Model):
    user = models.ForeignKey(UserInfo, on_delete=models.CASCADE, related_name='star')
    follower = models.ForeignKey(UserInfo, on_delete=models.CASCADE, related_name='follow')

    class Meta:
        unique_together = [('user', 'follower',),]

class UserInfo(models.Model):
    name = models.CharField(max_length=16,unique=True)
    ...
    fans = models.ManyToManyField('UserInfo',
                                  through="UserFans",
                                  through_fields=('user','follower'))

class Blog(models.Model):
    site = models.CharField(max_length=16,unique=True)
	...
    user = models.ForeignKey(UserInfo, unique=True, on_delete=models.CASCADE, related_name="blog")
blog = models.Blog.objects.filter(site=site).first()
if blog:
    fans_count = blog.user.fans.count() #普通:直接查询userinfo的fans字段
    #多对多+反向:follow找到user在UserFans中作为folloer的所有数据
    follow_count = blog.user.follow.all() #即查询user关注了的userinfo

5、raw()原生查询

for p in models.Article.objects.raw("SELECT * FROM repository_article"):
    print(p)

for p in models.Article.objects\
	.raw('SELECT id, strftime("%Y-%m",create_time) AS ctime FROM repository_article'):
	print("----",p.ctime)

for p in models.Article.objects\
	.raw('SELECT id, count(id) as nm, strftime("%Y-%m",create_time) AS ctime FROM repository_article GROUP BY strftime("%Y-%m",create_time)'):
    print("----",p.ctime, p.nm, p.id)

dates = models.Article.objects\
	.raw('SELECT repository_article.id, count(repository_article.id) as nm, strftime("%Y-%m",repository_article.create_time) AS ctime, site FROM repository_article,repository_blog WHERE blog_id=repository_blog.id GROUP BY strftime("%Y-%m",create_time)')
for i in dates:
    print(i.site)

# s = models.Blog.objects.raw('SELECT * FROM repository_blog WHERE site="bruce"')
sql_raw = 'SELECT repository_article.id, count(repository_article.id) as nm, strftime("%Y-%m",repository_article.create_time) AS ctime, site FROM repository_article,repository_blog WHERE blog_id=repository_blog.id AND repository_blog.site = '\
          + '\'%s\''%site + ' GROUP BY strftime("%Y-%m",create_time)'
print(sql_raw)
dates = models.Article.objects.raw(sql_raw)
for i in dates:
    print(i.site)

通过结果“dates”.访问article的id,nm,ctime查询sql语言中的这些SELECT过的字段,
不需要重新查询。而访问其它字段,例如:dates.title,dates.summary,就会另外查询。
另外,dates由于是通过models.Arcticle查询出来的,因此访问的是Article的字段。

6、where()查询

articles=models.Article.objects.filter(blog__site=site)
	.extra(where=['strftime("%%Y-%%m",create_time)=%s'],params=[param,]).all()

7、Select_relate 链表查询只能连有foreign的,不可以反向连
反向查询:

tag = models.Tag.objects.filter(id=param, blog__site=site).first()
articles = tag.article_set.all()

8、跨表查询相关

做评论列表时,查询评论数据,然后序列化。由于评论者在评论中是外键关联。
模版通过 评论.user 只能拿到user的id,即外键字段的值。
那么,应该怎样拿到user name?
目前的解决方法:在视图函数提前点出来
comments = models.ArticleComment.objects.filter(article_id=article_id)\
.select_related("user","reply").all()\
.values("id","content","user","reply","create_time","user__name","reply__user__name")

9、

通过values指定查询的字段,可以减少文章列表对数据库查询次数。因为文章model里关联了在模版渲染时
articles = models.Article.objects.filter(blog__site=site)\
.values("title","id","summary","create_time","comment_count","up_count")


troubles = models.FR_table.objects.filter(user_id=user_id).values("id","title",'status','ctime','processor')
troubles = models.FR_table.objects.filter(user_id=user_id).only("id","title",'status','ctime','processor')
Values 与 only是不同的
values是将字段查询出来组成字典
only只是限定查询的字段
在模版中<td>{{ a.get_status_display }}</td>    用values时,这个模版语言是没有效果的。因为用了values,模版中只能使用values指定的那些键。而用only,在模版中可以通过指定字段继续查询
only是只查对应字段  与使用values 的SQL语句一样,不知道如何产生不同的效果
如果不使用only和values,会查询所有字段,只要查询一条记录,就查询所有字段。

manyTomany: 文章被删除,文章&Tag第三张表仍有被删除文章的id 好像文章是被自己直接从数据库中删除

10、查询关联model的方法

def display_all_related_objs(obj):
    """
    显示要被删除对象的所有关联对象
    :param obj:
    :return:
    """
    ele = "<ul>"
    # ele += "<li><a href='/kingadmin/%s/%s/%s/change/'>%s</a></li>" %(obj._meta.app_label,
    #                                                                  obj._meta.model_name,
    #                                                                  obj.id,obj)

    for reversed_fk_obj in obj._meta.related_objects: #._meta.related_objects可以拿到反向关联和多对多的表
        related_table_name =  reversed_fk_obj.name
        related_lookup_key = "%s_set" % related_table_name
        related_objs = getattr(obj,related_lookup_key).all() #反向查所有关联的数据
        ele += "<li>%s<ul> "% related_table_name

        if reversed_fk_obj.get_internal_type() == "ManyToManyField":  # 不需要深入查找
            for i in related_objs:
                ele += "<li><a href='/kingadmin/%s/%s/%s/change/'>%s</a> 记录里与[%s]相关的的数据将被删除</li>" \
                       % (i._meta.app_label,i._meta.model_name,i.id,i,obj)
        else:
            for i in related_objs:
                #ele += "<li>%s--</li>" %i
                ele += "<li><a href='/kingadmin/%s/%s/%s/change/'>%s</a></li>" %(i._meta.app_label,
                                                                                 i._meta.model_name,
                                                                                 i.id,i)
                ele += display_all_related_objs(i)

        ele += "</ul></li>"

    ele += "</ul>"

    return ele
posted @   Bruce_JRZ  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示