Как использовать цепочку селектов django_select2 в панели администратора django?
Я взял почти неизменное руководство из документации есть мой models.py
from django.db import models
class Country(models.Model):
name = models.CharField(max_length=255)
class City(models.Model):
name = models.CharField(max_length=255)
country = models.ForeignKey('Country', related_name="cities", on_delete=models.CASCADE)
class Address(models.Model):
country = models.ForeignKey('Country', on_delete=models.CASCADE)
city = models.ForeignKey('City', on_delete=models.CASCADE)
и создали ModelForm, потому что простая форма из документации не подходит для панели администратора
class AddressForm(forms.ModelForm):
class Meta:
model = Address
fields = '__all__'
widgets = {
'country': ModelSelect2Widget(
model=Country,
search_fields=['name__icontains'],
),
'city': ModelSelect2Widget(
model=City,
search_fields=['name__icontains'],
dependent_fields={'country': 'country'},
max_results=500,
)
}
на простой, не админской, странице он работает нормально. Я попробовал это только для тестирования. Мне действительно нужно только в админ панели. Вот шаблон из документации
<!DOCTYPE html>
<html lang="en">
<head>
<title>Create Book</title>
{{ form.media.css }}
<style>
input, select {width: 100%}
</style>
</head>
<body>
<h1>Create a new Book</h1>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
{{ form.media.js }}
</body>
</html>
и класс представления
class AddressCreateView(generic.CreateView):
model = models.Address
form_class = forms.AddressForm
success_url = "/"
template_name = 'address.html'
Но в панели администратора эта же форма не работает. Selects не содержит никаких элементов и нет поля поиска. также нет никаких запросов, отправленных на сервер, которые я могу видеть при взаимодействии с selects на простой странице
from django.contrib import admin
from .models import City, Country, Address
from .forms import AddressForm
@admin.register(Address)
class AddressAdmin(admin.ModelAdmin):
class Media:
js = (
'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js',
)
form = AddressForm
admin.site.register(City)
admin.site.register(Country)
Этот ответ сэкономит вам много времени, НЕ используйте 'django_select2' для реализации цепочки полей select в админке Django, вместо этого используйте Django AutoComplete Light с Django-Hacker. Где DAL будет отвечать за реализацию AJAX запросов для получения данных для цепочки Select2 полей, а Django-Hacker сэкономит ваше время, настраивая стандартные формы Django непосредственно из любого места в api без необходимости создавать специальные формы для вашего класса администратора.
ШАГ1: установите указанные пакеты, а затем добавьте следующие пакеты сверху INSTALLED_APPS
в settings.py
файл:
settings.py
INSTALLED_APPS = [
'dal',
'dal_select2',
]
Примечание: это обязательно отменит скрипт jquery.init.js
, предоставленный администратором, который устанавливает jQuery с помощью noConflict
, делая jQuery доступным только в django.jQuery
, а не $
(глобально).
ШАГ2: Убедитесь, что вы зарегистрировали ваш api urls.py
файл в главном urls.py
файле вашего Django проекта.
ШАГ 3: Создайте класс представления, который будет использоваться для получения и обновления данных (с помощью AJAX) для вашего цепного поля Select2 на странице администратора, как показано в примере ниже.
views.py
from dal import autocomplete
from your_api.models import model_name, depend_on_model
class MyAutocompleteView(autocomplete.Select2QuerySetView):
"""Select2 autocomplete view class to return queryset for chained Select2 field
on admin page depending on specific field value"""
def get_queryset(self):
"""Customize the queryset for this class view"""
# Note: Don't forget to filter out results depending on the visitor !
# Make sure the HTTP request is made by authenticated user, if
# unauthenticated then return nothing.
if not self.request.user.is_authenticated:
return model_name.objects.none()
value = self.forwarded.get('query_string_name', None)
# Check if HTTP request have a value for the query string (URL parameter).
if value:
queryset = depend_on_model.objects.filter(
depend_on_field=value
).order_by('-created_at')
return queryset
ШАГ 4: Наконец, вам нужно зарегистрировать это представление в вашем api urls.py
файле и в то же время создать поле формы для вашего цепного поля Select2.
urls.py
from django.urls import path
from django import forms
from dal import autocomplete
import djhacker
from your_api import views
from your_api.models import model_name
# Define a variable that help to identify which api that creating URL from when
# using reverse function.
app_name = 'your_api'
urlpatterns = [
path(
'my-autocomplete/',
views.MyAutocompleteView.as_view(),
name='my-autocomplete',
),
]
# Now hack your model field to always render the autocomplete field with
# that view!
djhacker.formfield(
# Specify the field of the model.
model_name.field_name_to_be_chained_selec2,
# Specify the form field type, since our field is a Foreign key, so we set
# it to be choice field.
forms.ModelChoiceField,
# Set the widget for this form field.
widget=autocomplete.ModelSelect2(
# Set your django api url:
# '<api name>:<name of the registered view path>'
#
# Note: make sure you registered the api routes in your main 'urls.py' file.
url='your_api:my-autocomplete',
# Set the depend on field in order to be forward its value to the view.
forward=['depend_on_field'],
# You can set some options for this Select2 field.
attrs={
# Set placeholder
'data-placeholder': 'Autocomplete...',
},
)
)
Вот и все, мы просто сделали цепочку Select2, которая зависит от значения другого поля, и вы можете проверить его на странице администратора Django для связанной модели без необходимости создавать сложный настраиваемый ajax файл, настраивать ваш Django admin JavaScript или добавлять кэш-сервер... и т.д.