【问题标题】:Django modelformset is_valid method retrieves entire model from databaseDjango modelformset is_valid 方法从数据库中检索整个模型
【发布时间】:2020-11-16 07:45:55
【问题描述】:

当调用 is_valid 方法时,我有一个 modelformset 从数据库中检索底层表单的整个模型对象,如果数据库表包含数十万条记录,则效率不高,我相信 Django 的设计没有这个缺陷并且存在我的代码一定有问题,当调用 is_valid 时,这些查询被发送到数据库,第一个查询没有 WHERE 子句,这意味着它将检索整个表!:

[{'sql': 'SELECT @@SQL_AUTO_IS_NULL', 'time': '0.000'},
{'sql': 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', 'time': '0.000'},

**{'sql': 'SELECT `npr`.`rid`, `npr`.`PID`, `npr`.`rel`, `npr`.`CID` FROM `npr` ORDER BY `npr`.`rid` ASC', 'time': '0.037'}**

{'sql': 'SELECT `person_details`.`ID`, `person_details`.`firstName` FROM `person_details` WHERE `person_details`.`ID` = 198 LIMIT 21', 'time': '0.001'},
{'sql': 'SELECT `person_details`.`ID`, `person_details`.`firstName` FROM `person_details` WHERE `person_details`.`ID` = 1243 LIMIT 21', 'time': '0.000'},
{'sql': 'SELECT `npr`.`rid`, `npr`.`PID`, `npr`.`rel`, `npr`.`CID` FROM `npr` WHERE `npr`.`rid` = 1377 LIMIT 21', 'time': '0.000'},
{'sql': 'SELECT (1) AS `a` FROM `person_details` WHERE `person_details`.`ID` = 198 LIMIT 1', 'time': '0.000'},
{'sql': 'SELECT (1) AS `a` FROM `person_details` WHERE `person_details`.`ID` = 1243 LIMIT 1', 'time': '0.000'},
{'sql': 'SELECT (1) AS `a` FROM `npr` WHERE (`npr`.`CID` = 1243 AND `npr`.`PID` = 198 AND NOT (`npr`.`rid` = 1377)) LIMIT 1', 'time': '0.000'},
{'sql': 'SELECT `person_details`.`ID`, `person_details`.`firstName` FROM `person_details` WHERE `person_details`.`ID` = 200 LIMIT 21', 'time': '0.000'},
{'sql': 'SELECT `person_details`.`ID`, `person_details`.`firstName` FROM `person_details` WHERE `person_details`.`ID` = 1243 LIMIT 21', 'time': '0.004'},
{'sql': 'SELECT `npr`.`rid`, `npr`.`PID`, `npr`.`rel`, `npr`.`CID` FROM `npr` WHERE `npr`.`rid` = 1378 LIMIT 21', 'time': '0.000'},
{'sql': 'SELECT (1) AS `a` FROM `person_details` WHERE `person_details`.`ID` = 200 LIMIT 1', 'time': '0.000'},
{'sql': 'SELECT (1) AS `a` FROM `person_details` WHERE `person_details`.`ID` = 1243 LIMIT 1', 'time': '0.000'},
{'sql': 'SELECT (1) AS `a` FROM `npr` WHERE (`npr`.`CID` = 1243 AND `npr`.`PID` = 200 AND NOT (`npr`.`rid` = 1378)) LIMIT 1', 'time': '0.000'}]

模型

   class PersonDetails(models.Model):
        id = models.AutoField(db_column='ID', primary_key=True)
        firstname = models.CharField(db_column='firstName', max_length=20)
    
        class Meta:
            managed = True
            db_table = 'person_details'
    
    
    class Npr(models.Model):
        rid = models.AutoField(db_column='rid', primary_key=True)
        pid = models.ForeignKey(PersonDetails, on_delete=models.CASCADE, db_column='PID', related_name='pid')
        rel = models.CharField(max_length=1)
        cid = models.ForeignKey(PersonDetails, on_delete=models.CASCADE, db_column='CID', related_name='cid')
    
        class Meta:
            managed = True
            db_table = 'npr'
            unique_together = (('pid', 'cid'),)

和表单定义:

class prelation(ModelForm):
    class Meta:
        model = Npr
        fields = ['pid', 'rel', 'cid']
        widgets = {'pid':HiddenInput(), 'rel':HiddenInput(), 'cid':HiddenInput()}

prelations = modelformset_factory(Npr, form = prelation, can_delete=True, extra=1)

当针对模型表单集调用 is_valid 方法时,如何优化发送到数据库的查询?我正在使用 Django 版本:3.0.4,Python 版本:3.7.3,数据库:10.3.22-MariaDB-0+deb10u1-log

编辑 1: 我正在使用 Django shell 进行测试,因为我想让问题简洁并避免整个应用程序的复杂性,并且两者都给出了相同的结果。

>>> from tstapp.forms import prelations
>>> 
>>> 
>>> datana={'form-TOTAL_FORMS':'2',
... 'form-INITIAL_FORMS':'2',
... 'form-MIN_NUM_FORMS':'0',
... 'form-MAX_NUM_FORMS':'1000',
... 'form-0-pid':'198',
... 'form-0-rel':'F',
... 'form-0-cid':'1243',
... 'form-0-rid':'1377',
... 'form-0-DELETE':'None',
... 'form-1-pid':'200',
... 'form-1-rel':'M',
... 'form-1-cid':'1243',
... 'form-1-rid':'1378',
... 'form-1-DELETE':'None'}
>>> 
>>> form=prelations(data=datana)
>>> connection.queries
[]
>>> form.is_valid()
True
>>> connection.queries
[{'sql': 'SELECT @@SQL_AUTO_IS_NULL', 'time': '0.000'}, {'sql': 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', 'time': '0.000'}, {'sql': 'SELECT `npr`.`rid`, `npr`.`PID`, `npr`.`rel`, `npr`.`CID` FROM `npr` ORDER BY `npr`.`rid` ASC', 'time': '0.037'}, {'sql': '

【问题讨论】:

  • 添加您的视图或调用 is_valid 的代码

标签: django django-forms formset


【解决方案1】:

幸运的是;我在文档中找到了缺失的部分 (Changing the queryset):

默认情况下,当您从模型创建表单集时,该表单集将 使用包含模型中所有对象的查询集(例如, 作者.objects.all())。您可以使用 查询集参数:

在验证导致 Django 检索整个底层模型并在模型中包含所有对象的表单集之前,我没有更改查询集。在创建将要验证的表单时,我应该使用用于生成表单集的相同查询集。验证应该是这样的:

qs = prs.objects.filter(Q(cid = 1243) | Q(pid = 1243))
form=prelations(data=datana, queryset = qs)

【讨论】:

    猜你喜欢
    • 2016-05-14
    • 2011-01-23
    • 2020-03-14
    • 1970-01-01
    • 2021-01-18
    • 2016-09-08
    • 2017-04-18
    • 2021-12-11
    • 1970-01-01
    相关资源
    最近更新 更多