Запрос к модели 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,
)

Это должно сработать!

Вернуться на верх