Ovo trenutno radi na sledeći način: kad god se vrednost u combobox-u promeni, šalju se dva AJAX requesta. Prvi poziva view koji renderuje sledeći <select> ako kategorija ima 'dece', u suprotnom vraća HttpResponse koji prestaje da kači listener. Drugi request poziva view koji renderuje poseban, drugi ModelForm ako je selektovana kategorija root node (glavna kategorija), u suprotnom vraća HttpResponse koji kaže da se ne renderuje drugi ModelForm
Pokušavam da serviram posebni ModelForm baziran na selektovanoj glavnoj kategoriji. Na primer, ako postoje dve glavne kategorije, Books i Shoes, ako selektuješ Books, BookModelForm treba da se pojavi i proizvod treba biti sačuvan kao Book. Implementirao sam taj deo oko serviranja drugog ModelForm-a, ali problem je sam product_create_view i snimanje proizvoda u bazu.
views.py:
Code:
mappings = {
'1': BookProductForm,
'2': ShoesProductForm
}
def load_categories(request):
category_id = request.GET.get('category')
request.session['category'] = category_id
subcategories = Category.objects.get(id=category_id).get_children()
if subcategories:
return render(request, 'products/category_dropdown_list_options.html', {'subcategories': subcategories})
return HttpResponse('leaf_node')
def load_modelform(request):
category = request.GET.get('category')
form = mappings[category]
if Category.objects.get(id=int(category)).is_root_node():
return render(request, 'products/category_modelform.html', {'form': form})
return HttpResponse('dont_change_modelform')
@login_required
def product_create_view(request):
if request.method == 'POST':
create_product_form = CreateProductForm(request.POST, request=request)
if create_product_form.is_valid():
create_product_form.save()
else:
create_product_form = CreateProductForm(request=request)
return render(request, 'products/product_create.html', {'form': create_product_form})
mappings = {
'1': BookProductForm,
'2': ShoesProductForm
}
def load_categories(request):
category_id = request.GET.get('category')
request.session['category'] = category_id
subcategories = Category.objects.get(id=category_id).get_children()
if subcategories:
return render(request, 'products/category_dropdown_list_options.html', {'subcategories': subcategories})
return HttpResponse('leaf_node')
def load_modelform(request):
category = request.GET.get('category')
form = mappings[category]
if Category.objects.get(id=int(category)).is_root_node():
return render(request, 'products/category_modelform.html', {'form': form})
return HttpResponse('dont_change_modelform')
@login_required
def product_create_view(request):
if request.method == 'POST':
create_product_form = CreateProductForm(request.POST, request=request)
if create_product_form.is_valid():
create_product_form.save()
else:
create_product_form = CreateProductForm(request=request)
return render(request, 'products/product_create.html', {'form': create_product_form})
forms.py:
Code:
from django import forms
from django.forms import ModelForm
from .models import Product, Category, Book, Shoes
class CreateProductForm(ModelForm):
class Meta:
model = Product
fields = (
'title',
'description',
'price',
'stock',
'category'
)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super().__init__(*args, **kwargs)
self.fields['category'].queryset = Category.objects.filter(parent=None)
def clean_category(self):
category = Category.objects.get(id=self.request.session.get('category'))
if category.is_leaf_node():
return category
else:
raise forms.ValidationError('Please select the most specific category.')
class BookProductForm(ModelForm):
class Meta:
model = Book
fields = (
'title',
'description',
'price',
'stock',
'author',
'publisher',
'language',
'year',
'isbn'
)
class ShoesProductForm(ModelForm):
class Meta:
model = Shoes
fields = (
'title',
'description',
'price',
'stock',
'size',
'colour'
)
from django import forms
from django.forms import ModelForm
from .models import Product, Category, Book, Shoes
class CreateProductForm(ModelForm):
class Meta:
model = Product
fields = (
'title',
'description',
'price',
'stock',
'category'
)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super().__init__(*args, **kwargs)
self.fields['category'].queryset = Category.objects.filter(parent=None)
def clean_category(self):
category = Category.objects.get(id=self.request.session.get('category'))
if category.is_leaf_node():
return category
else:
raise forms.ValidationError('Please select the most specific category.')
class BookProductForm(ModelForm):
class Meta:
model = Book
fields = (
'title',
'description',
'price',
'stock',
'author',
'publisher',
'language',
'year',
'isbn'
)
class ShoesProductForm(ModelForm):
class Meta:
model = Shoes
fields = (
'title',
'description',
'price',
'stock',
'size',
'colour'
)
Template:
Code:
<h1>Create a product</h1>
<div class='modelform'>
<form method='POST' id='productForm' data-products-url="{% url 'products:ajax_load_categories' %}" data-modelform-url="{% url 'products:ajax_load_modelform' %}">
{% csrf_token %}
<div class='the-rest'>
{{ form.non_field_errors }}
{% for field in form %}
{% ifnotequal field.name 'category' %}
{{ field.label_tag }} {{ field }}
{{ field.errors }}
{% endifnotequal %}
{% endfor %}
</div>
<div class='categories'>
{{ form.category.label_tag }} {{ form.category }}
</div>
<input type="submit" name="" value="Submit">
</form>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
var $r_ = function() {
var url = $("#productForm").attr("data-products-url");
var categoryId = $(this).val();
var toRemove = $(this).nextAll('select');
$.ajax({
url: url,
data: {
'category': categoryId
},
success: function (data) {
if (data != 'leaf_node') {
toRemove.remove();
$(".categories").append(data);
}
else {
toRemove.remove();
}
}
});
var url2 = $('#productForm').attr('data-modelform-url');
$.ajax({
url: url2,
data: {
'category': categoryId
},
success: function (data) {
if (data != 'dont_change_modelform') {
$('.the-rest').empty();
$('.the-rest').append(data);
}
}
});
}
$(document).on('change', 'select', $r_);
</script>
<h1>Create a product</h1>
<div class='modelform'>
<form method='POST' id='productForm' data-products-url="{% url 'products:ajax_load_categories' %}" data-modelform-url="{% url 'products:ajax_load_modelform' %}">
{% csrf_token %}
<div class='the-rest'>
{{ form.non_field_errors }}
{% for field in form %}
{% ifnotequal field.name 'category' %}
{{ field.label_tag }} {{ field }}
{{ field.errors }}
{% endifnotequal %}
{% endfor %}
</div>
<div class='categories'>
{{ form.category.label_tag }} {{ form.category }}
</div>
<input type="submit" name="" value="Submit">
</form>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
var $r_ = function() {
var url = $("#productForm").attr("data-products-url");
var categoryId = $(this).val();
var toRemove = $(this).nextAll('select');
$.ajax({
url: url,
data: {
'category': categoryId
},
success: function (data) {
if (data != 'leaf_node') {
toRemove.remove();
$(".categories").append(data);
}
else {
toRemove.remove();
}
}
});
var url2 = $('#productForm').attr('data-modelform-url');
$.ajax({
url: url2,
data: {
'category': categoryId
},
success: function (data) {
if (data != 'dont_change_modelform') {
$('.the-rest').empty();
$('.the-rest').append(data);
}
}
});
}
$(document).on('change', 'select', $r_);
</script>
Pokušao sam ovo da rešim postojanjem samo jedne forme, CreateProductForm, kojoj bi prosledio model, ali sam došao u situaciju gde treba da dohvatim CreateProductForm klasu iz unutrašnje Meta klase.
Nisam siguran da je ovo pravo rešenje na prvom mestu, saveti dobrodošli.