Добавить jquery в widget Django

Есть два простых способа добавить jQuery в формы или виджеты в админку django

1. Добавление другой версии jQuery

Сначала нужно скачать jQuery. В качестве примера для этой статьи я использовал jQuery.2.2.0. Помещаем её, например, сюда: my_project/static/jquery/jquery-2.2.0.min.js.

my_app/forms.py
from django import forms
from django.conf import settings

from my_app.models import MyModel


class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        exclude = ()

    class Media:
        js = [settings.JQUERY_URL, 'my_app/my_script.js']
settings.py
import os

...
JQUERY_URL = os.path.join(STATIC_URL, 'jquery/jquery-2.2.0.min.js')
...

2. Использование Django jQuery

my_app/forms.py
from django import forms
from django.conf import settings

from my_app.models import MyModel


class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        exclude = ()

    class Media:
         extra = '' if settings.DEBUG else '.min'  # to use minified libraries or not
         js = [f'admin/js/vendor/jquery/jquery{extra}.js',
               'admin/js/vendor/jquery/jquery.init.js'
               'my_app/admin_compat.js',
               'my_app/my_script.js']
my_app/admin_compat.js
if (window.django !== undefined) var jQuery = django.jQuery, $ = django.jQuery;

В зависимости от того, находится ли наш код в режиме разработки или в продакшене, используем полную или минифицированную версию jquery. Это нужно обязательно сделать, иначе будет либо на локальной машине, либо на продакшене загружаться две версии jquery - это не только избыточный код, но и может произойти, что подключённая библиотека локально может работать, а на продакшене нет и наоборот.

admin/js/vendor/jquery/jquery(/.min).js - версия jquery, которая идёт в коробке с Django.

admin/js/vendor/jquery/jquery.init.js - переименовывает $ в django.jQuery для того, чтобы избежать конфликта имён, если на странице используются разные версии библиотеки jquery (или даже, если другая библиотека использует для сокращения такой же знак $). Вот его код:

var django = django || {};
django.jQuery = jQuery.noConflict(true);

Но так как чаще мы используем знак $ в наших скриптах, например:

$('.test_btn').click(function(){
    alert('clicked');
});

то нужно сделать обратное преобразование, как это сделано в admin_compat.js - добавляет $ (в том числе и jQuery) в пространство имён javascript.

Мы можем и не использовать admin_compat.js, но в таком случае нам придётся использовать django jquery так:

(function('.test_btn').click(function(){
    alert('clicked');
})(django.jQuery);

Также, если мы хотим использовать $ в наших скриптах, нам не следует просто использовать jquery Django без jquery.init.js и admin_compat.js:

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        exclude = ()

    class Media:
         extra = '' if settings.DEBUG else '.min'
         # плохое использование своих скриптов без jquery.init.js и admin_compat.js
         js = [f'admin/js/vendor/jquery/jquery{extra}.js', 'my_app/my_script.js']

Потому что Django может использовать jquery.init.js при рендере других частей страницы, например, рендер inline-объектов, и в этом случае $ переименуется в django.jQuery и для вашего скрипта my_script.js функция $ будет undefined.

Ещё хочу напомнить, что если использовать шаблон админки унаследованный, например, от base_site.html, то нужно всё-равно явно выводить переменную media:

my_app/views.py
from django.core import management
from django.shortcuts import redirect, render
from django.views.generic import View

from my_app.forms import MyModelForm


class TestView(View):
    template_name = 'admin/my_app/test_template.html'
    form = MyModelForm

    def get(self, request, *args, **kwargs):
        return render(request, self.template_name, {'form': self.form()})

    def post(self, request, *args, **kwargs):
        form = self.form(request.POST)

        if form.is_valid():
            # some handling...
            return redirect('/')

        return render(request, self.template_name, {'form': form})
my_app/urls.py
from django.conf.urls import url
from django.contrib.auth.decorators import user_passes_test

from my_app.views import TestView


urlpatterns = [
    url(r'^my_test/$', user_passes_test(lambda u: u.is_superuser)(TestView.as_view()), name='my_test'),
]
my_app/templates/admin/my_app/test_template.html
{% extends "admin/base_site.html" %}
{% load i18n %}

{% block title %}Кастомная страница админки{% endblock %}

{% block extrahead %}{{ block.super }}
    <script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script>
    {{ form.media }}
    {% comment %}Примечание: Можно и сюда загружать свои скрипты и здесь управлять порядком загрузки скприптов{% endcomment %}
{% endblock %}

{% block content %}
    <div class="fieldsets">
        <fieldset class="module">
            <h1>Кастомная страница админки</h1>

            <p>Содержание страницы</p>
        </fieldset>
    </div>
{% endblock %}

Так как {{ media }} выводится только в change_form.html (и ещё delete_confirmation.html и delete_selected_confirmation.html, если быть точным):

lib/python2.7/site-packages/django/contrib/admin/templates/admin/change_form.html
{% extends "admin/base_site.html" %}
{% load i18n admin_urls static admin_modify sb_tags %}

{% block extrahead %}{{ block.super }}
<script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script>
{{ media }}
{% endblock %}

{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />{% endblock %}

{% block coltype %}colM{% endblock %}
...

Порядок загрузки скриптов в формах и виджетах django

Выше описанные способы работают, когда хочешь загружать в админку свои скрипты. Но если есть такие виджеты, которые требуют jQuery, то нужно загружать jQuery до загрузки виджетов, так как при рендере страницы сначала загружаются скрипты виджетов, а потом уже то, что объявлено в Media у класса Form.

Пока я нашёл единственное решение - раширять виджеты, добавляя в класс Media jquery на первые позиции. Как это сделать, я покажу на примере django-select2.

Добавить jQuery в django-select2

Устарело!
Это актуально для django-select2 <= 7.7.1

Вот так захочешь по-быстрому поставить автокомплит Select2 для Select в админку Django:

from django_select2.forms import Select2Widget

class MyForm(forms.Form):
    my_choice = forms.ChoiceField(widget=Select2Widget)

И не получается.. Потом выясняется из документации, что jQuery не идёт в комплекте с виджетом:

External Dependencies
- jQuery version 2. This is not included in the package since it is expected that in most scenarios this would already be available.

Казалось бы, ладно, нужно просто добавить отдельно jQuery в форму, например так:

class MyAdminForm(forms.ModelForm):

    class Media:
        model = MyModel
        js = ('path/to/jquery.js', )  # Объявленные скрипты в Media добавятся после скриптов всех используемых виджетов.

Но Select2 не заработает! Так как объявленные стили и скрипты в Media добавятся после стилей и скриптов всех используемых виджетов:

my_app/my_model/1/change/ (просмотр кода в браузере загруженной страницы)
<head>
...
<link href="/static/select2/css/select2.css" type="text/css" media="all" rel="stylesheet">
<link href="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" type="text/css" media="screen" rel="stylesheet">

<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/i18n/ru.js"></script>
<script type="text/javascript" src="/static/django_select2/django_select2.js"></script>

<script type="text/javascript" src="/static/jquery/jquery.js"></script>
...
</head>

Чтобы jquery загружалось раньше скриптов select2, я переопределил класс Media, создав свой класс Select2Widget и унаследовав его от базового:

my_app/widgets.py
from django.conf import settings
from django_select2.forms import Select2Widget as BaseSelect2Widget


class Select2Widget(BaseSelect2Widget):
    """
    Added jquery to widget
    """
    def _get_media(self):
        media = super()._get_media()

        css = ['select2/css/select2.css']  # если нужно какие-то стили переопределить
        css.extend(media._css['screen'])

        extra = '' if settings.DEBUG else '.min'
        js = [f'admin/js/vendor/jquery/jquery{extra}.js', 'admin/js/jquery.init.js', 'my_app/js/admin_compat.js']
        js.extend(media._js)

        return forms.Media(js=js, css={'screen': css})

    media = property(_get_media)

В этом коде, как видите, я использовал jquery, который идёт в комплекте с django. Если вы хотите использовать свою версию jquery, то просто замените строку:

extra = '' if settings.DEBUG else '.min'
js = [f'admin/js/vendor/jquery/jquery{extra}.js', 'admin/js/jquery.init.js', 'my_app/js/admin_compat.js']

на:

js = ['jquery/jquery.js']

Теперь можно также использовать Select2Widget, как описано в документации, импортируя свой Select2Widget:

my_app/forms.py
from my_app.widgets import Select2Widget

class MyForm(forms.Form):
   my_choice = forms.ChoiceField(widget=Select2Widget)

Оцените статью

5 из 5 (всего 1 оценка)

captcha
Отмеченные звёздочкой поля ( * ) являются обязательными для заполнения.

Спасибо за ваш отзыв!

После нажатия кнопки "Отправить" ваше сообщение будет доставлено мне на почту.

Автор статьи

Артём Мальцев

Веб-разработчик, владеющий знаниями языка программирования Python, фреймворка Django, системы управления содержимым сайта Django CMS, платформы для создания интернет-магазина Django Shop и многих различных приложений, использующих эти технологии.

Права на использование материала, расположенного на этой странице https://vivazzi.pro/ru/it/jquery-to-widget-django/:

Разрешается копировать материал с указанием её автора и ссылки на оригинал без использования параметра rel="nofollow" в теге <a>. Использование:

Автор статьи: Артём Мальцев
Ссылка на статью: <a href="https://vivazzi.pro/ru/it/jquery-to-widget-django/">https://vivazzi.pro/ru/it/jquery-to-widget-django/</a>

Больше: Правила использования сайта

Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.

Книга предназначается для широкого круга читателей и, по мнению автора, будет полезна специалистам отдела закупок и логистики, категорийным и финансовым менеджерам, менеджерам по продажам, аналитикам, руководителям и директорам, в компетенции которых принятие решений по управлению ассортиментом.

Комментарии: 0

Вы можете оставить комментарий как незарегистрированный пользователь.

Но зарегистрировавшись, вы сможете:

  • получать оповещения об ответах
  • просматривать свои комментарии
  • иметь возможность использовать все функции разработанных сервисов

Для комментирования от своего имени войдите или зарегистрируйтесь на сайте Vuspace

Отправить

На данный момент нет специального поиска, поэтому я предлагаю воспользоваться обычной поисковой системой, например, Google, добавив "vivazzi" после своего запроса.

Попробуйте

Выберите валюту для отображения денежных единиц