Я должен выполнить запрос к большой базе данных с несколько сложным моделированием, которое я попытаюсь сократить ниже:
class ScreeningItem(models.Model):
# other fields
receivedItem = models.OneToOneField(ReceivedItem, null=True, on_delete=models.SET_NULL)
class ReceivedItem(models.Model):
# other fields
dossier = models.ForeignKey(Dossier, null=True, on_delete=models.SET_NULL)
class Dossier(models.Model):
# other fields
subjects = models.ManyToManyField('SubjectTypes', through='Subjects',
through_fields=('dossier', 'subjectType'))
class Subject(models.Model):
main = models.BooleanField(null=True)
dossier = models.ForeignKey(Dossier, null=True, on_delete=models.SET_NULL)
subjectType = models.ForeignKey(SubjectType, null=True, on_delete=models.SET_NULL)
class SubjectType(models.Model):
# other fields
name = models.CharField(max_length=255, null=True, blank=True)
parent = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
Теперь проблема в том, что я должен найти в ScreeningItem
элементах таблицы когда поле "далеко-далеко" SubjectType.name
содержит определенные c слов. Нет, хуже. Как вы можете видеть ниже, в этой модели есть ссылка на себя «родитель-потомок», и я должен искать эти c слов в родственном SujectType
, его родительском элементе и его прародителе, если они существуют.
Моя попытка:
exp = 'something'
queryset = ScreeningItem.objects.filter(
Q(receivedItem__dossier__subjects__subjecttype__name__iregex=exp) |
Q(receivedItem__dossier__subjects__subjecttype__parent__name__iregex=exp) |
Q(receivedItem__dossier__subjects__subjecttype__parent__parent__name__iregex=exp))
Однако, когда я получил количество записей намного меньше, чем я ожидал, я проверил базу данных и, к своему удивлению, обнаружил, что было много ScreeningItem
, которые имели a ReceivedItem
с Dossier
, который был связан с SubjectTypes
, в котором было слово, которое я искал.
К сожалению, мне не разрешено раскрывать содержание здесь. Итак, я написал процедуру тестирования ниже:
def test():
exp = 'something' # valid and equal both for Python and MySQL regular expression engines
re_exp = re.compile(exp, re.IGNORECASE)
queryset_1 = ScreeningItem.objects.filter(
Q(receivedItem__dossier__subjects__subjecttype__name__iregex=exp) |
Q(receivedItem__dossier__subjects__subjecttype__parent__name__iregex=exp) |
Q(receivedItem__dossier__subjects__subjecttype__parent__parent__name__iregex=exp))
set_1 = set(queryset_1.values_list('id', flat=True))
print(len(set_1))
queryset_2 = GnomoItemTriagem.objects.filter(receivedItem__dossier__isnull=False)
set_2a = set()
set_2b = set()
for item in queryset_2:
subjects = item.receivedItem.dossier.subjects
if subjects.filter(
Q(name__iregex=exp) |
Q(parent__name__iregex=exp) |
Q(parent__parent__name__iregex=exp)).count() > 0:
set_2a.add(item.id)
for subject in subjects.all():
if re_exp.findall(subject.name) or\
(subject.parent and re_exp.findall(subject.parent.name)) or \
(subject.parent and subject.parent.parent and re_exp.findall(subject.parent.parent.name)):
set_2b.add(item.id)
print(len(set_2a))
print(len(set_2b))
И тогда мои результаты были
1596
21223
21223
Итак, как должен быть написан мой 1-й запрос, чтобы также вернуть все необходимые 21223 элемента? Что я делаю не так?