Django admin 在 mysql 中做了很多重复的查询
Posted
技术标签:
【中文标题】Django admin 在 mysql 中做了很多重复的查询【英文标题】:Django admin makes a lot of duplicate queries in mysql 【发布时间】:2016-06-26 19:35:15 【问题描述】:我遇到了一个问题。
当我尝试打开更改页面以查看元素中的参数(如 djangosite.com/admin/djangoapp/someelement/1/change/
)时,它的加载速度非常慢(10-15 秒)。
我发现 Django 做了很多重复的查询:
更新: 我想我在 admin.py 中犯了错误。
inlines = [PhoneInline,FlatInline,NeedInline]
如果我删除上面的行,一切都很好。
mysql日志
2161 Query set autocommit=0
2161 Query SELECT `ha_phone`.`id`, `ha_phone`.`phone_number`, `ha_phone`.`phone_owner_id` FROM `ha_phone` WHERE `ha_phone`.`id` = 262
2161 Query SELECT `django_content_type`.`id`, `django_content_type`.`app_label`, `django_content_type`.`model` FROM `django_content_type` WHERE (`django_content_type`.`model` = 'phone' AND `django_content_type`.`app_label` = 'MYAPP')
2161 Query commit
2161 Query set autocommit=1
2161 Query SELECT `ha_owner`.`id`, `ha_owner`.`owner_pub_date`, `ha_owner`.`owner_name`, `ha_owner`.`owner_verify`, `ha_owner`.`owner_company_id` FROM `ha_owner` WHERE `ha_owner`.`id` = 236
2161 Query SELECT `ha_company`.`id`, `ha_company`.`company_name` FROM `ha_company` WHERE `ha_company`.`id` = 1
2161 Query SELECT `ha_owner`.`id`, `ha_owner`.`owner_pub_date`, `ha_owner`.`owner_name`, `ha_owner`.`owner_verify`, `ha_owner`.`owner_company_id` FROM `ha_owner`
2161 Query SELECT `ha_company`.`id`, `ha_company`.`company_name` FROM `ha_company` WHERE `ha_company`.`id` = 1
2161 Query SELECT `ha_company`.`id`, `ha_company`.`company_name` FROM `ha_company` WHERE `ha_company`.`id` = 1
2161 Query SELECT `ha_company`.`id`, `ha_company`.`company_name` FROM `ha_company` WHERE `ha_company`.`id` = 1
2161 Query SELECT `ha_company`.`id`, `ha_company`.`company_name` FROM `ha_company` WHERE `ha_company`.`id` = 1
2161 Query SELECT `ha_company`.`id`, `ha_company`.`company_name` FROM `ha_company` WHERE `ha_company`.`id` = 1
2161 Query SELECT `ha_company`.`id`, `ha_company`.`company_name` FROM `ha_company` WHERE `ha_company`.`id` = 1
2161 Query SELECT `ha_company`.`id`, `ha_company`.`company_name` FROM `ha_company` WHERE `ha_company`.`id` = 1
2161 Query SELECT `ha_company`.`id`, `ha_company`.`company_name` FROM `ha_company` WHERE `ha_company`.`id` = 1
2161 Query SELECT `ha_company`.`id`, `ha_company`.`company_name` FROM `ha_company` WHERE `ha_company`.`id` = 1
...
models.py
class House(models.Model):
house_number = models.CharField(max_length=10, verbose_name="Номер дома")
house_floors = models.PositiveSmallIntegerField(verbose_name="Число этажей", null=True)
house_walls = models.ForeignKey(Walls, verbose_name="Материал стен", null=True)
house_street = models.ForeignKey(Street, verbose_name="Улица")
house_metro = models.ForeignKey(Metro, verbose_name="Станция Метро", null=True)
house_block = models.ForeignKey(Block, verbose_name="Микрорайон", null=True)
class Meta:
verbose_name = 'Дом'
verbose_name_plural = 'Дома'
ordering = ['house_street','house_number']
def __unicode__(self):
return unicode(self.house_street.street_name) + " " + unicode(self.house_number)
class Flat(models.Model):
flat_number = models.CharField(max_length=7, verbose_name="Номер квартиры", null=True)
flat_rooms = models.PositiveSmallIntegerField(verbose_name="Число комнат")
flat_total_sq = models.PositiveSmallIntegerField(verbose_name="Общая площадь")
flat_life_sq = models.PositiveSmallIntegerField(verbose_name="Жилая площадь")
flat_kitchen_sq = models.PositiveSmallIntegerField(verbose_name="Кухонная площадь")
flat_floors = models.PositiveSmallIntegerField(verbose_name="Этаж")
flat_house = models.ForeignKey(House, verbose_name="Дом")
flat_owner = models.ForeignKey(Owner, verbose_name="Владелец")
flat_comment = models.TextField(verbose_name="Комметарий", null=True)
flat_price = models.PositiveIntegerField(verbose_name='Цена квартиры')
...
class Owner(models.Model):
owner_pub_date = models.DateField(default=None,null=True,verbose_name="Дата публикации")
owner_name = models.CharField(max_length=150, verbose_name="ФИО владельца")
owner_verify = models.BooleanField(verbose_name="Пользователь верифицирован?")
owner_company = models.ForeignKey(Company, verbose_name="Компания")
class Meta:
verbose_name = 'Владельца'
verbose_name_plural = 'Владельцы'
def __unicode__(self):
return unicode(self.id) + " | "+ self.owner_name + " " + unicode(self.owner_company)
class Phone(models.Model):
phone_number = models.CharField(max_length=25, verbose_name="Номер телефона")
phone_owner = models.ForeignKey(Owner, verbose_name="Владелец телефона")
class Meta:
verbose_name = 'Телефон'
verbose_name_plural = 'Телефоны'
def __unicode__(self):
return unicode(self.phone_owner) + " " + self.phone_number
admin.py
...
class PhoneInline(admin.StackedInline):
model = Phone
extra = 2
class FlatInline(admin.TabularInline):
model = Flat
extra = 0
class NeedInline(admin.TabularInline):
model = Need
extra = 1
class OwnerAdmin(admin.ModelAdmin):
field=['owner_name']
inlines = [PhoneInline,FlatInline,NeedInline]
admin.site.register(Owner,OwnerAdmin)
我该怎么办? 非常感谢。
更新 @Alasdair,谢谢。减少了使用 ha_company 的查询。但是我有另一个与 ha_street 相同的副本。看起来像这样:
2601 Query SELECT `ha_company`.`id`, `ha_company`.`company_name` FROM `ha_company`
2601 Query SELECT `ha_house`.`id`, `ha_house`.`house_number`, `ha_house`.`house_floors`, `ha_house`.`house_walls_id`, `ha_house`.`house_street_id`, `ha_house`.`house_metro_id`, `ha_house`.`house_block_id`, `ha_house`.`house_age`, `ha_house`.`house_flat`, `ha_house`.`house_quality` FROM `ha_house` INNER JOIN `ha_street` ON (`ha_house`.`house_street_id` = `ha_street`.`id`) ORDER BY `ha_street`.`street_name` ASC, `ha_house`.`house_number` ASC
2601 Query SELECT `ha_street`.`id`, `ha_street`.`street_name` FROM `ha_street` WHERE `ha_street`.`id` = 74
2601 Query SELECT `ha_street`.`id`, `ha_street`.`street_name` FROM `ha_street` WHERE `ha_street`.`id` = 74
2601 Query SELECT `ha_street`.`id`, `ha_street`.`street_name` FROM `ha_street` WHERE `ha_street`.`id` = 36
2601 Query SELECT `ha_street`.`id`, `ha_street`.`street_name` FROM `ha_street` WHERE `ha_street`.`id` = 582
2601 Query SELECT `ha_street`.`id`, `ha_street`.`street_name` FROM `ha_street` WHERE `ha_street`.`id` = 582
【问题讨论】:
如果您的解决方案没问题,只需回答您自己的问题,这样人们会更容易找到它 【参考方案1】:Phone
模型的__unicode__
方法包括unicode(self.phone_owner)
,它依次访问owner_company
外键。这意味着 Django 必须为内联中的每个电话对象查找公司。
您通过删除内联解决了问题,但如果您想保留内联,您可以:
-
将
__unicode__
方法更改为Phone
或Owner
,以便不包括公司
为您的内联覆盖@987654328@ 方法,以便您可以使用select_related
。
class PhoneInline(admin.StackedInline):
model = Phone
extra = 2
def get_queryset(self, request):
return super(PhoneInline, self).get_queryset(request).select_related('phone_owner', 'phone_owner__ owner_company')
【讨论】:
谢谢。它有助于。但是我对 ha_street 也有同样的问题。我应该如何重写这个:unicode(self.house_street.street_name)
?是这个问题吗?
这是一个类似的问题,看起来您的查询正在查找查询集中的每所房子的街道。您可以从__unicode__
方法中删除self.house_street
,或使用select_related
。你还没有向模型管理员展示或者说是哪个 url 导致了这些查询,所以我不能说如何做到这一点。
我在上面的问题中添加了模型管理员。问题出在 django admin 的所有者更改页面中。我认为 FlatInline 中的原因
如果问题是FlatInline
,则覆盖其get_queryset
方法并使用select_related
。您可能需要重新考虑是否要在 __unicode__
方法中包含外键。如果Flat.__unicode__
方法使用自己,它的房子和房子的街道,那么你需要非常小心,防止大量的SQL查询。以上是关于Django admin 在 mysql 中做了很多重复的查询的主要内容,如果未能解决你的问题,请参考以下文章