Задать вопрос
Ответы пользователя по тегу Django
  • Как добавить кнопку "Копировать в буфер" в django admin?

    А зачем эта кнопка нужна, если можно ctrl+a и ctrl+c? Ведь оно костыль. Напишите лучше об этом, например, в help_text, если надо в паре мест, или даже в шаблон жирными буквами.

    Но если все-таки есть желание... Самый простой способ - это поискать тут. Если там ничего нет, то остается "сложный".

    Я так понял, что речь идет именно про страницу редактирования. Нужно сделать отдельное приложение с скриптиком на JS и/или кастомным шаблоном, а также сделать класс/миксин для админки, чтобы удобно делать что-то в стиле:

    class YourModelAdmin(ClipboardMixin, admin.ModelAdmin):
        clipboard_fields = ('clipboardable_field',)

    Передать в шаблон нужные поля можно по-разному:
    • Передать в контекст имена нужных полей (см. пример в доках, который показывает, как в контекст что-нибудь передать).
    • Закастомить виджет поля формы, добавив туда определенный класс, если нужно.

    Второй вариант вижу правильным, его и будем реализовывать.

    class ClipboardMixin(object):
        #change_form_template = 'admin/clipboard_change_form.html'
        clipboard_class_name = 'your-clipboard-class'
        clipboard_fields = ()
    
        def get_form(self, request, obj=None, **kwargs):
            form = super(ClipboardModelAdmin, self).get_form(request, obj=None, **kwargs)
            for i in self.clipboard_fields:
                if i in form.base_fields:
                    if 'class' in form.base_fields[i].widget.attrs:
                        form.base_fields[i].widget.attrs['class'] += ' '+self.clipboard_class_name
                    else:
                        form.base_fields[i].widget.attrs['class'] = self.clipboard_class_name
            return form
    
        class Media:
            js = ('admin/clipboard.js',)

    Ну а дальше дело за скриптом. С буфером обмена все довольно костыльно, некрасиво, но сделать можно. Скрипт надо сделать универсально: если у поля есть определенный класс, то стоит добавить кнопочку "в буфер". Как вы это будете делать - не важно, я бы бейджик какой-нибудь навесил с абсолютным позиционированием, но можно и шаблон поправить.
    Ответ написан
    Комментировать
  • Как можно проверить изображение в POST?

    Написать тест.
    Ответ написан
    Комментировать
  • Как реализовать ранжирование результатов полнотекстового поиска по тексту и тагам в Django + Sphinx (sphinxit библиотека)?

    У вас не совсем полный вопрос. Он про ранжирование или про то, как подружить теги со сфинксом? А как теги реализованы? Поэтому я напишу обзорный ответ, который покажет, куда копать, что делать. Сам я использовал однажды django-sphinx (ныне заброшенный) для похожих задач (только по тегам не сортировал, ибо задача у меня была по ним уточнять). А вот sphinxit не использовал, поэтому будем рассматривать сначала "голый" сфинкс, а потом уже sphinxit как надстройку. Так что могу где ошибиться, наврать.

    Примем, что у вас классическая реализация тегов (тагов? хы) в виде таблички с тегами + many-to-many в табличку с элементами (так, например, делает django-taggit).

    В сфинксе есть полнотекстовые поля (по ним он строит специальную структуру (индекс), чтобы быстро искать совпадения по ключевым словам). Они не хранятся в первоначальном виде, только в виде индекса. Есть еще атрибуты, они прикрепляются к индексу, по ним потом можно фильтровать, они именно хранятся в индексе. Это разные числовые значения (типа price или customer_id) или строковые или даже JSON, по ним обычно удобно фильтровать, уточнять запрос. Есть еще MVA - это тоже атрибуты, но представляют из себя множества числовых значений. А как их задать в сфинксе - пример. Вообще, такая возможность (атрибуты и MVA в частности) сделана, чтобы разгрузить БД и нагрузить сфинкс. :)

    MVA-атрибуты подходят, чтобы в них хранить тэги и подобное (many-to-many), даже в доках написано:

    That is useful to implement article tags, product categories, etc.

    Ранжирование - это очень комплексный алгоритм. Для полнотекстовых полей в сфинксе есть специальные ранкеры, среди которых есть алгоритм BM25 и наивные ранкеры, например SPH_RANK_WORDCOUNT, который как раз и выполняет простой подсчет вхождений ключевых слов и учитывает вес поля. По атрибутам же можно фильтровать и сортировать. По MVA тоже можно фильтровать и сортировать.

    Дальше буду говорить в рамках языка запросов SphinxQL. Можно еще обращаться к его API, но все равно вы используйте обертку, да и язык запросов как-то попроще для объяснения. В доках встречаются примеры из реализации API на PHP иногда, причем про SphinxQL пояснений нет, но это не значит, что через него нельзя это сделать (или значит, надо смотреть).

    Для вашей задачи нужно сделать SELECT с функцией LENGTH() по MVA-атрибуту с тегами, далее по нему отсортировать с помощью ORDER_BY в нужном порядке, а также сделать фильтрацию с помощью WHERE, где указать вхождение тегов в атрибут с помощью оператора IN. Оператор WHERE - это комбайн фильтров по атрибутам и полнотекстового поиска. Таким образом можно рассортировать результаты по длине MVA-атрибута (количеству тегов).

    Можно сюда добавить полнотекстовое ранжирование еще (включается с помощью SetRankingMode или с помощью OPTION в SphinxQL) у полнотекстовых полей (по алгоритму BM25, например, что по умолчанию), и сортировать в ORDER_BY и по длине MVA-атрибута с тегами и по WEIGHT() от ранкера (см. доки на предмет примеров); возможно или даже скорее всего, тут придется выбрать еще WEIGHT() в SELECT (раньше он неявно возвращался в ORDER_BY, я это тоже не тестировал). В таком случае будет круто: например, если подряд попадется 50 записей с одинаковым количеством тегов, то они будут отсортированы по весу ранжирующего алгоритма.

    В общем, ваша задача красиво решается. Учитывая пример выше, можно с помощью исключительно только сфинкса реализовать и полное совпадение по тегам (сравнивать LENGTH() с количеством тегов в WHERE). И подобное.

    Если же теги хранятся как-то неклассически (highload и т.п.), то их в любом случае можно будет достать либо в MVA, либо сделать полнотекстовым полем (в таком случае ранкер SPH_RANK_WORDCOUNT как раз применим). Поэтому суть та же.

    Думаю, на все "теоретические" вопросы касательно ранжирования и сфинкса я ответил. Тут есть поле и для хорошего ранжирования и для оптимизации запросов, надо экспериментировать.

    Теперь же в рамках sphinxit. Согласно его докам, он умеет и ранкеры включать и на SphinxQL говорить. Надо просто там все это оформить. Не исключены подводные камни, возможно, что-то он не сможет сделать, возможно, где-то и я наврал. По идее нужно уметь делать фильтрацию (тык), сортировку (тык), а тут даже пример, как включать ранкер + описание возможных ранкеров. Кажется, если что, то можно и в селект дописать условие. В общем, все выглядит дружелюбно, удачи!

    Кстати, в документации sphinxit в примерах опций (ссылка выше) есть пример, где включен ранкер, но в ORDER BY условие только сортировать по атрибуту name. По идее это должно убить весь смысл ранкера для сортировки, ведь его надо явно указывать в ORDER BY. Видимо, там просто пример, как это конвертится в SphinxQL.

    p.s. Странно, что уже как 4+ дня прошло, и на этот вопрос никто не написал ответа. Sphinx не популярен? :(
    Ответ написан
    5 комментариев
  • Как вывести defaultdict поэлементно в шаблоне Django?

    Создаете кастомный фильтр, который достает элемент из dict.

    @register.filter
    def get_item(v, a):
        return v.get(a)

    Теперь в шаблоне можно сделать (или даже для этого использовать переменные):

    {{ foo|get_item:1|get_item:3 }}

    p.s. Но зачем тут defaultdict, да и вообще dict? Почему нe list?
    Ответ написан
    4 комментария
  • Какими модулями вы пользуетесь для SEO Django?

    Я эволюционно шел:
    1. Сначала просто вбивал переменные в методе формирования контекста.
    2. Добавил стандартные мета-теги в модель с настройками (на случай, если нечего вбивать).
    3. Добавил мета-теги в модель, допустим, с категорией и понял, что стоит создать абстрактный класс, от которого позже наследовал и базовые настройки и эту модель.
    4. Понял, что вьюхи сильно дублируют код: постоянно присваиваю переменным одно и то же.
    5. В базовой вьюхе определил переменную, которая определяет, какие мета-теги используются, для каждой из них сделал метод ее получения, теперь во вьюхах пишу просто список мета-тегов, оно пытается выгрузить их из модели, либо найти метод, который их вернет (такой метод нужен на случай, если мета-теги не заполнены и нужно вместо seo_title подставить просто name).
    6. Понял, что, по-хорошему, тут нужно создать приложение, которое сможет расширять любую вьюху. То есть отвязать его от моей базовой вьюхи и подарить сообществу.
    7. Наконец-то решил погуглить: нашел django-meta, которое делает все то же самое, только чуть более изящно, автор явно прошел дальше по эволюционной ветке.
    8. Приуныл, собираюсь использовать вот буквально завтра.

    Оно выглядит хорошо: предоставляет базовый класс с мета-тегами, миксин для вьюхи (который экземпляр класса добавит в context). Можно забить мета-тег либо статично во вьюху, либо сделать метод для его динамического получения. Вкупе с абстрактной моделью это получается удобно, в данный момент я не могу придумать лучше.

    Да, что касается админки. Если там нужны какие-то стандартные действия с полями SEO, типа как добавление их в fieldsets, лучше тоже создать миксин, который переопределил get_fieldsets, например (или что там у вас).

    p.s. Я не думаю, что все это имеет смысл на сайте-визитке, например. Я бы делал такое начиная с масштаба интернет-магазина и более.
    Ответ написан
    Комментировать
  • Как обновить дату в поле модели django при смене текущего года?

    Обновлять по крону - это красивое решение. У вас дата очень напрашивается быть в БД и работать с миром как обычное поле. Как я понимаю, хранится она долго, создается при сохранении объекта модели, обновляется раз в год. Здесь не нужен метод, который проверяет ее актуальность, потому что вам эта проверка не нужна подавляющее большинство времени. Должен быть просто метод, заполняющий дату и ничего больше не делающий. Тем более, если после 1 января у вас будет пик посещений, вы получите дополнительную нагрузку на БД, плюс еще и неактуальные в ней данные останутся. Привязывать обновление данных к запросу нехорошо. Гораздо лучше крон, который сделает ее актуальной незаметно в 4:03 утра 1 января для всех сразу.

    Если бы это была быстро меняющаяся информация, то тогда подобный метод + кэш были бы кстати.
    Ответ написан
    Комментировать