Django admin inline:select_related [英] Django admin inline: select_related
问题描述
class Product(models.Model):
name = models.CharField(max_length = 255)
#这里还有一些字段
def __str __(self):
return self.name
class PricedProduct(models.Model):
product = models.ForeignKey(Product,related_name ='prices')
#some more fields here
def __str __(self )
return str(self.product)
class Coming(models.Model):
#some unimportant fields here
class ComingProducts(models.Model):
coming = models.ForeignKey(Coming)
priced_product = models.ForeignKey(PricedProduct)
#more unimportant fields
和以下admin.py:
class ComingProductsInline(ForeignKeyCacheMixin,admin.TabularInline):
model = ComingProducts
class ComingAdmin(admin.ModelAdmin):
inline = [ComingProductsInline]
当然,我对数据库的乘法查询有问题:我有列表中的每个项目的查询和每行的查询。所以,有100项我得到100 ^ 2查询。
我已经使用为Django表单中的ModelChoiceField或ModelMultipleChoiceField缓存查询选项
但是我仍然遇到 str 方法的问题。我尝试了以下内容:
1)将prefetch_related添加到ComingAdmin:
def get_queryset(self,request):
return super(ComingAdmin,self).get_queryset(request)。 \
prefetch_related('products__product')
2)添加select_related到ComingProductInline:
$ b
def get_queryset(self,request):
return super(ComingProductsInline,self).get_queryset(request)。 \
select_related('priced_product__product')
3)定义内联和添加的自定义表单select_related to field queryset:
class ComingProductsInline(ForeignKeyCacheMixin,admin.TabularInline):
4)定义自定义表单集
model = ComingProducts
form = ComingProductsAdminForm
class ComingProductsAdminForm(ModelForm):
def __init __(self,* args,** kwargs):
super(ComingProductsAdminForm,self).__ init __(args,kwargs )
self.fields ['priced_product']。queryset = PricedProduct.objects.all()。 \
select_related('product')
class Meta:
model = ComingProducts
fields ='__all__'
class ComingProductsInline(ForeignKeyCacheMixin,admin.TabularInline):
model = ComingProducts
formset = MyInlineFormset
class MyInlineFormset(BaseInlineFormSet):
def __init __(self,data = None,文件=无,实例=无,
save_as_new = False,前缀=无,queryset =无,** kwargs):
super(MyInlineFormset,self).__ init __(数据,文件,实例,
save_as_new,前缀,queryset,** kwargs)
self.queryset = ComingProducts.objects.all()。 \
prefetch_related('priced_product__product')
5)以前4种方法的不同组合
没有任何帮助:每个调用PricedProduct的str使Django对Product表执行查询。所有这些方法都在stackoverflow中提到,但他们处理了ModelAdmin,并且不帮助Inline。我想念什么?
解决方案表单解决方案对我来说是有效的,但是有一个稍微不同的方法:
class MyInlineFormset(BaseInlineFormSet):
def __init __(self,* args,** kwargs):
super(MyInlineFormset,自我).__ init __(* args,** kwargs)
self.queryset = self.queryset.prefetch_related('priced_product__product')
BaseInlineFormSet类为您过滤查询集,您需要使用该过滤的查询集并添加预取。使用您的formset实现(all()queryset),您可以获得无关的ComingProduct对象,并且渲染可能需要太长时间。当它是过滤的查询器,它很快呈现。
Using Django 1.8 on Python 3.4.1 with models:
class Product(models.Model): name = models.CharField(max_length=255) # some more fields here def __str__(self): return self.name class PricedProduct(models.Model): product = models.ForeignKey(Product, related_name='prices') # some more fields here def __str__(self): return str(self.product) class Coming(models.Model): # some unimportant fields here class ComingProducts(models.Model): coming = models.ForeignKey(Coming) priced_product = models.ForeignKey(PricedProduct) # more unimportant fields
and the following admin.py:
class ComingProductsInline(ForeignKeyCacheMixin, admin.TabularInline): model = ComingProducts class ComingAdmin(admin.ModelAdmin): inlines = [ComingProductsInline]
Of course, i have a problem with multiply queries to database: i have a query for each item in list and a query for each line. So, having 100 items i get 100 ^ 2 queries. I've solved the problem with queries for each line with Caching queryset choices for ModelChoiceField or ModelMultipleChoiceField in a Django form But i still having problem with str method. I've tried the following:
1) adding prefetch_related to ComingAdmin:
def get_queryset(self, request): return super(ComingAdmin, self).get_queryset(request). \ prefetch_related('products__product')
2) adding select_related to ComingProductInline:
def get_queryset(self, request): return super(ComingProductsInline, self).get_queryset(request). \ select_related('priced_product__product')
3) Defining custom form for inline and adding select_related to field queryset:
class ComingProductsInline(ForeignKeyCacheMixin, admin.TabularInline): model = ComingProducts form = ComingProductsAdminForm class ComingProductsAdminForm(ModelForm): def __init__(self, *args, **kwargs): super(ComingProductsAdminForm, self).__init__(args, kwargs) self.fields['priced_product'].queryset = PricedProduct.objects.all(). \ select_related('product') class Meta: model = ComingProducts fields = '__all__'
4) Defining a custom formset:
class ComingProductsInline(ForeignKeyCacheMixin, admin.TabularInline): model = ComingProducts formset = MyInlineFormset class MyInlineFormset(BaseInlineFormSet): def __init__(self, data=None, files=None, instance=None, save_as_new=False, prefix=None, queryset=None, **kwargs): super(MyInlineFormset, self).__init__(data, files, instance, save_as_new, prefix, queryset, **kwargs) self.queryset = ComingProducts.objects.all(). \ prefetch_related('priced_product__product')
5) Different combinations for previous 4 methods
And nothing helps: each call of str for PricedProduct makes Django to perform a query for Product table. All of these methods were mentioned on stackoverflow, but they treated ModelAdmin, and do not help with Inline. What do i miss?
解决方案The formset solution does work for me, but with a slightly different approach:
class MyInlineFormset(BaseInlineFormSet): def __init__(self, *args, **kwargs): super(MyInlineFormset, self).__init__(*args, **kwargs) self.queryset = self.queryset.prefetch_related('priced_product__product')
The BaseInlineFormSet class filters the queryset for you, and you need to take that filtered queryset and add the prefetch. With your formset implementation (the all() queryset) you get unrelated ComingProduct objects and it probably takes much too long to render. When it's the filtered queryset it renders very quickly.
这篇关于Django admin inline:select_related的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!