Запрос к модели Django и сравнение ее полей на предмет сходства или близких дубликатов
У меня есть модель, которая записывает изменения других моделей в моей базе данных.
Я хотел бы запросить изменения, которые добавляют только символ новой строки -- \n
.
Моя модель изменений выглядит следующим образом:
class Change(models.Model):
object_type = models.ForeignKey(
ContentType,
related_name="object_change_set",
on_delete=models.CASCADE,
)
object_id = models.CharField(max_length=255, db_index=True)
object = GenericForeignKey("object_type", "object_id")
old_fields = models.JSONField(encoder=JSONEncoder, null=True, blank=True)
new_fields = models.JSONField(encoder=JSONEncoder, null=True, blank=True)
По сути, я хочу найти случаи Change
, где разница между значением ключа в old_fields
и new_fields
составляет \n
.
Вот как выглядят new_fields
:
{
"body": "Had a great time on Wednesday.",
"created": "2022-06-15T19:49:06.784Z",
}
И аналогично, old_fields
:
{
"body": "Had a great time on Wednesday.\n",
"created": "2022-06-15T19:49:06.784Z",
}
Обратите внимание, что new_fields
и old_fields
оба являются JSONFields
.
В конечном итоге, я хочу удалить экземпляры Change
, которые только добавляют \n
к body
.
Я понимаю, что могу сделать это путем итерации по набору запросов и поиска этих расхождений, но мне интересно, есть ли более элегантное решение.
Вы можете использовать фильтры __startswith
(вместе с выражением F()
) и __endswith
, чтобы проверить, начинается ли тело old_fields
с тела new_fields
и заканчивается ли оно :
from django.db.models import F
queryset = Change.objects.filter(
old_fields__body__startswith=F("new_fields__body"), old_fields__body__endswith="\n"
)
Однако это все равно будет соответствовать, если тело old_fields
будет содержать любую строку между концом тела new_fields
и завершающим переводом строки (например, "Had a great time on Wednesday.aaaaaaaaaaaaaaaaaa\n"
). Чтобы исправить это, вы можете аннотировать набор запросов функцией Length
и проверить, равна ли длина тела old_fields
тела Length("new_fields__body") + 1
:
from django.db.models import F
from django.db.models.functions import Length
queryset = Change.objects.annotate(old_body_len=Length("old_fields__body")).filter(
old_fields__body__startswith=F("new_fields__body"),
old_fields__body__endswith="\n",
old_body_len=Length("new_fields__body") + 1,
)
Это должно сработать!