Метод Django modelformset is_valid извлекает всю модель из базы данных

У меня есть modelformset, когда вызывается метод is_valid, все объекты модели базовой формы извлекаются из базы данных, что неэффективно, если таблица базы данных содержит сотни тысяч записей, я считаю, что 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 для тестирования, потому что хочу сделать вопрос кратким и избежать сложностей полного приложения, и оба дали одинаковые результаты.

>>> 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': '

person Abdul    schedule 27.07.2020    source источник
comment
Добавьте свое представление или код, который вызывает is_valid   -  person Iain Shelvington    schedule 27.07.2020


Ответы (1)


К счастью; Я нашел недостающую часть, в документации говорится (Изменение набора запросов):

По умолчанию, когда вы создаете набор форм из модели, набор форм будет использовать набор запросов, включающий все объекты в модели (например, Author.objects.all()). Вы можете переопределить это поведение, используя аргумент набора запросов:

Я не менял набор запросов перед проверкой набора форм, что заставляло Django извлекать всю базовую модель и включать все объекты в модель. Я должен был использовать тот же набор запросов, который использовался для создания набора форм при создании формы, которая будет проверена. Проверка должна проходить следующим образом:

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