Я хотів би відфільтрувати свою модель на основі довжини тексту Щось на зразок
MyModel.objects.filter(len(text) > 10)
де текст - це поле Char або Text у моделі MyModel
Я хотів би відфільтрувати свою модель на основі довжини тексту Щось на зразок
MyModel.objects.filter(len(text) > 10)
де текст - це поле Char або Text у моделі MyModel
Відповіді:
Було б набагато краще і швидше, якби ви просто додали стовпець, який попередньо обчислює (запам'ятовує) довжину тексту.
напр
class MyModel(models.Model):
text = models.TextField()
text_len = models.PositiveIntegerField()
def save(self, *args, **kwargs):
self.text_len = len(self.text)
return super(MyModel, self).save(*args, **kwargs)
MyModel.objects.filter(text_len__gt = 10) # Here text_len is pre-calculated by us on `save`
text
. Це оновлюється щоразу, коли текст змінюється. Отже, коли ми запитуємо модель, ми можемо відфільтрувати за довжиною тексту, яку МИ попередньо розрахували за нашим save
методом.
Для Django> = 1,8 ви можете використовувати функцію Length , яка є @ Pratyush CHAR_LENGTH()
під капотом для MySQL, або LENGTH()
для деяких інших баз даних:
from django.db.models.functions import Length
qs = MyModel.objects.annotate(text_len=Length('text_field_name')).filter(
text_len__gt=10)
text_len__gt=10
в першу чергу ( order_by
). Будь-який натяк?
text_len
анотацію таким же чином , ви будете використовувати будь-який інший бази даних поля , тому він працює в order_by
або Sum
або будь-який інший . Щоб відсортувати результати в порядку спадання тексту довжини і повертає значення довжини: MyModel.objects.annotate(text_len=Length('text_field_name')).order_by('-text_len').values_list('text_len', flat=True)
.
Length
Transform.
Sum
. Це також надзвичайно важливо для багатьох випадків. У мене був випадок, коли мені потрібно було попередньо перевірити максимальний обсяг даних, який може повернути запит, не призведе до втрати пам'яті сервера, і варіант цього працював чудово.
Length
оператора. Тож це називається перетворенням або відображенням . Агрегації зменшують кількість записів. Відображення не роблять.
Інший спосіб:
MyModel.objects.extra(where=["CHAR_LENGTH(text) > 300"])
Це можна використовувати, якщо довжина тексту також перевищує 255 символів.
LENGTH(..)
.
Гарне рішення для Django> = 1.9 можливо, зареєструвавши вбудовану функцію Length
як Transform forCharField
пошуку.
Зареєструйте трансформацію в проекті один раз. (Найкраще місце - це, мабуть, models.py.)
from django.db.models import CharField
from django.db.models.functions import Length
CharField.register_lookup(Length, 'length')
Використання :
result = MyModel.objects.filter(text__length__gt=10)
Дивіться точно такий самий приклад у документах щодо Length як перетворення .
Він працює коректно для всіх серверних систем, складених LENGTH()
для більшості серверів і CHAR_LENGTH()
для MySQL. Потім він автоматично реєструється для всіх підкласів CharField, наприклад для EmailField. TextField
реєструється індивідуально. Зареєструвати ім'я "довжина" безпечно, оскільки ім'я перетворення ніколи не може затінювати або затінювати однаково іменованим полем або пов'язаним ім'ям поля.
Єдиним недоліком могла б бути головоломка для читабельності: Звідки взялася "довжина"? (Пошук здійснюється глобально, але той самий може бути, на щастя, безпечно повторно зареєстрований у більшості модулів, якщо це зручно для читабельності, без будь-яких можливих накладних витрат під час виконання запиту.)
Іншим настільки ж цінним рішенням є наведена вище плита , яка коротша, якщо враховується реєстрація та якщо подібний запит не використовується повторно.
Ви можете використовувати регулярний вираз для пошуку тексту певної довжини:
MyModel.objects.filter(text__regex = r'.{10}.*')
Застереження: для MySQL максимальне значення довжини становить 255. В іншому випадку створюється виняток:
DatabaseError: (1139, "Got error 'invalid repetition count(s)' from regexp")
Using raw strings (e.g., r'foo' instead of 'foo') for passing in the regular expression syntax is recommended.
Я вирішив би проблему на вашому сервері додатків, а не оподатковував вашу базу даних. Ви можете зробити це, виконавши:
models_less_than_ten = []
mymodel = MyModel.objects.all()
for m in mymodel:
if len(m.text) > 10:
models_less_than_ten.append(m)