Django Admin зависимое выпадающее поле HTML
I have a Region and SubRegion ForeignKey in the Country Model. My SubRegion model also has a Region ForeignKey for the Region Model. I am having a hard time displaying the SubRegion dropdown in the Country Model on the basis of the Region selected.
Как лучше всего этого добиться? Было бы здорово, если бы выпадающие элементы основывались на значении их родителя.
models.py
class Region(models.Model):
name = models.CharField(max_length=20)
is_active = models.BooleanField(verbose_name='is active?', default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
class SubRegion(models.Model):
region = models.ForeignKey(Region, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
is_active = models.BooleanField(verbose_name='is active?', default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
class Meta:
verbose_name_plural = 'Sub Regions'
class Country(models.Model):
name = models.CharField(max_length=100)
region = models.ForeignKey(Region, on_delete=models.CASCADE, verbose_name='Region')
subregion = models.ForeignKey(SubRegion, on_delete=models.CASCADE, verbose_name='Sub Region')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
admin.py
class CountryAdmin(admin.ModelAdmin):
list_display = ('name', 'is_active', 'is_default', 'created_at', 'updated_at', )
list_filter = ('region', 'subregion', 'is_active', 'is_default', 'created_at', 'updated_at', )
search_fields = ('name', 'official_name', )
fieldsets = (
('Region Information', {'fields': ('region', 'subregion', )}),
('Basic Information', {'fields': ('name', 'official_name', )}),
('Codes Information', {'fields': ('cca2', 'ccn3', 'cca3', 'cioc','idd', 'status', )}),
('Coordinates', {'fields': ('latitude', 'longitude', )}),
('Membership & Statuses', {'fields': (('is_independent', 'is_un_member', 'is_default', 'is_active', ), )}),
('Country Flag', {'fields': ('png_flag_url', 'svg_flag_url', )}),
('Country Map', {'fields': ('google_map_url', 'openstreet_map_url', )}),
('Additional Information', {'fields': ('population', 'area', 'start_of_week', 'postal_code_format', 'postal_code_regex', )}),
)
inlines = [CountryTopLevelDomainInline, CountryCurrencyInline, CountryTimezoneInline]
admin.site.register(Country, CountryAdmin)
В настоящее время, когда я собираюсь добавить/редактировать страну, весь регион и субрегион отображаются в выпадающем списке выбора. Я хочу получить возможность загружать субрегион на основе выбора региона.
После долгих исследований я смог решить эту проблему.
Я создал JS файл внутри моего приложения.
static\geo_location\js\chained-region.js
var response_cache = {};
function get_subregion_for_region(region_id) {
(function($){
var selected_value = $("#id_subregion").val();
if(response_cache[region_id]){
$("#id_subregion").html(response_cache[region_id]);
$("select#id_subregion option").each(function(){
if ($(this).val() == selected_value)
$(this).attr("selected","selected");
});
} else {
$.getJSON("/geo-location/get-subregions-for-region", {region_id:region_id}, function(res, textStatus){
var options = '<option value="" selected="selected">---------</option>';
$.each(res.data, function(i, item){
options += '<option value="' + item.id + '">' + item.name + '</option>';
});
response_cache[region_id] = options;
$("#id_subregion").html(response_cache[region_id]);
$("select#id_subregion option").each(function(){
if ($(this).val() == selected_value)
$(this).attr("selected","selected");
});
});
}
})(django.jQuery);
}
затем, добавил функцию views для обработки AJAX запросов.
views.py
from django.http import JsonResponse
from django.contrib.auth.decorators import login_required
from .models import SubRegion
@login_required
def subregion_for_region(request):
if 'region_id' in request.GET and request.GET['region_id'] != '':
subregions = SubRegion.objects.filter(region=request.GET['region_id'])
return JsonResponse({'data': [{'id': subregion.id, 'name': subregion.name} for subregion in subregions]})
else:
return JsonResponse({'data': []})
Примечание:- Я добавил декоратор @login_required, чтобы предотвратить ненужный вызов.
В admin.py я создал форму и добавил событие "onchange" для выпадающего региона.
admin.py
from django import forms
class CountryForm(forms.ModelForm):
class Meta:
model = Country
fields = '__all__'
widgets = {
'region': forms.Select(attrs={'onchange': 'get_subregion_for_region(this.value);'})
}
class CountryAdmin(admin.ModelAdmin):
....
form = CountryForm
class Media:
js = (
'geo_location/js/chained-region.js',
)
И последнее добавление шаблона URL в файл urls.py приложения. urls.py
from django.urls import path
from . import views
app_name = 'geo_location'
urlpatterns = [
path('get-subregions-for-region/', views.subregion_for_region, name='subregions-for-region'),
]