Dependent forms in Django using AJAX - javascript

In my project I am trying to add a dependent forms solution from this answer. My template seems to accept all data correctly, but it is not displayed in the city field.
Models
class Country(models.Model):
name = models.CharField(max_length=50)
def __unicode__(self):
return u'%s' % (self.name)
class City(models.Model):
name = models.CharField(max_length=50)
country = models.ForeignKey(Country, on_delete=models.CASCADE)
def __unicode__(self):
return u'%s' % (self.name)
urls
path('getdetails/', views.getdetails, name='getdetails'),
path('new-post/', views.new_post, name='new_post'),
views
from django.shortcuts import render
from django.http import JsonResponse
from django.http import HttpResponse
def new_post(request):
countries = Country.objects.all()
[...]
def getdetails(request):
#country_name = request.POST['country_name']
country_name = request.GET['cnt']
result_set = []
all_cities = []
answer = str(country_name[1:-1])
selected_country = Country.objects.get(name=answer)
print("selected country name ", selected_country)
all_cities = selected_country.city_set.all()
print(all_cities)
for city in all_cities:
print("city name", city.name)
result_set.append({'name': city.name})
return HttpResponse(JsonResponse({'result_set': result_set}))
templates
<select name="selectcountries" id="selectcountries">
{% for item in countries %}
<option val="{{ item.name }}"> {{ item.name }} </option>
{% endfor %}
</select>
<select name="selectcities" id="selectcities">
</select>
<!-- and jquery -->
<script type="text/javascript" src="http://yourjavascript.com/7174319415/script.js"></script>
<script>
$(document).ready(function() {
$('select#selectcountries').change(function() {
var optionSelected = $(this).find("option:selected");
var valueSelected = optionSelected.val();
var country_name = optionSelected.text();
data = {
'cnt': country_name
};
ajax('/getdetails', data, function(result) {
console.log(result);
$("#selectcities option").remove();
for (var i = result.length - 1; i >= 0; i--) {
$("#selectcities").append('<option>' + result[i].name + '</option>');
};
});
});
});
</script>
As you can see, my template receives AJAX responses, but doesn't match the form, and all cities are always undefinied. How do I fix my error to show the correct cities?
https://www.awesomescreenshot.com/video/2878370?key=0b43f35b4587436854d2fbe2ae317b6f (video)

The call back to ajax returns the response. You need to access the result_set yet.
ajax('/getdetails', data, function(response) {
console.log(response);
$("#selectcities option").remove();
for (var i = response.result_set.length - 1; i >= 0; i--) {
$("#selectcities").append('<option>' + response.result_set[i].name + '</option>');
};
});

Related

How to insert data to the same table id with Javascript Clone Code?

I am trying something with django and i need clone the form elements.
I found some code, it works but it inserts the different table id. I wanna clone two form fields with js clone code. It clones and then post the fields, when i looked the database, i see two fields inserterd tho different ids. How can i fix this?
When you look database image, same numbers but different id's. How can i insert data to same id with two form fields.
This is create_normal.html
Here is the database
Here is my codes.
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class PatientBilgi(models.Model):
name = models.CharField(max_length=155)
surname = models.CharField(max_length=155)
def __str__(self):
return self.name
class PatientAliskanlik(models.Model):
sigara = models.CharField(max_length=155)
alkol = models.CharField(max_length=155)
def __str__(self):
return self.sigara
class Patient(models.Model):
name = models.CharField(max_length=155)
pbilgi = models.ForeignKey(PatientBilgi, on_delete=models.CASCADE, blank=True, null=True)
palis = models.ForeignKey(PatientAliskanlik, on_delete=models.CASCADE, blank=True, null=True)
def __int__(self):
return self.name
forms.py
from django import forms
from .models import Patient, PatientBilgi, PatientAliskanlik
from django.forms import (formset_factory, modelformset_factory)
class PatientForm(forms.ModelForm):
class Meta:
model = Patient
fields = ['name']
class PatientBilgiForm(forms.ModelForm):
class Meta:
model = PatientBilgi
fields = ['name', 'surname']
class PatientAliskanlikForm(forms.ModelForm):
class Meta:
model = PatientAliskanlik
fields = ['sigara', 'alkol']
###### Formsets
class PatientBilgiModelForm(forms.ModelForm):
class Meta:
model = PatientBilgi
fields = ('name', 'surname' )
labels = {
'name': 'Patient Name',
'surname': 'Patient Surname'
}
widgets = {
'name': forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Enter Patient Name and Surname here'
}
)
}
PatientBilgiFormset = formset_factory(PatientBilgiForm)
BookModelFormset = modelformset_factory(
PatientBilgi,
fields=('name', 'surname', ),
extra=1,
widgets={
'name': forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Enter Patient Name here'
}
),
'surname': forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Enter Patient Surname here'
}
)
}
)
PatientFormset = modelformset_factory(
Patient,
fields=('name', ),
extra=1,
widgets={'name': forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Enter Author Name here'
})
}
)
views.py
from django.shortcuts import render, redirect
from django.urls import reverse
from .models import Patient, PatientBilgi, PatientAliskanlik
from .forms import PatientForm, PatientBilgiForm, PatientAliskanlikForm, PatientBilgiFormset, PatientBilgiModelForm, PatientFormset
from formtools.wizard.views import SessionWizardView
# Create your views here.
def home(request):
return render(request, 'home.html')
def hasta_listele(request):
data = Patient.objects.all()
return render(request, 'deneme.html', {'data': data})
def hasta_detay(request, id):
kata = Patient.objects.get(id=id)
kata1 = PatientBilgi.objects.get(id=id)
kata2 = PatientAliskanlik.objects.get(id=id)
return render(request, 'hasta_detay.html',
context = {
'kata': kata,
'kata1': kata1,
'kata2': kata2}
)
# Multi Step Form Submission
class multistepformsubmission(SessionWizardView):
template_name = 'hasta_kayit.html'
form_list = [PatientBilgiForm, PatientAliskanlikForm, PatientForm]
def done(self, form_list, **kwargs):
form_data = [form.cleaned_data for form in form_list]
patientdata = PatientBilgi(name = form_data[0]['name'], surname = form_data[0]['surname'])
patientdata.save()
patientdata1 = PatientAliskanlik(sigara = form_data[1]['sigara'], alkol = form_data[1]['alkol'])
patientdata1.save()
patientdata2 = Patient(name = form_data[2]['name'] )
patientdata2.save()
data = Patient.objects.all()
data1 = PatientBilgi.objects.all()
data2 = PatientAliskanlik.objects.all()
return render(self.request, 'done.html', context={
'data': data,
'data1': data1,
'data2': data2
})
######## Deneme Amaçlı Fonksiyon, gereği yok....
def deneme(request):
a = Patient.objects.all()
return render(request, "a.html", {'a': a })
##################
########## Formset Fonskiyonu
def create_book_normal(request):
template_name = 'create_normal.html'
if request.method == 'GET':
formset = PatientBilgiFormset(request.GET or None)
elif request.method == 'POST':
formset = PatientBilgiFormset(request.POST)
if formset.is_valid():
for form in formset:
name = form.cleaned_data.get('name')
surname = form.cleaned_data.get('surname')
# save book instance
if name:
PatientBilgi(name=name).save()
PatientBilgi(surname=surname).save()
return redirect('done')
return render(request, template_name, {
'formset': formset,
})
def done1(request):
return render(request, 'done.html')
create_normal.html
<form class="form-horizontal" method="POST" action="">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
<div class="row form-row spacer">
<div class="col-2">
<label>{{form.name.label}}</label>
</div>
<div class="col-4">
<div class="input-group">
{{form.name}}
{{form.surname}}
<div class="input-group-append">
<button class="btn btn-success add-form-row">+</button>
</div>
</div>
</div>
</div>
{% endfor %}
<div class="row spacer">
<div class="col-4 offset-2">
<button type="submit" class="btn btn-block btn-primary">Create</button>
</div>
</div>
</form>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script type="text/javascript">
function updateElementIndex(el, prefix, ndx) {
var id_regex = new RegExp('(' + prefix + '-\\d+)');
var replacement = prefix + '-' + ndx;
if ($(el).attr("for")) $(el).attr("for", $(el).attr("for").replace(id_regex, replacement));
if (el.id) el.id = el.id.replace(id_regex, replacement);
if (el.name) el.name = el.name.replace(id_regex, replacement);
}
function cloneMore(selector, prefix) {
var newElement = $(selector).clone(true);
var total = $('#id_' + prefix + '-TOTAL_FORMS').val();
newElement.find(':input:not([type=button]):not([type=submit]):not([type=reset])').each(function() {
var name = $(this).attr('name')
if(name) {
name = name.replace('-' + (total-1) + '-', '-' + total + '-');
var id = 'id_' + name;
$(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');
}
});
newElement.find('label').each(function() {
var forValue = $(this).attr('for');
if (forValue) {
forValue = forValue.replace('-' + (total-1) + '-', '-' + total + '-');
$(this).attr({'for': forValue});
}
});
total++;
$('#id_' + prefix + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
var conditionRow = $('.form-row:not(:last)');
conditionRow.find('.btn.add-form-row')
.removeClass('btn-success').addClass('btn-danger')
.removeClass('add-form-row').addClass('remove-form-row')
.html('-');
return false;
}
function deleteForm(prefix, btn) {
var total = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
if (total > 1){
btn.closest('.form-row').remove();
var forms = $('.form-row');
$('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
for (var i=0, formCount=forms.length; i<formCount; i++) {
$(forms.get(i)).find(':input').each(function() {
updateElementIndex(this, prefix, i);
});
}
}
return false;
}
$(document).on('click', '.add-form-row', function(e){
e.preventDefault();
cloneMore('.form-row:last', 'form');
return false;
});
$(document).on('click', '.remove-form-row', function(e){
e.preventDefault();
deleteForm('form', $(this));
return false;
});
</script>
I found another way there is no need javascript. Actually i wanna make multiple forms and each datas must belong to one register. And sometimes one register can be own multiple datas. After all searching i found another way to make my project. I made a model with a primary key and then i give foreignkey and onetonefield to other models. Everything solved.
Here is the full project code: https://github.com/eseymenler/demo2

Django ValidationError after javascript modifies the choice field

I'm working on a job scheduling app for a REST API and I've created a Tasks, Nodes, URL, Adom, BaseOptions, and Jobs tables in Django. The BaseOptions have a foreign key for src_adom and dst_adom and the Jobs have foreign keys for the Task, src_node, dst_node, url and baseOptions. I didn't use a ModelForm but a generic Form instead and just loaded up the initial values and choices for all the fields I need in order to process a job. I did that because I couldn't figure out how to make the form change when the user selects a different node and want to change the select field for the corresponding adoms. I'm using javascript to detect a new node and changing the select field with the appropriate adoms for that node. I get a validation error if I change the initial source and/or destination node and modify the adom selection list. I know it is because my list of choices have changed from what I initially rendered the form with.
Is there a way to change the choices associated with a ChoiceField during the "clean" method? I can't seem to find that in the documents or digging through the Django code on github.
Models:
FMG = 'FMG'
FOS = 'FOS'
NODE_TYPE_CHOICES = (
(FMG, 'FMG'),
(FOS, 'FOS'),
)
# Create the types of tasks to run
class TaskType(models.Model):
name = models.CharField(max_length=200)
command = models.CharField(max_length=200)
node_type = models.CharField(max_length=60, choices=NODE_TYPE_CHOICES, default=FMG)
def __str__(self):
return self.name
# Create the nodes for tasks to be run on
class Node(models.Model):
ip = models.GenericIPAddressField(protocol='IPv4')
name = models.CharField(max_length=200)
apiname = models.CharField(max_length=200)
apikey = EncryptedCharField(max_length=200)
node_type = models.CharField(max_length=60, choices=NODE_TYPE_CHOICES, default=FMG)
def __str__(self):
return "{0} ({1})".format(self.name, self.ip)
class FMG_URLManger(models.Manager):
def get_queryset(self):
return super(FMG_URLManger, self).get_queryset().filter(node_type='FMG')
class FOS_URLManger(models.Manager):
def get_queryset(self):
return super(FOS_URLManger, self).get_queryset().filter(node_type='FOS')
class NodeURL(models.Model):
name = models.CharField(max_length=200)
node_type = models.CharField(max_length=60, choices=NODE_TYPE_CHOICES, default=FMG)
table_id = models.CharField(max_length=100)
table_url = models.CharField(max_length=200)
help_text = models.CharField(max_length=400, null=True)
filename = models.CharField(max_length=200)
objects = models.Manager()
fmg_objects = FMG_URLManger()
fos_objects = FOS_URLManger()
def __str__(self):
return self.name
class Adom(models.Model):
name = models.CharField(max_length=200)
version = models.CharField(max_length=60)
fmg = models.ForeignKey(Node, related_name='fmgs', on_delete=models.CASCADE)
class Meta:
unique_together = (("name", "version", "fmg"),)
def __str__(self):
return self.name
class BaseOption(models.Model):
src_adom = models.ForeignKey(Adom, related_name="src_adom", on_delete=models.CASCADE)
dst_adom = models.ForeignKey(Adom, related_name="dst_adom", on_delete=models.CASCADE, null=True)
name_filter = models.CharField(max_length=100, null=True)
site_name_filter = models.CharField(max_length=100, null=True)
policy_id_list_filter = models.CharField(max_length=60, null=True)
keep_policy_id = models.BooleanField(default=False)
disable_policy = models.BooleanField(default=False)
import_only = models.BooleanField(default=False)
def __str__(self):
return self.src_adom.name
# Create the actual request for jobs
class Job(models.Model):
UNKNOWN = 'Unknown'
PENDING = 'Pending'
SUCCESS = 'Success'
FAILURE = 'Failure'
STATUS_CHOICES = (
(UNKNOWN, 'Unknown'),
(PENDING, 'Pending'),
(SUCCESS, 'Success'),
(FAILURE, 'Failure'),
)
description = models.CharField(max_length=400)
task = models.ForeignKey(TaskType, related_name='job_task', on_delete=models.CASCADE)
src_node = models.ForeignKey(Node, related_name='src_node', on_delete=models.CASCADE)
urls = models.ManyToManyField(NodeURL)
dst_node = models.ForeignKey(Node, related_name='dst_node', on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name='jobs', on_delete=models.CASCADE)
opts = models.OneToOneField(BaseOption, related_name='job', on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
run_at = models.DateTimeField(editable=True, default=timezone.now)
start = models.DateTimeField(editable=True, null=True)
finished = models.DateTimeField(editable=True, null=True)
status = models.CharField(max_length=12, choices=STATUS_CHOICES, default=UNKNOWN, editable=True)
status_text = models.TextField(editable=True, null=True)
file_location = models.CharField(max_length=4086, editable=True, null=True)
objects = models.Manager()
def __str__(self):
return self.description
The ScheduleFormView:
class ScheduleView(LoginRequiredMixin, generic.FormView):
login_url = '/login/'
redirect_field_name = 'redirect_to'
template_name = 'tools/schedule.html'
form_class = ScheduleJobForm
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
print("Got a POST request, checking for valid...")
if form.is_valid():
# <process form cleaned data>
taskID_nodeType = form.cleaned_data['task']
description = form.cleaned_data['description']
src_nodeID_name = form.cleaned_data['src_node']
dst_nodeID_name = form.cleaned_data['dst_node']
urlsID_tableID = form.cleaned_data['urls']
src_adomID = form.cleaned_data['src_adom']
dst_adomID = form.cleaned_data['dst_adom']
name_filter = form.cleaned_data['name_filter']
site_name_fiter = form.cleaned_data['site_name_fiter']
policy_id_list_filter = form.cleaned_data['policy_id_list_filter']
taskID = taskID_nodeType.split('.')[0]
src_nodeID = src_nodeID_name.split('.')[0]
dst_nodeID = dst_nodeID_name.split('.')[0]
# urlsID_tableID was a list, now it's a single URL
# urlIDs = []
# for urlID_tableID in urlsID_tableID:
# urlID = urlID_tableID.split('.')[0]
# print("Got back id {}".format(urlID))
# urlIDs.append(urlID)
urlID = urlsID_tableID.split('.')[0]
urls = NodeURL.objects.filter(id=urlID)
# print("List of URLS = {}".format(urls))
src_node = Node.objects.get(id=src_nodeID)
dst_node = Node.objects.get(id=dst_nodeID)
task = TaskType.objects.get(id=taskID)
src_adom = Adom.objects.get(id=src_adomID)
dst_adom = Adom.objects.get(id=dst_adomID)
job = Job(description=description,
task=task,
src_node=src_node,
dst_node=dst_node,
user=request.user)
opts = BaseOption(src_adom=src_adom,
dst_adom=dst_adom,
name_filter=name_filter,
site_name_filter=site_name_fiter,
policy_id_list_filter=policy_id_list_filter)
opts.save()
job.opts = opts
job.save()
for url in urls:
url.job_set.add(job)
return HttpResponseRedirect('job-list.html')
else:
print("The form was not valid. Return for more processing.")
return render(request, self.template_name, {'form': form})
The ScheduleJobForm (with my unfinished code for 'clean'):
class ScheduleJobForm(forms.Form):
def clean(self):
print("Don't actually check for on src_adom.")
cleaned_data = super(ScheduleJobForm, self).clean()
print(cleaned_data)
adom = self.cleaned_data.get("src_adom")
print(adom)
# if adom < 1:
# raise forms.ValidationError("You didn't choose a valid ADOM.")
print("Don't actually check for on dst_adom.")
cleaned_data = super(ScheduleJobForm, self).clean()
adom = self.cleaned_data.get("dst_adom")
print(adom)
# if adom < 1:
# raise forms.ValidationError("You didn't choose a valid ADOM.")
initTasks = []
selectedNodeType = ''
# Get the first node_type because it will be the default selection of tasks.
for task in TaskType.objects.all().filter(node_type='FMG').order_by('id'):
if selectedNodeType == '':
selectedNodeType = task.node_type
taskChoice = str(task.id) + '.' + task.node_type, task.name
initTasks.append(taskChoice)
# Fill in the initial Nodes for the selected task above.
initNodes = []
selectedNodeID = 0
for node in Node.objects.all().filter(node_type=selectedNodeType).order_by('id'):
nodeChoice = str(node.id) + '.' + node.name, node.name + ' (' + node.ip + ')'
if selectedNodeID == 0:
selectedNodeID = node.id
initNodes.append(nodeChoice)
# Also grab the URL's for those node types and fill them in.
initURLs = []
for url in NodeURL.objects.all().filter(node_type=selectedNodeType).order_by('table_id'):
urlChoice = str(url.id) + '.' + url.table_id, url.name
initURLs.append(urlChoice)
# Since we've got the first node selected, then all the ADOMs are the same. Get them.
initAdoms = []
for adom in Adom.objects.all().filter(fmg_id=selectedNodeID).order_by('id'):
adomChoice = adom.id, adom.name
initAdoms.append(adomChoice)
# Add some hidden fields for the jQuery script to examine.
selected_node_type = forms.CharField(initial=selectedNodeType, widget=forms.HiddenInput)
# After this, a jQuery will have to keep the select fields updated if they are changed.
task = forms.ChoiceField(choices=initTasks)
description = forms.CharField()
src_node = forms.ChoiceField(choices=initNodes)
dst_node = forms.ChoiceField(choices=initNodes)
urls = forms.ChoiceField(choices=initURLs)
# These fields will have to be updated by the jQuery to get the available ADOMS for the selected
# Nodes. We also have to create a custom validator since the choices will change via the JS.
src_adom = forms.ChoiceField(choices=initAdoms)
dst_adom = forms.ChoiceField(choices=initAdoms)
name_filter = forms.CharField()
site_name_fiter = forms.CharField()
policy_id_list_filter = forms.CharField()
The schedule.js script that modifies the adoms:
/*
Of cource, I could use the following but I think the code below is
a bit more readable.
$(function(){
initPage();
}
); */
const coreapi = window.coreapi
const schema = window.schema
$(document).ready(function(){
initPage();
}
);
function initPage() {
console.log("Adding the change code.")
// Fill in the initial srcAdom
getSrcAdom()
// and the initial dstAdom
getDstAdom()
// Hide the wait icon
$('.loading').hide();
$('#id_task').change(
function() {
var currentNodeType = $('#id_selected_node_type').val();
var selectedOption = $('#id_task option:selected').val();
var selectedNodeType = selectedOption.split(".").pop();
if (currentNodeType != selectedNodeType) {
// The more I look at the options, I think this will have to be locked
// into FMG only nodes and create another form for just FOS nodes.
}
}
);
$('#id_src_node').change(
function() {
// Need to change the src adoms
$('.loading').show();
getSrcAdom()
$('.loading').hide();
}
);
$('#id_dst_node').change(
function() {
// Need to change the src adoms
$('.loading').show();
getDstAdom()
$('.loading').hide();
}
);
}
function getSrcAdom() {
var selectedOption = $('#id_src_node option:selected').val();
var selectedNodeName = selectedOption.split(".").pop();
// Clear the src adom options.
$('#id_src_adom')
.find('option')
.remove();
// Initialize a client
var client = new coreapi.Client()
// Interact with the API endpoint
var action = ["adom", "list"]
var params = {
search: selectedNodeName,
}
client.action(schema, action, params).then(function(result) {
// Return value is in 'result'
$.each(result, function(index, obj) {
$('#id_src_adom')
.append('<option value="' + obj["id"] + '">' + obj["name"] + '</option>');
console.log(index + " got '" + obj["name"] + "' (id: " + obj["id"] + ")");
})
})
}
function getDstAdom() {
var selectedOption = $('#id_dst_node option:selected').val();
var selectedNodeName = selectedOption.split(".").pop();
// Clear the src adom options.
$('#id_dst_adom')
.find('option')
.remove();
// Initialize a client
var client = new coreapi.Client()
// Interact with the API endpoint
var action = ["adom", "list"]
var params = {
search: selectedNodeName,
}
client.action(schema, action, params).then(function(result) {
// Return value is in 'result'
$.each(result, function(index, obj) {
$('#id_dst_adom')
.append('<option value="' + obj["id"] + '">' + obj["name"] + '</option>');
console.log(index + " got '" + obj["name"] + "' (id: " + obj["id"] + ")");
})
})
}
function createNodeSelect(data) {
// This was to clear all selected nodes and list new node types.
// It's not going to be used in this form at this time.
// Need to determine data format from JSON return.
// Leaving for future code example of how to clear options
// and replace it with a single option.
$('#id_src_node')
.find('option')
.remove()
.end()
.append('<option value="whatever">text</option>')
.val('whatever');
}
The schedule.html template (with Bootstrap 4 tags):
{% extends "tools/base_site.html" %}
{% block extra_js %}
{% load static %}
<script src="{% static 'rest_framework/js/coreapi-0.1.1.js' %}"></script>
<script src="{% url 'api-docs:schema-js' %}"></script>
<script src="{% static 'js/schedule.js' %}"></script>
{% endblock %}
{% block content %}
<div id="content-main">
<br>
{% block loading %}
{% load static %}
<div id="loading" class="loading">
<img src="{% static 'images/spinning-wait-icons/wait30.gif' %}" alt="Wait" />
<!-- <h3>Loading Data from Server</h3> -->
</div>
{% endblock %}
{% load widget_tweaks %}
{% if form.errors %}
<div class="alert alert-primary">
<button type="button" class="close" data-dismiss="alert">×</button>
{% for field in form %}
{% if field.errors %}
<li>{{ field.label }}: {{ field.errors|striptags }}</li>
{% endif %}
{% endfor %}
</div>
{% endif %}
<form method="post">
{% csrf_token %}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="form-group">
{{ field.label_tag }}
{% render_field field class="form-control" %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Schedule</button>
</form>
</div>
{% endblock %}
I must confess I didn't go through all the code (it's quite a lot), but at a first glance it looks to me as you should move the initialization of your choices (intTasks, initNodes...) into the __init__ method of your FormClass (ScheduleJobForm).
Because you want the code to be run when you instantiate the class, not when you load the module, right?
So:
class ScheduleJobForm(forms.Form):
selected_node_type = forms.CharField(initial=selectedNodeType, widget=forms.HiddenInput)
task = forms.ChoiceField(choices=initTasks)
# further fields
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# initialize initNodes and the rest
self.fields["src_node"]=initNodes
# and resp.
The form does not care about Javascript, as it is instantiated in the post request after all the Javascript magic on the frontend.
So there doesn't have to (and cannot) be any interaction between Javascript and your form.
I was able to figure out how to dynamically change the choices by using the getter and setter property of ChoiceField (see github repo).
The change I made was in the ScheduleJobForm view. I added these additional lines before calling 'is_valid':
print("Got a POST request, checking for valid...")
print("Fix the choices in the ADOMs first.")
src_nodeID_name = form['src_node'].value()
dst_nodeID_name = form['dst_node'].value()
src_nodeID = src_nodeID_name.split('.')[0]
dst_nodeID = dst_nodeID_name.split('.')[0]
srcAdoms = []
for adom in Adom.objects.all().filter(fmg_id=src_nodeID).order_by('id'):
adomChoice = adom.id, adom.name
srcAdoms.append(adomChoice)
dstAdoms = []
for adom in Adom.objects.all().filter(fmg_id=dst_nodeID).order_by('id'):
adomChoice = adom.id, adom.name
dstAdoms.append(adomChoice)
form.fields['src_adom'].choices = srcAdoms
form.fields['dst_adom'].choices = dstAdoms
For efficiency, I should probably check changed_data and see if the ADOM's have actually changed or not.

How to submit a Django form using JavaScript (jQuery)

I'm working on a web app project. I had a problem with file upload. Then I realized that my team mate changed the default submit button in create_form.html. It works like in 5. and 6. and i need to collect file data as well.
What should I add to .js files to submit and save file?
forms.py
class DocumentUpload(forms.ModelForm):
class Meta:
model = Form
fields = ('file',)
models.py
class Form(TimeStampedModel, TitleSlugDescriptionModel):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=512)
is_final = models.BooleanField(default=False)
is_public = models.BooleanField(default=False)
is_result_public = models.BooleanField(default=False)
file = models.FileField(null=True, blank=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('form-detail', kwargs={'slug': self.slug})
views.py
def create_form(request):
if request.method == 'POST':
user = request.user
data = ParseRequest(request.POST)
print(data.questions())
print(data.form())
parsed_form = data.form()
parsed_questions = data.questions()
# tworzy formularz o podanych parametrach
formfile = DocumentUpload(request.POST, request.FILES or None)
if formfile.is_valid():
form = formfile.save(commit=False)
print(form)
form.author = user
form.title = parsed_form['title']
form.is_final = parsed_form['is_final']
form.is_result_public = parsed_form['is_result_public']
form.description = parsed_form['description']
form.save()
# zapisuje pytania z ankiety wraz z odpowienimi pytaniami
for d in parsed_questions:
question = Question(form=form, question=d['question'])
question.save()
# dla kazdego pytania zapisz wszystkie opcje odpowiadania
for opt in d['options']:
option = Option(question=question, option=opt)
option.save()
return render(request, 'forms/form_form.html', {})
else:
form = DocumentUpload()
return render(request, 'forms/form_form.html', {'form': form})
create_form.html
Here I have to submit {{ form.as_p }} <- I have to submit this input in JS**
{% block content %}
<form method="post" id="form" enctype='multipart/form-data'>
{%csrf_token %}
<div class="form-group">
{% csrf_token %}
<label for="form-title">Tytuł formularza</label>
<input id="form-title" class="form-control" type="text"
placeholder="Tytuł" required/>
</div>
{{ form.as_p }}
.... more divs ...
<input class="btn btn-default" type="submit" value="zapisz"/>
</form>
{% endblock %}
collect_data.js
This is my function called to save inputs from create_form.html instead of:
<input class="btn btn-default" type="submit" value="zapisz"/>
but I don't know how to save input from:
{{ form.as_p }}
function collect_data() {
var csrftoken = getCookie('csrftoken');
var data = {
form_title: $('#form-title').val(),
is_final: $('#form-is-final').prop('checked'),
is_public: $('#form-is-public').prop('checked'),
is_result_public: $('#form-is-result-public').prop('checked'),
description: $('#description').val(),
questions: [],
num_questions: num_questions,
csrfmiddlewaretoken: csrftoken
};
for (var k = 0; k < num_questions; k++) {
var my_data = {};
var question_k = $('#question-' + k);
my_data.question = question_k.find('#question-text').val();
my_data.answer_type = question_k.find('select').val();
my_data.options = [];
for (var j = 0; j < num_question_options[k]; j++) {
var answer = question_k.find('#answer-' + j).val();
if (answer !== '') {
my_data.options.push(answer)
}
}
my_data.num_options = my_data.options.length;
data.questions.push(my_data)
}
return data
}
submit_data_create.js
$(document).ready(function (event) {
$(document).on('submit', '#form', function (e) {
e.preventDefault();
var data = collect_data();
$.ajax({
type: 'POST',
url: '/form/create/',
data: data,
success: function (data, textStatus) {
window.location.href = '/form/list/'
},
fail: function (response) {
alert('Coś poszło nie tak.');
}
});
})
});

Django View on Ajax call

I'm creating a catalogue page. On this page I want to allow user to filter the products.
So I created a sidebar with checkboxes and input texts.
I would like that every time the user changes the filter parameters, the catalogue is updated.
this is my code:
html for sidebar (filter):
<h3>Filtri:</h3>
<b>Marca:</b><br>
{% for marca in marche %}
<input type="checkbox" title="{{ marca.nome }}" value="{{ marca.nome }}" name="marca" class="marca" onclick="filtra()"> {{ marca.nome }} <br>
{% empty %}
<p>Nessuna Marca è ancora stata inserita.</p>
{% endfor %}
<br>
<b>Portata:</b> <br>
Maggiore di
<input type="text" title="portata" name="portata" id="portata" class="textbox-filtro" maxlength="4" onblur="filtra()"> kg
<br><br>
<b>Sollevamento:</b> <br>
Maggiore di
<input type="text" title="sollevamento" id="sollevamento" class="textbox-filtro" maxlength="4" onblur="filtra()"> mt
<br><br>
<b>Trazione:</b><br>
{% for tra in trazione %}
<input type="checkbox" title="{{ tra.trazione }}" value="{{ tra.trazione }}" id="{{ tra.trazione }}" class="trazione" onclick="filtra()"> {{ tra.trazione }} <br>
{% empty %}
<p>Nessuna Trazione è ancora stata inserita</p>
{% endfor %}
<br>
<b>Idroguida:</b><br>
{% for idro in idroguida %}
<input type="checkbox" title="{{ idro.idroguida }}" value="{{ idro.idroguida }}" id="{{ idro.idroguida }}" class="idroguida" onclick="filtra()"> {{ idro.idroguida }} <br>
{% empty %}
<p>Nessuna Idroguida è ancora stata inderita</p>
{% endfor %}
As you can see, I've 5 filter groups: Marca (brand), Portata (carrying capacity), Sollevamento (lift), Trazione (traction) and Idroguida (power steering).
Every time you edit these values, the javascript function filtra() is called... so onblur for text input and onclick for checkboxes.
Here the javascript code:
<script>
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function filtra() {
var marche_selezionate = [];
var marca_check = document.getElementsByClassName('marca');
for(var i = 0; i < marca_check.length; i++){
if(marca_check[i].checked){
marche_selezionate.push(marca_check[i].value);
}
}
marche_selezionate = marche_selezionate.join(',');
var portata_selezionata = document.getElementById('portata').value;
var sollevamento_selezionata = document.getElementById('sollevamento').value;
var trazioni_selezionate = [];
var trazione_check = document.getElementsByClassName('trazione');
for(i = 0; i < trazione_check.length; i++){
if(trazione_check[i].checked){
trazioni_selezionate.push(trazione_check[i].value);
}
}
var idroguida_selezionate = [];
var idroguida_check = document.getElementsByClassName('idroguida');
for(i = 0; i < idroguida_check.length; i++){
if(idroguida_check[i].checked){
idroguida_selezionate.push(idroguida_check[i].value);
}
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
var postUrl = "{% url 'carrellielevatori:carrellielevatori' %}";
$.ajax({
url: postUrl,
type: 'POST',
data: {'marche_selezionate': marche_selezionate},
success: function(result){
alert('success');
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
}
</script>
so, after setting up csrf token, in way to avoid the error "403 forbidden", I start looking and all the parameters and set up the 5 variables that I would like to pass at the view in way to filter up the catalogue.
I've also added some alert in the ajax call in way to know if it's successful or not. It is. The alert with "success" appear.
The problem is that everything stops here.
In fact, it seems nothing happens in the view.
here the code of the view:
def carrellielevatori(request):
lista_carrelli = Carrelli.objects.all()
lista_marche = Marche.objects.all()
lista_trazione = Trazione.objects.all()
lista_idroguida = Idroguida.objects.all()
footerForm = MailForm()
method = 'get'
if request.is_ajax():
method = 'ajax'
return render(request,
'carrellielevatori/carrellielevatori.html',
{
'title': 'Carrelli Elevatori - Giemme Lift s.r.l.',
'footerForm': footerForm,
'year': datetime.now().year,
'carrelli': lista_carrelli,
'marche': lista_marche,
'trazione': lista_trazione,
'idroguida': lista_idroguida,
'method':method,
})
to understand if it works, I've set up the variable method to "get" and displayed it on the page. Then in the ajax "if", I change the value to "ajax".
So it should change, right? the text remains "get" and never changes to "ajax".
This is a first try to see if it works. Once I know this work I'll proceed to filter the query that with the products. But if this does not work it's useless.
PS. Yes in the ajax call I pass just one parameters. This is to know if it works. Later I will proceed adding the other parameters in the data field.
To conclude, can you please tell me why does not enter in the in if request.is_ajax()':
Is this in not the right way, how can I filter the oringal query?
I've also tried with if request.method == 'POST', but i get the same result.
Here’s how I would do it:
#csrf_exempt
def carrellielevatori(request):
lista_carrelli = Carrelli.objects.all()
lista_marche = Marche.objects.all()
lista_trazione = Trazione.objects.all()
lista_idroguida = Idroguida.objects.all()
footerForm = MailForm()
method = 'get'
if request.is_ajax():
method = 'ajax'
return JsonResponse({
'title': 'Carrelli Elevatori - Giemme Lift s.r.l.',
'footerForm': footerForm,
'year': datetime.now().year,
'carrelli': lista_carrelli,
'marche': lista_marche,
'trazione': lista_trazione,
'idroguida': lista_idroguida,
'method':method,
})
In the JS:
function filtra() {
var marche_selezionate = [];
var marca_check = document.getElementsByClassName('marca');
for(var i = 0; i < marca_check.length; i++){
if(marca_check[i].checked){
marche_selezionate.push(marca_check[i].value);
}
}
marche_selezionate = marche_selezionate.join(',');
var portata_selezionata = document.getElementById('portata').value;
var sollevamento_selezionata = document.getElementById('sollevamento').value;
var trazioni_selezionate = [];
var trazione_check = document.getElementsByClassName('trazione');
for(i = 0; i < trazione_check.length; i++){
if(trazione_check[i].checked){
trazioni_selezionate.push(trazione_check[i].value);
}
}
var idroguida_selezionate = [];
var idroguida_check = document.getElementsByClassName('idroguida');
for(i = 0; i < idroguida_check.length; i++){
if(idroguida_check[i].checked){
idroguida_selezionate.push(idroguida_check[i].value);
}
}
var postUrl = "{% url 'carrellielevatori:carrellielevatori' %}";
$.post(postUrl, {'marche_selezionate': marche_selezionate},
function(result){
alert('success');
}).fail(function (data, status, xhr) {
alert(xhr.status);
alert(thrownError);
});
}

django Javascript dropdown

Am new to programming in Python and Javascript and I have been learning Python for few months now and love it. I have been playing with django which is cool I was wondering how I can make this model work with a Iavascript. I'll like someone to explain as much as the code involved as I just what to have a full understanding of the process from django to Javascript.
I want to dynamically is CarModel.objects.filter(make ='somename') or just 'somename'.
This is a test model am using since its similar to the Javascript I use for tutorial from online (YouTube) the scripts is below as well:
class Make(models.Model):
name = models.CharField(max_length=50,blank=True,null = True)
#so so so so
class CarModel(models.Model):
name = models.CharField(max_length=50,blank=True,null = True)
make = models.ForeignKey(Make,blank=True,null = True)
Now how will you pass say something like this to your Javascript?
class Model(ModelForm):
make = forms.ModelChoiceField(queryset= Model.objects.none(), required=True)
def __init__(self, somemake,*args, **kwargs):
super(Model, self).__init__(*args, **kwargs)
self.fields['property'].queryset = Model.objects.filter(make = somemake)
class Meta:
model = Model
exclude= ('make')
<script type="text/javascript">
function populate(s1,s2){
var s1 = document.getElementById(s1);
var s2 = document.getElementById(s2);
s2.innerHTML = "";
if(s1.value == "Chevy"){var optionArray = ["|","camaro|Camaro","corvette|Corvette","impala|Impala"];
}
else if(s1.value == "Dodge"){
var optionArray = ["|","avenger|Avenger","challenger|Challenger","charger|Charger"];
} else if(s1.value == "Ford"){
var optionArray = ["|","mustang|Mustang","shelby|Shelby"];
}
for(var option in optionArray){
var pair = optionArray[option].split("|");
var newOption = document.createElement("option");
newOption.value = pair[0];
newOption.innerHTML = pair[1];
s2.options.add(newOption);
}
}
</script>
and html here
Choose Car Make:
<select id="slct1" name="slct1" onchange="populate(this.id,'slct2')">
<option value=""></option>
<option value="Chevy">Chevy</option>
<option value="Dodge">Dodge</option>
<option value="Ford">Ford</option>
</select>
Choose Car Model:
<select id="slct2" name="slct2"></select>
If you want to do in JS, this is how I would solve the problem.
First create a template that contains the following for the 2 select lists.
<html>
<head>
<script>
var json = {
"Chevy": ["chev1", "chev2", "chev3"],
"Dodge": ["dodge1", "dodge2", "dodge3"],
"Ford": ["ford1", "ford2", "ford3"]
};
function carMake () {
select = document.getElementById('slct1');
select.options.length = 0;
for(make in json) {
select.options[select.options.length] = new Option(make, make);
}
}
function carModel(sel) {
var car_make = sel.options[sel.selectedIndex].value
select = document.getElementById('slct2');
select.options.length = 0;
for(var i=0;i<json[car_make].length;i++) {
select.options[select.options.length] = new Option(json[car_make][i], i);
}
}
</script>
</head>
<body>
Choose Car Make:
<select id="slct1" onchange="carModel(this)"></select>
<script> carMake(); </script>
Choose Car Model:
<select id="slct2" name="slct2"></select>
</body>
</html>
The above JS will read in the JSON object and update the Car Make when ever the dynamically populated Car Model select field is changed.
To generate the JSON object using your supplied Model you need to do the following:
In the view.py file:
from <your-app>.models import Make
from <your-app>.models import Model
import json
json_dict = {}
for car_make in Make.objects.all():
json_dict[car_make] = Model.objects.filter(make=car_make)
json_data = json.dumps(json_dict)
Then you take json_data and and add that to your response render context.
Finally alter the above template so that the JS variable json will be rendered to contain the JSON object passed from the view to the template.
You don't need javascript to do some fancy dropdown. You can use Django Forms to do it for you. All you need is to provide forms.py some information about the choices that a user can make and you will have your form rendered without you having to do anything more.
Look at my forms.py to see how I have done it.
You should convert query set to list before using json.dumps otherwise it will give you an error which is "NOT JSON SERIALIZABLE"
from <your-app>.models import Make
from <your-app>.models import Model
import json
json_dict = {}
for car_make in Make.objects.all():
json_dict[car_make] = list(Model.objects.filter(make=car_make).value())
json_data = json.dumps(json_dict)

Categories