It seems that my request.session isn't saved or is somehow modified in other ways, despite using request.session.modified = True after changing the value.
Here is the debug output:
This should run first.
This should run second.
I have set main category to 2 (Shoes)
Main category is 1 (Books)
The code below should display a different ModelForm based on selected category, however when I select, for instance, Books, ShoesModelForm is displayed and vice-versa. This currently works as follows: whenever a value in a combobox is changed, two AJAX requests are fired. First one calls a view (load_categories) that renders another if a category has children, otherwise returns an HttpResponse which stops attaching the listener. Second one calls a view (load_modelform) that renders a specific ModelForm if selected category is root node (main category).
mappings = {
'1': BookProductForm,
'2': ShoesProductForm
}
def load_categories(request):
print("This should run first.")
category_id = request.GET.get('category')
request.session['category'] = category_id
request.session.modified = True
if Category.objects.get(id=category_id).is_root_node():
request.session['main_category'] = category_id
request.session.modified = True
print(f"I have set main category to {request.session['main_category']} ({Category.objects.get(id=category_id).name})")
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):
print("This should run second.")
main_category = request.session['main_category']
print(f"Main category is {main_category} ({Category.objects.get(id=main_category).name})")
form = mappings[main_category]
return render(request, 'products/category_modelform.html', {'form': form})
#login_required
def product_create_view(request):
if request.method == 'POST':
category = request.session.get('main_category')
create_product_form = mappings[category](request.POST)
if create_product_form.is_valid():
create_product_form.save()
return render(request, 'products/product_create.html', {
'categories': Category.objects.filter(parent=None)
})
What might be going on here?
#EDIT:
I'm including my template with jQuery code that contains Ajax requests:
{% extends 'pages/base.html' %}
{% load static %}
{% block cssfiles %}
<link rel="stylesheet" type="text/css" href="{% static 'products/css/create.css' %}">
{% endblock %}
{% block content %}
<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='categories'>
<label>Category</label>
<select>
{% for category in categories %}
<option value="{{ category.pk }}">{{ category.name }}</option>
{% endfor %}
</select>
</div>
<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>
<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');
setTimeout(function() {
$.ajax({
url: url2,
data: {
'category': categoryId
},
success: function (data) {
if (data != 'dont_change_modelform') {
$('.the-rest').empty();
$('.the-rest').append(data);
}
}
});
}, 100);
}
$(document).on('change', 'select', $r_);
</script>
{% endblock %}
Related
when i used ajax in my project the form.is_valid() method not validating the form. it showing the 'this field required error' but i access that using request.POST means i fill all the fields.
'''
this is html code which render the django model form
##HTML FORM##
<form action="" method="post" enctype="multipart/form-data" id="reception_form" novalidate> {% csrf_token %}
{% for field1 in form1 %}
<label for="{{field1.id_for_label}}"> {{field1.label}} </label> {{field1}}
<div>
{% if field1.errors %}{% for error in field1.errors %} <small class="errorlist">{{error}}</small> {% endfor %}{% endif %}
</div>
{% endfor %}
{% for field2 in reception %}
{% if field2.name != 'gender' %}
<label for=" {{field2.id_for_label}} "> {{field2.label}} </label> {{field2}}
<div>
{% if field2.errors %}{% for error in field2.errors %} <small class="errorlist">{{error}}</small> {% endfor %}{% endif %}
</div>
{% endif %}
{% endfor %}
{% for radiofield in reception.gender %}
{{radiofield.tag}}
<label for=" {{radiofield.id_for_label}} "> {{radiofield.choice_label}} </label> <br>
{% endfor %}
<input type="submit" value="Add Reception" name="Add Reception" class="btn btn-secondary mb-3" >
</form>
----------
## Ajax ##
$('#reception_form').submit(function(e){
console.log(" submit pressed")
e.preventDefault();
let Rnm = $('#id_username').val();
let Rfnm = $('#id_first_name').val();
let Rlnm = $('#id_last_name').val();
let Rem = $('#id_email').val();
let Rpwd = $('#id_password1').val();
let Rmob = $('#id_mob_no').val();
let Rcty= $('#id_city').val();
let Rdob = $('#id_dob').val();
let Rpr = $('#id_profile_photo').val();
let Rgen = $("input[name='gender']:checked").val()
let Rcsr = $("input[name='csrfmiddlewaretoken']").val()
reception_data = {Rusername : Rnm , Rfirst_name:Rfnm ,Rlast_name:Rlnm ,Remail:Rem , Rpassword:Rpwd, RmMob_no:Rmob , Rcity:Rcty , RBirth_Date :Rdob, Rprofile:Rpr, Rgender:Rgen , csrfmiddlewaretoken:Rcsr};
//console.log(reception_data)
$.ajax({
url: "{% url 'AddReception' %}" ,
type : 'POST',
data : reception_data,
dataType:'json',
success: function(data){
console.log("ajax executed");
console.log(data);
}
});
});
----------
admin_home view render the initial form and user information
## views ##
## 1) home##
def Admin_home(request):
print("admin Home")
user = request.user
admin = Admin.objects.get(pk=user)
# print(request)
form1 = Register()
reception = Register_Reception()
param = {'user':user , 'admin':admin , 'form1':form1 , 'reception':reception}
return render(request , "patients/admin/home.html" , param)
----------
This view function handles the ajax request but is_valid() returns false
## 2) Add Reception ##
def Add_reception(request):
if request.method == "POST":
form1 = Register(request.POST) #usercreation form
form2 = Register_Reception(request.POST , request.FILES) #reception profile form
print(form1.is_valid())
print(form1.errors)
print(request.POST['Rpassword'])
return HttpResponse("form submited")
'''
i think you are using jquery, right? Then i would try to serialize the form data like this:
reception_data = $("#reception_form").serialize()
Maybe this is better to send the POST data to the form...
Best,
jingo
When i click add to cart i have the following error in views.py:
"In updateItem, productId = data['productId'] KeyError: 'productId' "
views.py line 70 where i have my error:
def updateItem(request):
data = json.loads(request.body)
productId = data['productId']
action = data['action']
print('Action:', action)
print('productId:', productId)
customer = request.user.customer
product = Product.objects.get(id=productId)
order, created = Order.objects.get_or_create(customer=customer, complete=False)
orderItem, created = OrderItem.objects.get_or_create(order = order, product = product)
if action == 'add':
orderItem.quantity = (orderItem.quantity +1)
elif action == 'remove':
orderItem.quantity = (orderItem.quantity -1)
orderItem.save()
if orderItem.quantity <=0:
orderItem.delete()
return JsonResponse('El item fue agregado', safe=False)
carrito.js:
function updateUserOrder(productId, action){
console.log('Usuario logeado y enviando data...')
var url = '/update_item/'
fetch (url, {
method: 'POST',
headers:{
'Content-Type':'application/json',
'X-CSRFToken': csrftoken,
},
body:JSON.stringify({'productId': productId, 'action':action})
})
.then((response) =>{
return response.json()
})
.then((data) =>{
console.log('data:', data)
location.reload()
})
}
My template carrito.html:
When i click on the button Add to cart i have the issue.
{% extends 'tienda/index.html' %}
{% load static %}
{% block content %}
</div>
{% for item in items %}
<div class="cart-row">
<div style="flex:2"><img class="row-image" src="{{item.product.imageURL}}"></div>
<div style="flex:2"><p>{{item.product.name}}</p></div>
<div style="flex:1"><p>{{item.product.price|floatformat:2}}</p></div>
<div style="flex:1">
<p class="quantity">{{item.quantity}}</p>
<div class="quantity">
<img data-product={{item.product.id}} data-action="add" class="chg-quantity update-cart" src="{% static 'images/arrow-up.png' %}">
<img data-product={{item.product.id}} data-action="remove" class="chg-quantity update-cart" src="{% static 'images/arrow-down.png' %}">
</div>
</div>
<div style="flex:1"><p>${{item.get_total}}</p></div>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock %}
The above block of code is where i have the buttons with the actions.
The json.loads() function accepts only unicode strings.
So first try to decode the request body with request.body.decode('utf-8') and next to load it with json.loads().
decoded_data = request.body.decode('utf-8')
data = json.loads(decoded_data)
There you can read the docs about json.loads
Return redirect doesn't work in an else statement after receiving json data. The same redirect works in an other if statement. In the terminal I can see the GET request for the url I want to redirect to, that is why I found this strange.The print statement works perfectly in else, only redirect fails. My code so far:
views.py (please let me know if the other views are necessary to answer the question)
def data_type_error_handling(request):
'''handles all the possible choices after data_type_errors '''
if '_skip' in request.POST:
return redirect('data_validation')
elif 'first_load' in request.session or '_refresh' in request.POST or request.method == 'GET':
print("data_load vagy refresh")
error_list = request.session['error_list']
errors = json.dumps(error_list, indent=4, sort_keys=True, default=str)
if 'first_load' in request.session:
del request.session['first_load']
return render(request, "upload/data-type-correction.html",
{"error_list": errors})
else:
raw_data = request.body.decode('utf-8')
data = json.loads(raw_data)
print(data)
return redirect('data_validation')
def data_validation(request):
return render(request, "upload/data-validation.html")
return redirect('data_validation') works in the first if statement, but not in else, it stays on the same page where I clicked on the button.
urls.py
from django.urls import path
from . import views
urlpatterns=[
path('data-upload', views.data_upload, name='data-upload'),
path('upload-failed', views.data_upload, name='upload-failed'),
path('upload-successful', views.data_upload, name='upload-successful'),
path('data-type-correction', views.data_type_error_handling, name ='data-type-correction'),
path('data-validation', views.data_validation, name ='data_validation'),
]
data-type-correction.html
{% extends "base.html" %}
{% block title %} Data type error correction {% endblock title %}
{% block content %}
<h1>Data type errors</h1>
<h3 id="data-type-error-h3">There are data type errors in your submission. Please change string characters to numbers in the Amount column.</h3>
<input type="submit" class="btn-back-correct" id="btn-back-to-upload" value="Back" onclick="history.go(-1)" />
<div id="main-container">
<button type="submit" class="btn-submit-correct" id="btn-repost-data-errors" name="_reload">Load corrected data</button>
<div id="datatype-error-container"></div>
<form action="" method="post">
<ul id="datatype-action-container">
{%csrf_token%}
<li><input type="submit" class="btn-submit-correct" id="btn-dismiss-data-errors" value="Skip this data" name="_skip" onclick="return confirm('Are you sure you do not need this data?');"></li>
<li><input type="submit" class="btn-submit-correct" id="btn-refresh-data-errors" value="Refresh error list" name="_refresh"></li>
</ul>
</form>
<!--handsontable-->
<script>
var errors = {{ error_list|safe }}
console.log(errors)
function log (event) {console.log(event)}
var container = document.getElementById('datatype-error-container');
var settings = {
data: errors,
rowHeaders: true,
colHeaders: true,
filters: true,
dropdownMenu: true,
contextMenu: true,
width: '75.66%',
height: 500,
minRows: 1,
afterChange: log.bind(this, 'afterChange'),
afterRemoveRow: log.bind(this, 'removeRow'),
afterRemoveCol: log.bind(this, 'removeCol'),
afterCreateRow: log.bind(this, 'createRow'),
afterCreateCol: log.bind(this, 'createCol'),
columns: [
{
data: 0,
type: 'text',
width: 210,
allowInsertRow: true
},
{
data: 1,
width: 210,
type: 'text',
},
{
data: 2,
width: 210,
type: 'text',
},
{
data: 3,
width: 210,
},
],
licenseKey: 'non-commercial-and-evaluation',
colHeaders: [
'CID',
'Product',
'Account',
'Amount'
]
};
var hot = new Handsontable(container, settings);
</script>
<script src="../../static/app/scripts/fetchData.js"></script>
</div>
{% endblock content %}
data-validation.html
{% extends "base.html" %}
{% block title %} Data validation {% endblock title %}
{% block content %}
<h1>Data validation output goes here</h1>
{% endblock content %}
First time poster, long time reader. I've spend quite awhile looking for an answer to this, which makes me think its something fundamental I'm missing.
I'm trying to pull data held in a database table and pass it through for display in a Highcharts plot. I'm not getting any errors from Django or by the client when inspecting source.
Using: Django 1.7 and Python 3.4
The views.py:
#unit/views.py
from django.http import JsonResponse
from django.shortcuts import render
from unit.analysis_funcs import ChartData
def chart_data_json(request):
data = {}
data['chart_data'] = ChartData.get_data()
return JsonResponse(data, safe = True)
def plot(request):
return render(request, 'unit/data_plot.html', {})
The get_data() function:
#unit/analysis_funcs.py
from unit.models import CheckValve
class ChartData(object):
def get_data():
data = {'serial_numbers': [], 'mass': []}
valves = CheckValve.objects.all()
for unit in valves:
data['serial_numbers'].append(unit.serial_number)
data['mass'].append(unit.mass)
return data
The template:
<!-- templates/unit/data_plot.html -->
{% extends "base.html" %}
{% block extrahead %}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
{% endblock %}
{% block rootcontainer %}
<div id="container" style="width:100%; height:400px;"></div>
{% endblock %}
{% block overwrite %}
<!-- Overwrite the base.html jQuery load and put in head for Highcharts to work -->
{% endblock %}
{% block extrajs %}
<script>
$(document).ready(function() {
var options = {
chart: {
renderTo: 'container',
type: 'line'
},
series: [{}]
};
var ChartDataURL = "{% url 'chart_data_json' %}";
$.getJSON('ChartDataURL', function(data) {
options.xAxis.categories = data['chart_data']['serial_numbers'];
options.series[0].name = 'Serial Numbers';
options.series[0].data = data['chart_data']['mass'];
var chart = new Highcharts.Chart(options);
});
});
</script>
{% endblock %}
Finally the urls:
from unit import views, graphs
urlpatterns = patterns('',
url(r'^chart_data_json/', views.chart_data_json, name = 'chart_data_json'),
url(r'^plot/', views.plot, name = 'plot'),
)
Everything seems to run, but the Highchart plot doesn't render. I think its in how I'm moving the JSON data from the view.py to the template.html, but after so long staring at it I'm going cross-eyed.
Any help would be awesome!
I finally got my plotting working. I found this approach here. Thanks to Harrison for posting his method!
My new views.py based on the above approach:
def plot(request, chartID = 'chart_ID', chart_type = 'line', chart_height = 500):
data = ChartData.check_valve_data()
chart = {"renderTo": chartID, "type": chart_type, "height": chart_height,}
title = {"text": 'Check Valve Data'}
xAxis = {"title": {"text": 'Serial Number'}, "categories": data['serial numbers']}
yAxis = {"title": {"text": 'Data'}}
series = [
{"name": 'Mass (kg)', "data": data['mass']},
{"name": 'Pressure Drop (psid)', "data": data['pressure drop']},
{"name": 'Cracking Pressure (psid)', "data": data['cracking pressure']}
]
return render(request, 'unit/data_plot.html', {'chartID': chartID, 'chart': chart,
'series': series, 'title': title,
'xAxis': xAxis, 'yAxis': yAxis})
Quick function for pulling database objects and passing the data:
class ChartData(object):
def check_valve_data():
data = {'serial numbers': [], 'mass': [],
'pressure drop': [], 'cracking pressure': [], 'reseat pressure': []}
valves = CheckValve.objects.all()
for unit in valves:
data['serial numbers'].append(unit.serial_number)
data['mass'].append(unit.mass)
data['cracking pressure'].append(unit.cracking_pressure)
data['pressure drop'].append(unit.pressure_drop)
data['reseat pressure'].append(unit.reseat_pressure)
return data
The key to Harrison's method is a mapping script to translate the Highcharts js to Python template variables:
{% extends "base.html" %}
{% block extrahead %}
<!-- Load in jQuery and HighCharts -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
{% endblock %}
{% block heading %}
<h1 align="center">Analysis</h1>
{% endblock %}
{% block content %}
<div id={{ chartID|safe }} class="chart" style="height:100px; width:100%"></div>
{% endblock %}
{% block overwrite %}
<!-- Overwrite the base.html jQuery load and put in head for Highcharts to work -->
{% endblock %}
{% block extrajs %}
<!-- Maps the Python template context variables from views.py to the Highchart js variables -->
<script>
var chart_id = {{ chartID|safe }}
var chart = {{ chart|safe }}
var title = {{ title|safe }}
var xAxis = {{ xAxis|safe }}
var yAxis = {{ yAxis|safe }}
var series = {{ series|safe }}
</script>
<!-- Highchart js. Variable map shown above -->
<script>
$(document).ready(function() {
$(chart_id).highcharts({
chart: chart,
title: title,
xAxis: xAxis,
yAxis: yAxis,
series: series
});
});
</script>
{% endblock %}
Everything works and displays correctly now!
I currently have the following template,
{% extends "123/123-base.html" %}
{% block main %}
<script type="text/javascript">
$(document).ready(function() {
$("#button").click(function() {
var host = $("#hostinput").val();
var record = $("#recordinput").val();
$.ajax({
url : "/lookup_ajax",
type : "POST",
dataType: "json",
data : {
hostinput : host,
recordinput : record,
csrfmiddlewaretoken: '{{ csrf_token }}'
},
success : function(json) {
$('#mainsection').append( "response" + json.response );
},
error : function(xhr,errmsg,err) {
alert(xhr.status + ": " + xhr.responseText);
}
});
return false;
});
});
</script>
<div id="mainsection">
<div id="maininput" class="input-append">
<form method="post" name="inputlookup" action="/lookup_ajax">
{% csrf_token %}
<input class="span2" id="hostinput" name="hostinput" type="text">
<select title="Record" id="recordinput" name="recordinput" >
<option value="A">A</option>
<option value="MX">MX</option>
<option value="Cname">Cname</option>
</select>
<button id="button" class="btn" type="submit">Lookup</button>
</form>
</div>
<div id="mainouput">
</div>
</div>
{% endblock %}
However the response I receieve back from the server I want to loop over using the Django template tags, like this,
{% extends "123/123-base.html" %}
{% block main %}
{% if error %}
{{ error }}
{% else %}
<ul>
<table class="table table-style table-striped">
<thead>
<tr>
<th>HOSTNAME</th>
<th>TTL</th>
<th>CLASS</th>
<th>TYPE</th>
<th>DETAILS</th>
</tr>
</thead>
{% for answer in response %}
<tr>
{% for field in answer %}
<td>{{ field }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
</ul>
{% endif %}
{% endblock %}
Any ideas on how this should be done ?
Thanks,
It looks to me like you're returning a JSON object for your AJAX call. If that's correct then django doesn't come into it for displaying the result. You'd need to change your success function to something like the following:
success: function(json){
// Table header
var table = $('<table>').addClass('table table-style table-striped');
var thead = $('<thead>');
var headrow = $('<tr>');
var head1 = $('<th>').text('HOSTNAME');
var head2 = $('<th>').text('TTL');
var head3 = $('<th>').text('CLASS');
var head4 = $('<th>').text('TYPE');
var head5 = $('<th>').text('DETAILS');
$(headrow).append(head1, head2, head3, head4, head5);
$(thead).append(headrow);
$(table).append(thead);
// table body
var tbody = $('<tbody>');
num_answers = json.length
for (i = 0; i < num_answers; i++) {
var row = $('<tr>');
var cell1 = $('<td>').text(json[i][0]);
var cell2 = $('<td>').text(json[i][1]);
var cell3 = $('<td>').text(json[i][2]);
var cell4 = $('<td>').text(json[i][3]);
var cell5 = $('<td>').text(json[i][4]);
$(row).append(cell1, cell2, cell3, cell4, cell5);
$(tbody).append(row);
}
$(table).append(row);
$('#mainsection').append(table);
}