Django Пользовательские формы в наборах форм с использованием CBV
Я хочу создать новый сайт и одновременно добавить соответствующие публикации. Мне приходится использовать специальную форму для "сайта" из-за большого набора данных, связанного с ним через внешний ключ "муниципалитет"
У меня есть эти модели:
class site(models.Model):
sid = models.AutoField(primary_key=True)
site_name = models.CharField(max_length=250)
site_notes = models.CharField(max_length=2500, blank=True, null=True)
municipality = models.ForeignKey('local_administrative_unit', on_delete=models.PROTECT)
geom = models.PointField(srid=4326)
def __str__(self):
return '{}, {} ({})'.format(self.sid, self.site_name, self.municipality)
lass cit_site(models.Model):
cit_site_id = models.AutoField(primary_key=True)
publication = models.ForeignKey('publication', on_delete=models.PROTECT)
site = models.ForeignKey('site', on_delete=models.PROTECT)
first_page = models.IntegerField(null=True, blank=True)
last_page = models.IntegerField(null=True, blank=True)
notes = models.CharField(max_length=500, null=True, blank=True)
def __str__(self):
return '{}: {} - {}'.format(self.publication.pub_id, self.first_page, self.last_page)
На данный момент форма site просто добавляет site через представление на основе класса. Из-за большого набора данных муниципалитетов, загрузка формы заняла бы вечность и было бы не очень удобно выбирать нужный муниципалитет (16k+ записей в этой таблице на данный момент), поэтому я сделал эту пользовательскую форму:
class NewSiteForm(DynamicFormMixin, forms.Form):
def land_choices(form):
country = form['country'].value()
return models.administrative_level_4.objects.filter(adm_level_5=country)
def land_initial(form):
country = form['country'].value()
return models.administrative_level_4.objects.filter(adm_level_5=country).first()
def district_choices(form):
land = form['land'].value()
return models.administrative_level_3.objects.filter(adm_level_4=land)
def district_inital(form):
land = form['land'].value()
return models.administrative_level_3.objects.filter(adm_level_4=land).first()
def town_choices(form):
district = form['district'].value()
return models.administrative_level_2.objects.filter(adm_level_3=district)
def town_initial(form):
district = form['district'].value()
return models.administrative_level_2.objects.filter(adm_level_3=district).first()
def municipality_choices(form):
town = form['town'].value()
return models.local_administrative_unit.objects.filter(adm_level_2=town)
def municipality_initial(form):
town = form['town'].value()
return models.local_administrative_unit.objects.filter(adm_level_2=town).first()
country = forms.ModelChoiceField(
queryset=models.administrative_level_5.objects.all(), empty_label='Select a country...'
)
land = DynamicField(
forms.ModelChoiceField,
queryset=land_choices,
initial=land_initial
)
district = DynamicField(
forms.ModelChoiceField,
queryset=district_choices,
initial=district_inital
)
town = DynamicField(
forms.ModelChoiceField,
queryset=town_choices,
initial=town_initial
)
siteMunicipality = DynamicField(
forms.ModelChoiceField,
queryset=municipality_choices,
initial=municipality_initial
)
siteNotes = forms.CharField(
required=False,
widget=forms.Textarea
)
siteName = forms.CharField()
В нем используется некоторое количество htmx для заполнения каскадных выпадающих элементов, что позволяет ему загружаться намного быстрее. Вид выглядит следующим образом:
class NewSiteView(FormMixin, View):
form_class = forms.NewSiteForm
template_name = 'datamanager/newsiteCascade.html'
success_url = 'datamanager/newsiteCascade.html'
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {'form':form})
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
pol = models.local_administrative_unit.objects.values('geom').filter(lau_id=form.cleaned_data['siteMunicipality'].lau_id)[0]['geom']
cent_point = pol.centroid
geom = cent_point.wkt
municipality = form.cleaned_data['siteMunicipality']
site_name = form.cleaned_data['siteName']
site_notes = form.cleaned_data['siteNotes']
new_site = models.site(site_name = site_name, site_notes=site_notes, municipality=municipality, geom=geom)
new_site.save()
if 'Save' in request.POST:
return HttpResponseRedirect(reverse_lazy('data_manager:all_sites'))
elif 'SaveAnother' in request.POST:
return HttpResponseRedirect(reverse_lazy('data_manager:new_site'))
###############################################################
## HTMX Queries
###############################################################
def lands(request):
form = forms.NewSiteForm(request.GET)
return HttpResponse(form['land'])
def districts(request):
form = forms.NewSiteForm(request.GET)
return HttpResponse(form['district'])
def towns(request):
form = forms.NewSiteForm(request.GET)
return HttpResponse(form['town'])
def siteMunicipalities(request):
form = forms.NewSiteForm(request.GET)
return HttpResponse(form['siteMunicipality'])
Однако в настоящее время мне приходится добавлять литературу на эти сайты из другой формы (просто модельформы из модели cit_site, показанной выше) после создания сайта. Я хочу сделать все это за один раз, чтобы я мог создать site, добавить цитаты и сохранить все вместе. Я также хочу продолжать использовать каскадные выпадающие элементы из формы выше, чтобы избежать проблемы загрузки.
Насколько я понимаю, мне нужно использовать некий набор форм, который хранит обе формы. Но все, что я нашел до сих пор, использовало modelforms, что не было бы полезно в моем случае (нет пользовательской формы). Кроме того, данные для родительской формы, похоже, уже должны существовать при отображении набора форм. Поэтому мне нужна помощь в решении этой проблемы (возможно, это две проблемы в одной?). Заранее спасибо.