python - Django Model Formset 在 POST 上非常慢
问题描述
我试图让用户在一个屏幕上修改多条记录,所以 Django Formsets 似乎是最好的选择。表单集中的每个表单都包含 9 个外键字段,这会导致运行许多查询。我通过对每一个使用 Jquery Autocomplete 在表单渲染方面解决了这个问题,这将渲染时间从 30 或 40 秒减少到大约 3 或 4 秒(将数百个查询减少到 4 个)。我现在遇到的性能问题是在 POST 方面——提交表单时,根据 Django 调试工具栏,它仍在运行数百个重复查询。我花了几个小时阅读各种博客和这里的表单集文档和建议。我尝试的最后一件事是将表单集查询集设置为自定义查询,并为每个 ForeignKey 字段使用 select_related()。这似乎使主要查询根据 DjDT 包含很多连接,但它并没有消除 POST 上剩余的数百个查询。我已经把我所有的头发都拔掉了,所以也许有人有建议或者可以看到我做错了什么?
我的模型:
class Info(AbstractAddArchive):
item= models.ForeignKey(ITEM, on_delete=models.PROTECT)
rec= models.ForeignKey(Log, on_delete=models.PROTECT, null=True, blank=True)
c1 = models.CharField(max_length=2, blank=True, null=True)
c1rec = models.ForeignKey(Log, on_delete=models.PROTECT, related_name='c1rec', blank=True, null=True)
c1sts = models.ForeignKey(Sts, on_delete=models.PROTECT, null=True, blank=True)
c1f = models.IntegerField(blank=True, null=True)
c2 = models.CharField(max_length=2, blank=True, null=True)
c2rec = models.ForeignKey(Log, on_delete=models.PROTECT, related_name='c2rec', blank=True, null=True)
c2sts = models.ForeignKey(Sts, on_delete=models.PROTECT, null=True, blank=True, related_name='c2sts')
c2f = models.IntegerField(blank=True, null=True)
c3 = models.CharField(max_length=2, blank=True, null=True)
c3rec = models.ForeignKey(Log, on_delete=models.PROTECT, related_name='c3rec', blank=True, null=True)
c3sts = models.ForeignKey(Sts, on_delete=models.PROTECT, null=True, blank=True, related_name='c3sts')
c3f = models.IntegerField(blank=True, null=True)
c4 = models.CharField(max_length=2, blank=True, null=True)
c4rec = models.ForeignKey(Log, on_delete=models.PROTECT, related_name='c4rec', blank=True, null=True)
c4sts = models.ForeignKey(Sts, on_delete=models.PROTECT, null=True, blank=True, related_name='c4sts')
c4 = models.IntegerField(blank=True, null=True)
comment1 = models.CharField(max_length=45, blank=True, null=True)
comment2 = models.CharField(max_length=45, blank=True, null=True)
posted_by = models.ForeignKey(User, on_delete=models.PROTECT, max_length=10, null=True, blank=True)
posted_ts = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('item',) # This sets initial order of formset display
def __str__(self):
return f"{self.item_id}"
class Log(AbstractAddArchive):
rec= models.CharField(max_length=10, primary_key=True)
... other fields ...
slug = models.SlugField(null=False, blank=True, unique=True)
def __str__(self):
return f"{self.name}"
class Sts(models.Model):
name = models.CharField(max_length=10, primary_key=True)
description = models.CharField(max_length=50, null=True, blank=True)
sequence = models.IntegerField()
def __str__(self):
return f"{self.name}"
我的表单和表单集:
class InfoReviseForm(forms.ModelForm):
class Meta:
model = Info
fields = ('rec',
'c1rec',
'c1f',
'c1sts',
'c2rec',
'c2f',
'c2sts',
'c3rec',
'c3f',
'c3sts',
'c4rec',
'c4f',
'c4sts',
'comment1',
)
widgets = {
'rec': forms.TextInput(attrs={
'class': 'autocomplete',
'placeholder': 'Choose rec...',
'app': 'appname',
'model-class': 'Log',
'search-field': 'rec',
'autocomplete-url': reverse_lazy('autocomplete_field')}),
... similar for all foreignkey fields - .js enables autocomplete on each
}
class InfoBaseFormSet(forms.BaseModelFormSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.queryset = Info.objects.select_related('rec').select_related('c1rec').select_related('c2rec').select_related('c3rec').select_related('c4rec').select_related('car').select_related('c1sts').select_related('c2sts').select_related('c3sts').select_related('c4sts')
InfoReviseFormset = modelformset_factory(Info, form=InfoReviseForm, extra=0, formset=InfoBaseFormSet)
我的观点(发布方法)
def post(self, request, *args, **kwargs):
formset = InfoReviseFormset(request.POST)
if formset.is_valid():
for form in formset:
if form.has_changed():
carinfo_active = form.instance
carinfo_active.posted_by = request.user
carinfo_active.save() #save new data - updates existing non archive record
return super().post(request, *args, **kwargs)
据我所知,“if formset.is_valid”是很多查询运行的地方——但在那之后它也很慢。顺便说一句,目前我在表单集中有大约 55 个表单 - 表单的最大数量可能高达 200 个,这只会让事情变得更慢。如果我可以减少查询,我认为这会更合理。
我简化了上面的一些代码 - 如果缺少任何帮助查看的内容,我很乐意发布更多内容。
感谢您的任何建议
解决方案
推荐阅读
- python - 加载了 gensim 的 Fasttext 模型不会继续使用新句子进行训练
- python - 不同颜色和不同线条样式的python轮廓
- javascript - 在变量 ID 或类而不是像素数处停止鼠标滚动
- xml - 如何判断我编写的 XSLT 3.0 是否实际上是流式传输 XML?
- mariadb - “我如何在 ubuntu 18.04 上安装 mariadb 版本 10.1.37”
- python - 对文件夹中的文件进行排序
- html - 为什么绝对定位元素要考虑边距?
- python - 根据时间序列中的先前值和后续值将值替换为 NaN
- common-lisp - Lisp plist 仅在符号的属性列表单元格的上下文中?
- javascript - 点击事件上的 jQuery Mobile listview 小部件不会为 Mobile 触发