首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Django Admin中使用raw_id_fields时如何优化查询数

在Django Admin中使用raw_id_fields时如何优化查询数
EN

Stack Overflow用户
提问于 2016-11-30 20:17:31
回答 2查看 1.5K关注 0票数 8

我有一个如下的数据模型:

代码语言:javascript
复制
class Candidate(models.Model):
    name = models.CharField()

class Skill(models.Model):
    name = models.CharField()

class CandidateSkill(models.Model):
    candidate = models.ForeignKey(Candidate)
    skill = models.ForeignKey(Skill, related_name='candidate_skills')
    proficiency = models.CharField()

在管理员中,我有:

代码语言:javascript
复制
class CandidateSkillInline(admin.TabularInline):
    model = CandidateSkill
    fields = ('skill', )
    extra = 0
    raw_id_fields = ('skill',)

class CandidateAdmin(admin.ModelAdmin):
    model = Candidate
    fields = ('name',)
    inlines = [CandidateSkillInline]

每个候选人都可以有很多技能。这里的问题是,在每个内联的更改页面中,将使用一个查询来获取技能(SELECT ••• FROM "skill" WHERE "skill"."id" = <id>)。如果我在CandidateSkillInline中将字段skill添加为read_only,那么就不会有额外的查询。然而,我希望能够在内联中添加新的项目。我试过的东西:

1)将自定义表单集添加到CandidateSkillInline

代码语言:javascript
复制
class CandidateSkillInlineFormset(BaseInlineFormSet):
    def __init__(self, *args, **kwargs):
        super(CandidateSkillInlineFormset, self).__init__(*args, **kwargs)
        self.queryset = self.queryset.select_related('skill')

2)覆盖内联上的get_queryset

代码语言:javascript
复制
def get_queryset(self, request):
    super(CandidateSkillInline, self).get_queryset(request).select_related('skill')

3)覆盖CandidateAdmin上的get_queryset

代码语言:javascript
复制
def get_queryset(self, request):
    return super(CandidateAdmin, self).get_queryset(request).prefetch_related('candidate_skills__skill')

但是,我仍然会得到每个技能的查询。不发送查询的唯一方法是在CandidateSkillInilne的read_only_fields中设置skill。问题是,我如何在一个查询中选择或预取技能,而不是每个内联查询一个技能?

EN

回答 2

Stack Overflow用户

发布于 2016-11-30 20:28:10

这看起来像是你在尝试实现你自己的ManyToManyField。你能用ManyToManyField和内联来代替吗?它在管理中有一个很好的多选小部件。

https://docs.djangoproject.com/en/dev/ref/contrib/admin/#working-with-many-to-many-models

票数 1
EN

Stack Overflow用户

发布于 2019-12-17 04:38:52

嗯,ForeignKeyRawIdWidget的设计并不是那么优雅。作为小部件的基本职责,ForeignKeyRawIdWidget不只是以特定的方式显示某些数据,而是进行额外的查询,以便在屏幕上显示更相关的信息(它显示str(obj)方法的值)。

查询在label_and_url_for_value方法中执行。因此,您可以尝试使用自己的自定义小部件来避免此查询,但您必须考虑可视化中的权衡。

一种可能的解决方案是:

代码语言:javascript
复制
from django.contrib.admin.widgets import ForeignKeyRawIdWidget
from django.urls import reverse

class OptimisedForeignKeyRawIdWidget(ForeignKeyRawIdWidget):
    def label_and_url_for_value(self, value):
        try:
            url = reverse(
                '%s:%s_%s_change' % (
                    self.admin_site.name,
                    self.rel.model._meta.app_label,
                    self.rel.model._meta.object_name.lower(),
                ),
                args=(value,)
            )
        except NoReverseMatch:
            url = ''  # Admin not registered for target model.
        return str(value), url

最后一步,您必须在ModelForm类中设置自定义小部件。有很多方法可以做到这一点。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40888175

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档