我有3个ForeignKey的领域的简单模型。
class Car(models.Model):
wheel = models.ForeignKey('Wheel', related_name='wheels')
created = models.DateTimeField(auto_now_add=True)
max_speed = models.PositiveSmallIntegerField(null=True)
dealer = models.ForeignKey('Dealer')
category = models.ForeignKey('Category')
对于在Django管理列表视图中我得到4个查询。 其中之一是选择具有3内部连接。 这一个查询的方式来放缓。 与STRAIGHT_JOIN更换内部联接将解决这个问题。 有没有办法来修补管理员生成的查询其被评估之前?
我实现了一个INNER JOIN修复Django的ORM,它会在内部连接订货的情况下使用STRAIGHT_JOIN。 我跟Django的核心开发者,我们决定做这个作为一个独立的后端现在。 所以,你可以看看这里: https://pypi.python.org/pypi/django-mysql-fix
然而,有一个其他的解决办法。 从詹姆斯的答案中使用的摘要,但将其替换select_related:
qs = qs.select_related('').prefetch_related('wheel', 'dealer', 'category')
这将取消INNER JOIN和使用4个单独的查询:1与取车和3人car_id
IN(...)。
更新:我发现多了一个解决办法。 一旦你设置的ForeignKey的领域空=真,Django会使用LEFT OUTER连接,而不是INNER JOIN。 LEFT OUTER JOIN的作品,而不在这种情况下的性能问题,但你可能会面临,我是不知道的另外一些问题。
你可能只是指定list_select_related = ()
以防止Django的使用内连接:
class CarAdmin(admin.ModelAdmin):
list_select_related = ()
你可能会覆盖
def changelist_view(self, request, extra_context=None):
在您的管理类中的方法从继承ModelAdmin
类
像这样(但这个问题已很旧): Django管理:获取根据获取字符串过滤一个QuerySet,正是因为看到更改列表?
好吧,我找到了一种方法来修补生成的查询管理。 这是丑陋的,但它似乎工作 :
class CarChangeList(ChangeList):
def get_results(self, request):
"""Override to patch ORM generated SQL"""
super(CarChangeList, self).get_results(request)
original_qs = self.result_list
sql = str(original_qs.query)
new_qs = Car.objects.raw(sql.replace('INNER JOIN', 'STRAIGHT_JOIN'))
def patch_len(self):
return original_qs.count()
new_qs.__class__.__len__ = patch_len
self.result_list = new_qs
class CarAdmin(admin.ModelAdmin):
list_display = ('wheel', 'max_speed', 'dealer', 'category', 'created')
def get_changelist(self, request, **kwargs):
"""Return custom Changelist"""
return CarChangeList
admin.site.register(Rank, RankAdmin)
我在Django管理(版本1.4.9),其中当由MySQL支持的相当简单的管理列表页面非常缓慢穿过同样的问题来了。
在我的情况下,它是由引起ChangeList.get_query_set()
方法增加一个过于广泛的全球select_related()
来设置,如果在任意字段查询list_display
许多一对一的关系。 对于一个适当的数据库(PostgreSQL的咳嗽咳 ),这不会是一个问题,但它是为MySQL一度超过几联接被触发这种方式。
我找到了干净的解决方案是,以取代全球select_related()
用更有针对性的一个,只有加入了真的是必要的表指令。 这是很容易通过调用做select_related()
有明确的关系名称。
这种方法可能最终交换的数据库的连接多个后续查询,但如果MySQL在大型查询呛许多小的可能是你更快。
下面是我做什么,或多或少:
from django.contrib.admin.views.main import ChangeList
class CarChangeList(ChangeList):
def get_query_set(self, request):
"""
Replace a global select_related() directive added by Django in
ChangeList.get_query_set() with a more limited one.
"""
qs = super(CarChangeList, self).get_query_set(request)
qs = qs.select_related('wheel') # Don't join on dealer or category
return qs
class CarAdmin(admin.ModelAdmin):
def get_changelist(self, request, **kwargs):
return CarChangeList
我有慢管理员查询在MySQL,发现最简单的解决办法是STRAIGHT_JOIN添加到查询。 我想出了一个办法把它添加到QuerySet
而不是被迫去.raw()
它不会与管理工作,并有开源了它的一部分django-mysql
。 然后,您可以只:
def get_queryset(self, request):
qs = super(MyAdmin, self).get_queryset(request)
return qs.straight_join()