Ответы пользователя по тегу Django
  • Как в Django подключить JavaScript?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    <script type="text/javascript" src={% static "js/jquery.min.js" %}></script>
    <script type="text/javascript" src={% static "js/main.js" %}></script>
    Ответ написан
  • Как проверить, есть ли уже такая запись в БД?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Для ответа на оба вопроса, см. в документации Django следующие разделы:

    По первой ссылке можно найти как проверять наличие записи в БД. Но это думаю Вам сейчас не нужно.

    По второй ссылке можно найти как сделать кастомное представление (view) для авторизации пользователя и проверять авторизован ли пользователь в других представлениях.

    Google Translate и/или Яндекс.Переводчик в помощь.
    Ответ написан
  • Как заставить джангу рендерить темплейты, доставая их же из бд?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Это не извращение. Батарейки с WYSIWYG редакторами для того же Django так и работают (django-ckeditor, django-tinymce, django-summernote и пр.).

    Аналогичные расширения для Flask должны работать примерно так же (см. flask-ckeditor). Разница в том, что Flask гибкий и его могут готовить с разными ORM и СУБД, а потому разработчики расширений часто это учитывают.

    Но в общем виде, вывод HTML из СУБД в шаблон так и выглядит:
    • во вьюхе запрашиваешь из СУБД портянку с HTML,
    • добавляешь её в словарь контекста с каким-нибудь ключом,
    • выводишь переменную в шаблоне с фильтром | safe.
    Ответ написан
  • Как разделить реализацию различных типов модели?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Может быть django-polymorphic подойдёт:
    https://django-polymorphic.readthedocs.io/en/stabl...

    При многотабличном наследовании, Django ORM по-умолчанию позволяет получать все записи родительской и дочерних моделей только как объекты класса родительской модели.

    Библиотека django-polymorphic позволяет, делая запрос объектов родительской модели, получать объекты разных классов (как родительской, так и дочерних моделей).

    Плюс там реализованы классы, позволяющие адаптировать админку Django к удобной работе с полиморфными данными.

    Например, иметь в админке единый подраздел для родительской и дочерних моделей с фильтром записей по типу, при создании проходить через промежуточную страницу с выбором типа, а так же скажем выбирать тип при создании записей в инлайн-полях. Причём, всё достаточно опционально.
    Ответ написан
  • Как правильно вывести меню с использованием django-mptt?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Место в документации:
    https://django-mptt.readthedocs.io/en/latest/tutor...

    Пример использования в Интернет-магазине для вывода выпадающего каталога товаров:
    https://github.com/ri-gilfanov/python-t/blob/maste...

    Если лень вчитываться в весь шаблон, вот вкратце:
    {% load static mptt_tags %}
    
    {% recursetree category_tree %}
        <li>
            <a class="btn btn__light" href="{% url 'category' node.pk %}">
                <span style="flex: 1 1 auto;">{{ node.name }}</span>{% if not node.is_leaf_node %}
                <span>&nbsp;</span><span class="fa fa-angle-right"></span>{% endif %}
            </a>
            {% if not node.is_leaf_node %}
                <ul  class="site_nav_primary__submenu ul__column white_box">
                    {{ children }}
                </ul>
            {% endif %}
        </li>
    {% endrecursetree %}


    Переменная шаблона category_tree -- это дерево категорий, формируемое в контекст-процессоре, посмотреть его можно тут:
    https://github.com/ri-gilfanov/python-t/blob/maste...

    А модель категорий можно найти тут:
    https://github.com/ri-gilfanov/python-t/blob/maste...

    В разметке из шаблона выше, каждый элемент дерева категорий именуется node (т.е. узел). В общем-то, это обычный объект модели Django ORM.

    Скажем, формирование ссылки:
    <a class="btn btn__light" href="{% url 'category' node.pk %}"></a>


    В одном из urls.py есть route (маршрут) с именем category, принимающий id категории. Обычно, node.pk и node.id -- это одно и то же, но я предпочитаю брать .pk, чтобы независеть от реального названия первичного ключа.

    А вот этот фрагментик из фрагмента выше:
    {% if not node.is_leaf_node %}
        <ul  class="site_nav_primary__submenu ul__column white_box">
            {{ children }}
        </ul>
    {% endif %}


    ...значит следующее. Если узел (node) верхнего уровня содержит дочерние узлы, то мы делаем вложенные маркерованные списки (ul) с особыми стилями CSS, а переменная {{ children }} означает, что внутри тегов с каждым дочерним элементом будет происходить всё то же самое, что и с узлами верхнего уровня.

    Если псевдокодом на русском:
    {% рекурсивное_дерево дерева_категорий %}
        Открываем HTML-теги для узлов верхнего уровня
        и что-то делаем с узлами верхнего уровня.
            {% если узел верхнего уровня содержит дочерние узлы %}
                открываем html-теги, в которые хотим завернуть дочерние узлы
                    {{ дети }}
                закрываем html-теги
            {% конец если про детей %}
        Если нужно, ещё что-то делаем с узлами верхнего уровня
        и закрываем HTML-теги.
    {% конец рекурсивного дерева %}


    Правда, в примере из интернет-магазина, я делаю проверку на наличие дочерних узлов дважды.

    Первый раз, я использую её чтобы добавить "небездетным" узлам иконку со стрелочкой, чтобы пользователь знал, что можно навести мышкой и выпадут дочерние категории.

    Таким образом, эту проверку можно использовать в разных местах, если нужно по-разному оформить узды с детьми и узлы без детей.

    Извиняюсь, если изложил немного путанно. Однако, разобраться во всех возможностях django-mptt можно за один вечер. Документация есть, а при сложностях с английским можно воспользоваться онлайн-переводчиками.
    Ответ написан
  • Как организовать удобную разработку Django пакета (батарейки)?

    ri_gilfanov
    @ri_gilfanov Автор вопроса
    Web- and desktop-developer
    Сергей Горностаев предложил использовать tox, а в документации этого инструмента я наткнулся на более простое и удобное решение.

    В документации setuptools есть раздел Development mode.

    Если вместо команды install использовать команду develop
    python3 setup.py develop
    пакет не будет собран и полноценно установлен в глобальное или виртуальное окружение.

    Вместо этого, в глобальном или виртуальном окружении будет создана ссылка на исходники пакета (ссылка представляет собой файл с расширением .egg-link).

    После этого, пакет становится доступен для импорта.

    Если импортировать такой пакет в Django-проект, сделать manage.py runserver и начать редактировать исходники пакета -- встроенный в Django сервер для разработки как обычно перезапускается при каждом сохранении исходников пакета. Хотя импортированный пакет может лежать где угодно в файловой системе.

    Таким образом, работая над батарейкой для Django -- можно тут же видеть изменения в запущенном Django-проекте, без необходимости переустанавливать батарейку после каждой правки её исходников.

    Спасибо, проблема решена просто, дёшево и элегантно.

    P.S. Предложенная Сергеем библиотека tox больше подходит для автоматизации тестирования Python проекта во множестве разных рабочих окружений. Например, если Вы гарантируете пользователям поддержку разных версий требуемых библиотек, разных версий интерпретатора, разных интерпретаторов и т.д. -- tox может серьёзно облегчить Вам жизнь.

    P.P.S. Если кто-то не знает как пользоваться setuptools и создавать установочные файлы для своих Python пакетов -- есть статьи и даже видео на русском языке. Например:
    Ответ написан
  • Возможно ли корректное переопредение свойства _meta.app_label у моделей contrib.auth в Django?

    ri_gilfanov
    @ri_gilfanov Автор вопроса
    Web- and desktop-developer
    Понял, при каких обстоятельствах это работает.

    Если провести все миграции и только потом переопределить app_label для Group и Permission -- всё работает как надо. Имена таблиц остаются с префиксом auth_, но в админке модели группируются в одном разделе.

    Если закомментировать это переопределение -- можно создавать и делать миграции.

    В иных случаях, будет либо изложенное в вопросе, либо поломанная миграция:
    AttributeError: 'ManyToManyField' object has no attribute 'm2m_reverse_field_name'


    В общем, сомнительное решение. Надёжнее переопределить вьюхи/шаблоны админки или поставить соответствующую батарейку (например, django-admin-tools, django-suit или django-grappelli).
    Ответ написан
  • Как избавится от автоматического дописывания символов к имени изображения для уникальности?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Был похожий вопрос:
    Почему когда в django admin в ImageField добавлю картинку то django admin создаёт новую и загружает её?

    Схожим образом проверять совпадение имён файлов, удалять старый файл и загружать новый.

    Но как быть с одноимёнными, но разными файлами? Пользователи сайта будут вольно и невольно подменять уже загруженные изображения на свои. Переносить опыт работы с файловой системой на веб-сайт можно только в случае, если Вы единственный пользователь.

    В случае многопользовательского проекта, для повторного использования изображений стоит завести под них отдельную модель. А в модели статей сделать ForeignKey на модель изображений.
    Ответ написан
  • Как отрдактировать форму регистрации django?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Maxemp, вкратце.

    Объявить дочерний класс форм, унаследовавшись от UserCreationForm.

    Переопределить метод __init__ дочернего класса, в нём можно поменять что угодно.

    В данном случае, примерно так:

    class MyUserCreationForm(UserCreationForm):
        def __init__(self, *args, **kwargs):
            super(UserCreationForm, self).__init__(*args, **kwargs)
            self.fields['username'].help_text = ''
            self.fields['password'].help_text = ''


    После чего, использовать MyUserCreationForm во вьюхе вместо стандартной UserCreationForm.

    Другой возможный вариант, переопределить у дочернего класса не метод __init__, а вложенный класс Meta. Выглядит примерно так:

    class MyUserCreationForm(UserCreationForm):
        class Meta:
            model = User
            help_texts = {
                'password': '',
                'username': '',
            }


    Но я обычно всё через __init__ переопределял. Да и указание модели вроде обязательно, а значит лишний импорт и маленькая тонкость при кастомной модели пользователя.
    Ответ написан
  • Как переопределить возможные значения ManyToManyField в InlineModelAdmin с учётом значения другого поля инлайн-формы?

    ri_gilfanov
    @ri_gilfanov Автор вопроса
    Web- and desktop-developer
    Спасибо Anatoly Scherbakov, что натолкнул на решение.

    class VariantAttributeForm(ModelForm):
        def __init__(self, *args, **kwargs):
            super(VariantAttributeForm, self).__init__(*args, **kwargs)
            if 'instance' in kwargs:
                self.fields['values'].queryset = Variant.objects.filter(filter=kwargs['instance'].filter)
    
        class Meta:
            model = VariantAttribute
            fields = '__all__'
    
    class VariantAttributeInline(admin.TabularInline):
        form = VariantAttributeForm
    Ответ написан
  • Как дать имена анонимным юзерам в Django?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    Как вариант -- использование сессий: https://djbook.ru/rel1.9/topics/http/sessions.html

    В сессию пользователя можно добавлять любые данные в виде ключ-значение, а равно удалять из неё любые данные.

    Пример кода, обрабатывающего POST-запросы для временной регистрации, а так же удаления никнейма для анонимного пользователя:
    def chat_login(request):
        # Регистрируем псевдоним для чата на 30 дней
        if 'register' in request.POST:
            request.session.set_expiry(2592000)  # устанавливаем время жизни сессии
            request.session['username'] = request.POST['username']
        # Удаляем псевдоним для чата из своей сессии
        if 'unregister' in request.POST:
            request.session['username'].pop(request.POST['username'])


    Преимущества сессий в данном случае:
    - не нужно переопределять какие-либо модели,
    - можно хранить любые данные,
    - минимум кода.

    Недостатки:
    - сложнее проконтролировать уникальность имён пользователей,
    - у сессии должно быть время жизни (хотя его и можно продливать в любой вьюхе, обновив значение любого ключа).
    Ответ написан
  • Почему когда в django admin в ImageField добавлю картинку то django admin создаёт новую и загружает её?

    ri_gilfanov
    @ri_gilfanov
    Web- and desktop-developer
    По мнению разработчиков Django -- нормально.

    Если хочется изменить такое поведение по-быстрому:
    from django.db import models
    from django.db.models.signals import post_delete
    
    
    def change_image(post_object):
        # функция удаления изображений при их замене на новые
        post_object = self
        try:
            pre_object = post_object.__class__.objects.get(id=post_object.id)
            if pre_object.image != post_object.image:
                pre_object.image.delete(save=False)
        except:
            pass
    
    
    def delete_image(sender, **kwargs):
        # функция удаления изображений при удалении объектов
        try:
            object_ = kwargs.get('instance')
            storage, path = object_.image.storage, object_.image.path
            storage.delete(path)
        except:
            pass
    
    
    class MyModel(models.Model):
        # наша модель с картинкой
        image = models.ImageField(
            upload_to='images/',
        )
    
        def save(self, *args, **kwargs):
            # вызов change_image при сохранении объекта модели
            change_image(post_object=self)
            super(Category, self).save(*args, **kwargs)
    
    
    # прикрепляем функцию delete_image к сигналу post_delete от модели MyModel
    post_delete.connect(receiver=delete_image, sender=MyModel)


    Думал доработать данный костыль в инвалидную коляску, а именно -- так чтобы название поля модели не имело значения. Например, при изменении и удалении объекта, через цикл прогонять все поля модели, чтобы применять проверки и операции ко всем FileField и ImageField в модели.

    По-хорошему же, лучше разобраться с файловыми полями моделей и сделать своё кастомное. Рассматриваемая задача конечно мелочь, но опыт может пригодится.
    Ответ написан
  • Почему не срабатывает перевод verbose_name для приложений пакета django-allauth, устанавливленного через pip?

    ri_gilfanov
    @ri_gilfanov Автор вопроса
    Web- and desktop-developer
    В файлах локализации с расширением .po, часть переведённых строк имеет пометку нечёткий перевод:
    #, fuzzy
    И игнорируется при компиляции файлов с расширением .mo

    Если нечёткий перевод устраивает больше, чем английский оригинал -- русскую локализацию можно перекомпилировать и с использованием fuzzy-строк:
    python3 manage.py compilemessages --use-fuzzy --locale=ru

    или так:
    python3 manage.py compilemessages -f -l ru

    Результат:
    3de85ce26c9744b9a0de75612755eeab.png

    Благодарю sim3x за точную ссылку в документации.
    Ответ написан