Как показать форму Django в шаблоне?
Я хочу отображать страны и штаты в Django форме, для этого я пытаюсь получить данные из json, создать форму, передать json данные в форму и получить состояние страны по ajax запросу. Мне удалось написать процесс, насколько я понял, но в итоге форма не отображается на шаблоне Django. Как я могу отобразить форму Django со следующей структурой кода?
Моя модель:
from django.db import models
class Address(models.Model):
country = models.CharField(null=True, blank=True, max_length=100)
state = models.CharField(null=True, blank=True, max_length=100)
def __str__(self):
return '{} {}'.format(self.country, self.state)
Моя форма:
from django import forms
from .models import Address
import json
def readJson(filename):
with open(filename, 'r') as fp:
return json.load(fp)
def get_country():
""" GET COUNTRY SELECTION """
filepath = './static/data/countries_states_cities.json'
all_data = readJson(filepath)
all_countries = [('-----', '---Select a Country---')]
for x in all_data:
y = (x['name'], x['name'])
all_countries.append(y)
return all_countries
def return_state_by_country(country):
""" GET STATE SELECTION BY COUNTRY INPUT """
filepath = './static/data/countries_states_cities.json'
all_data = readJson(filepath)
all_states = []
for x in all_data:
if x['name'] == country:
if 'states' in x:
for state in x['states']:
y = (state['name'], state['name'])
all_states.append(state['name'])
else:
all_states.append(country)
return all_states
class AddressForm(forms.ModelForm):
country = forms.ChoiceField(
choices = get_country(),
required = False,
label='Company Country Location',
widget=forms.Select(attrs={'class': 'form-control', 'id': 'id_country'}),
)
class Meta:
model = Address
fields = ['country']
Моя форма.html
<form class="" action="" method="post">
{% csrf_token %}
{% for error in errors %}
<div class="alert alert-danger mb-4" role="alert">
<strong>{{ error }}</strong>
</div>
{% endfor %}
<div class="row">
<div class="col-lg-6">
<div class="mb-4">
{{ form.country}}
</div>
</div>
<div class="col-lg-6">
<div class="mb-4">
<div class="form-group">
<label >Select a Province/State</label>
<select id="id_province" class="form-control" name="state">
<option value="-----">Select Province/State</option>
</select>
</div>
</div>
</div>
</div>
</form>
Мой AJAX:
<script>
$("#id_country").change(function () {
var countryId = $(this).val();
$.ajax({
type: "POST",
url: "{% url 'get-province' %}",
data: {
'csrfmiddlewaretoken': '{{ csrf_token }}',
'country': country
},
success: function (data) {
console.log(data.provinces);
let html_data = '<option value="-----">Select Province/State</option>';
data.provinces.forEach(function (data) {
html_data += `<option value="${data}">${data}</option>`
});
$("#id_province").html(html_data);
}
});
});
</script>
Мой путь URL:
path('get-province',views.getProvince, name='get-province'),
path('process-form',views.processForm, name='process-form'),
Обработчик аякса:
def getProvince(request):
country = request.POST.get('country')
provinces = return_state_by_country(country)
return JsonResponse({'provinces': provinces})
Мои взгляды:
def processForm(request):
context = {}
if request.method == 'GET':
form = AddressForm()
context['form'] = form
return render(request, 'address.html', context)
if request.method == 'POST':
form = AddressForm(request.POST)
if form.is_valid():
selected_province = request.POST['state']
obj = form.save(commit=False)
obj.state = selected_province
obj.save()
Таким образом форма должна отображаться, но она не работает. Не могли бы вы помочь мне, почему я терплю неудачу? Как я могу решить эту проблему?
С ModelForms
я обнаружил, что этот тип конфигурации, в которой все подпадает под class Meta:
, работает.
Однако я сомневаюсь в этом методе get_country()
. Если вы поделитесь им, я смогу посмотреть глубже и, возможно, даже протестировать его, чтобы убедиться, что он не делает ничего странного
Если ваш список стран несколько статичен и не слишком длинный, вы можете рассмотреть возможность использования типа TextChoices
enum в атрибуте вашей модели для ограничения выбора. Django forms автоматически отобразит выпадающий виджет со списком элементов из вашего перечисления.
Вы можете проверить этот ответ, если вы хотите изучить это, который далее ссылается на документацию django.
class AddressForm(forms.ModelForm):
class Meta:
model = Address
fields = ['country']
widgets = {
"country": forms.ChoiceField(
choices = get_country(),
attrs={
"class": "form-control",
"id": "id_country"
}
),
}
labels = {
"country" : "Company Country Location"
}