Привет, друзья!
Я работаю над проектом на Django и у меня есть модель:
```python
class AccountModel(models.Model):
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
user_name = models.CharField("Account name", null=True, blank=True, max_length=256)
@property
def task_inwork_count(self):
return WorkModel.objects.filter(account=self.pk, status=1).count()
class WorkModel(models.Model):
account = models.ForeignKey("AccountModel", on_delete=models.CASCADE)
status = models.ForeignKey("StatusOfWork", default=1, on_delete=models.CASCADE)
```
Также у меня есть форма, в которой поле выбора для "account" должно заполняться моделями AccountModel, у которых свойство `task_inwork_count` равно 0.
Вот код формы:
```python
class AddWorkForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(AddWorkForm, self).__init__(*args, **kwargs)
choices = (
x
for x in AccountModel.objects.filter(
status=2, user_id=args[0]["user_id"]
)
if x.task_inwork_count == 0
)
print(choices)
self.fields["account"].queryset = choices
class Meta:
model = WorkModel
fields = ["account"]
```
Однако, при инициализации формы возникает ошибка:
```
File ".venv\Lib\site-packages\django\core\handlers\exception.py", line 55, in inner
response = get_response(request)
^^^^^^^^^^^^^^^^^^^^^
File ".venv\Lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
```
Не могли бы вы подсказать, в чем может быть проблема?
Ваша проблема заключается в том, что вы пытаетесь использовать свойство `task_inwork_count` в запросе при инициализации формы. При этом происходит выполнение отдельного SQL-запроса для каждой записи `AccountModel`, что может привести к ухудшению производительности и потенциальным ошибкам, особенно если в базе данных много записей.
Кроме того, ваш код неэффективен с точки зрения запросов к базе данных. Вам нужно отфильтровать `AccountModel` на уровне базы данных, а не в Python-коде. Для этого вы можете использовать `Subquery` или `OuterRef` для фильтрации записей с `task_inwork_count == 0` на уровне базы данных.
Вот как вы можете изменить ваш код:
```python
from django.db.models import Count, OuterRef, Subquery
from django import forms
class AddWorkForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(AddWorkForm, self).__init__(*args, **kwargs)
# Подзапрос, который считает задачи со статусом=1
subquery = WorkModel.objects.filter(
account=OuterRef('pk'),
status=1
).values('account').annotate(count=Count('id')).values('count')
# Фильтр для выбора только тех AccountModel, у которых count = 0
self.fields["account"].queryset = AccountModel.objects.filter(
status=2,
user_id=args[0]["user_id"]
).annotate(task_inwork_count=Subquery(subquery)).filter(task_inwork_count=0)
class Meta:
model = WorkModel
fields = ["account"]
```
В этом примере:
1. Мы создаём подзапрос, который использует `OuterRef`, чтобы сослаться на `AccountModel`, и подсчитывает количество связанных `WorkModel` с `status=1`.
2. Далее мы аннотируем `AccountModel`, добавляя поле `task_inwork_count`, основанное на результате подзапроса.
3. Наконец, мы фильтруем аннотированный queryset, чтобы оставить только те записи, где `task_inwork_count` равно 0.
Этот подход более производителен, так как условия фильтрации выполняются непосредственно на уровне СУБД, что позволяет избежать множественных запросов из Python к базе данных.
Мне надо ему дать AccountModel.objects.filter(status=2, user_id=args[0]["user_id"]), но что бы она еще фильтровалась по @property task_inwork_counttask_inwork_count нужно переносить на уровень SQL, читай про annotate и aggregate