Django AJAX form, no POST data in view - ajax

I have some contact form and JS/Angular code sending it to view for some validation and mailing.
contact_form.js
(function() {
var app = angular.module('contactForm', []);
app.config(function ($httpProvider) {
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
});
app.controller('contactFormController', ['$http', '$scope', function($http, $scope){
$scope.contact_form = {};
this.send = function(form){
if (form.$valid){
$http.post('/contact_form_submit/', {'form': $scope.contact_form}).
success(function(data, status, headers, config) {
if (data.status == 1) {
$scope.msg = 'Twoja wiadomość została wysłana.';
$scope.contact_form = {};
$scope.contactForm.$setPristine();
}
else if (data.status == 'delay')
$scope.msg = 'Odczekaj.';
}).
error(function(data, status, headers, config) {
$scope.msg = 'Wystąpił błąd.';
if (status == '403')
$scope.msg += ' Włącz cookie!';
});
}
else
this.msg = 'invalid!';
};
}]);
})();
view.py
def contact_form_submit(request):
return return_json(request)
if not request.is_ajax() or (request.method != 'POST'):
raise SuspiciousOperation
response_data = {}
# dealing with existing (or not) delay entry
try:
if request.session['mailer_delay'] > str(timezone.now()):
response_data['status'] = 'delay'
return return_json(response_data)
except KeyError:
pass
# validation
form_data = {}
for field in ['name', 'email', 'phone', 'subject', 'text']:
form_data[field] = request.POST.items()
# mailing
mailer = send_mail('Subject here', 'Here is the message.', 'from#example.com',
['to#example.com'], fail_silently=False)
request.session['mailer_delay'] = str(timezone.now()+timedelta(seconds=60))
response_data['status'] = mailer
return return_json(response_data)
and the return_json()
def return_json(data):
from django.http import HttpResponse
import json
return HttpResponse(json.dumps(data), content_type="application/json")
The problem is i get no items at all in request.POST in view. Firebugs tells me that data was sent correctly, but there's no in view.
Someone knows the answer what's wrong?

Ok, i got it. All data was in request.body, not request.POST.
Could anyone explain why? I've read the docs, but still it's not clear for me.

Related

Ajax post request don't work with flask route

I'm trying to build a 'like' button with ajax and flask,but when I try to get the string for the button to decide which button was clicked,my alert always return 'None'.
flask relevant part:
#bp.route('/<int:id>/post', methods=('GET', 'POST'))
#login_required
def show_post(id):
my_opinion=request.form.get("opinion")
my_post=get_post(id,False)
if request.method == 'POST':
opi = request.form.get("opinion")
if opi == 'Like':
update_like(id,my_post,g.user['id'])
my_opinion='like'
elif opi == 'Dislike':
update_dislike(id,my_post,g.user['id'])
my_opinion='dislike'
user_info=g.user['id']
user_new = get_db().execute(
'SELECT liked_posts,disliked_posts'
' FROM user u'
' WHERE id = ?',
(user_info,)
).fetchone()
return render_template('blog/show.html',post=my_post,user=user_new,my=my_opinion)
ajax part:
<script src="https://code.jquery.com/jquery-3.5.1.js"
integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc="
crossorigin="anonymous"></script>
<script type="text/javascript">
$(document).on('submit','.opin',function(e)
{
e.preventDefault();
$.ajax({
type:'POST',
url:'/1/post?author=josh',
data:{
opinion:"check"
},
success:function()
{
const new_opinion = document.getElementsByClassName("opinion");
let special = "{{my}}";
alert(special);
const cssObj = window.getComputedStyle(new_opinion[0], null);
let bgColor = cssObj.getPropertyValue("background-color");
if (bgColor=='rgb(128, 128, 128)'){
bgColor="linear-gradient(144deg,#AF40FF, #5B42F3 50%,#00DDEB)";
}
else{
bgColor="gray"
}
new_opinion[0].style.background=bgColor;
}
})
});
</script>
This part alert 'None':
let special = "{{my}}";
alert(special);
I'm trying to get 'check' string into 'my' template parameter.

Display JsonResponse data in template

I want to send the JsonResponse data in the demo.html and display in it. what is wrong in my code. please help me to solve it.
function ComAction() {
let xhr = new XMLHttpRequest(),
data = new FormData();
data.append('csrfmiddlewaretoken', getCookie('csrftoken'));
brands.forEach(function (brand) {
data.append('brand', brand);
});
xhr.open('POST', 'compare_in/', true);
xhr.onload = function () {
if (xhr.status === 200) {
data = JSON.parse(xhr.responseText);
console.log(data);
alert('Data received successfully. Brands are ' + data.brands);
window.location.assign({% url 'demo' %});
} else if (xhr.status !== 200) {
alert('Request failed.');
}
};
xhr.send(data);
}
it's my urls:
urlpatterns = [
path('compare_in/', views.compare, name='compare'),
path('demo/', views.demo, name='demo'),
]
it's my views:
def compare(request):
if request.method == 'POST':
compare_res = request.POST.getlist('brand')
d3 = {'brand':{'x', 'y'}, 'color':{'black', 'white'}}
response_data = {
'brands': d3,
'redirect_url': 'http://127.0.0.1:8000/demo/'}
return JsonResponse(response_data)
return render(request, 'prodcutSearch/compare_in.html')
def demo(request):
return render(request, 'prodcutSearch/demo.html')

Django json loads fails because of empty query dict in request Object

I have ajax call posted to /cart/total where I am dumping JSON string stored in local storage using post when I run json loads it shows me the error.
TypeError(f'the JSON object must be str, bytes or bytearray, '
TypeError: the JSON object must be str, bytes or bytearray, not QueryDict
and my JSON string before parsing looks like having an empty feild, which I am not aware of in Django
<QueryDict: {'{"32":1,"33":1,"34":2}': ['']}>
<script>
function addtocart(mitem, mprice) {
if(localStorage.getItem('cart')==null){
// var mobj = {}
// var countQ ={}
var price = String(mprice)
var mobj = { [String(mitem)]: 1 }
var countQ = {'Quantity':1}
var storeobj = JSON.stringify(mobj)
var storeCountq = JSON.stringify(countQ)
localStorage.setItem('cart', storeobj)
localStorage.setItem('quantity',storeCountq)
console.log(localStorage.getItem('cart'))
}else{
var data = localStorage.getItem('cart')
var quant = localStorage.getItem('quantity')
var obj = JSON.parse(data)
var parsequant = JSON.parse(quant)
if(obj.hasOwnProperty(String(mitem))){
obj['%s',mitem]++
parsequant['Quantity']++
var storeobj = JSON.stringify(obj)
console.log(localStorage.getItem('cart'))
var storeCountq = JSON.stringify(parsequant)
localStorage.setItem('cart', storeobj)
localStorage.setItem('quantity', storeCountq)
}
else{
obj[String(mitem)] = 1
parsequant['Quantity']++
var storeobj = JSON.stringify(obj)
console.log(localStorage.getItem('cart'))
var storeCountq = JSON.stringify(parsequant)
localStorage.setItem('cart', storeobj)
localStorage.setItem('quantity', storeCountq)
}
}
}
function ajaxcall(){
$.ajax(
{
type: "POST",
url: "/cart/total",
data: localStorage.getItem('cart'),
success: function () {
console.log("sent tdata")
}
})
}
ajaxcall()
</script>
<p style="position: absolute; bottom: 0px"><button class="button" style="width: 200px" onclick="addtocart( '{{M.Menu_Item_Id}}', '{{M.Menu_ItemPrice}}' )" >Add to cart</button>
view function
#csrf_exempt
def cartpricecalculator(request):
if request.method == 'POST':
data = json.loads(request.POST)
print(request.POST)
return HttpResponse('200 Okay')
I am not sure what I am doing wrong, any help is appreciated.
request.POST is for form data. You need;
data = json.loads(request.body)
Try:
In JS, pass a dict instead of a string. As per the documentation of ajax, data must be an Object with key and value or stringify of an Object with key and value.
Ref: https://api.jquery.com/jQuery.ajax/
function ajaxcall(){
$.ajax(
{
type: "POST",
url: "/cart/total",
data: {'cart': localStorage.getItem('cart')},
success: function () {
console.log("sent tdata")
}
})
}
In python
#csrf_exempt
def cartpricecalculator(request):
if request.method == 'POST':
cart_data = json.loads(request.POST.get('cart', '{}'))
print(request.POST)
print(request.POST.get('cart'))
return HttpResponse('200 Okay')

Using Select2 autocomplete with Django project does not work while fetching the data

In my Django project, I have a Search field. I used Select2 autocomplete with it. I needed to fetch the product_list from my Product model. So I created a rest API that returns the product in json formats.
Here is my rest API code:
serializer.py:
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = ProductList
fields = ('product_id', 'product_name', 'product_image', 'product_available',
'product_description')
views.py:
class JSONResponse(HttpResponse):
def __init__(self, data, **kwargs):
content = JSONRenderer().render(data)
kwargs['content_type'] = 'application/json'
super(JSONResponse, self).__init__(content, **kwargs)
def list(request):
if request.method == 'GET':
products = ProductList.objects.filter(product_name__icontains=request.GET.get('q'))
serializer = ProductSerializer(products, many=True)
serializer_data = serializer.data
customData = {'results': serializer_data}
return JSONResponse(customData)
Now in my html, in the javascript portion I used this code mentioned in this Select2 doc. The code I used, looks like this:
base.html:
<script type="text/javascript">
$(document).ready(function() {
$('.js-data-example-ajax').select2({
ajax: {
url: "/api.alif-marine.com/search/products",
dataType: 'json',
delay: 250,
type: 'GET',
data: function (params) {
return{
q: params.term, // search term
page: params.page
};
},
processResults: function (data, params) {
params.page = params.page || 1;
return {
results: data.results,
};
},
cache: true
},
placeholder: 'Search for a product',
escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
minimumInputLength: 1,
templateResult: formatRepo,
templateSelection: formatRepoSelection
});
function formatRepo (repo) {
if (repo.loading) {
return repo.text;
}
var markup = "<div class='select2-result-repository clearfix'>" +
{# "<div class='select2-result-repository__avatar'><img src='" + repo.owner.avatar_url + "' /></div>" +#}
"<div class='select2-result-repository__meta'>" +
"<div class='select2-result-repository__title'>" + repo.product_name + "</div>";
if (repo.product_description) {
markup += "<div class='select2-result-repository__description'>" + repo.product_description + "</div>";
}
return markup;
}
function formatRepoSelection (repo) {
return repo.product_name || repo.text;
}
});
</script>
When I used Postman to check if the rest API works or not, it worked perfectly. For my query in the Postman like these:
localhost:8000/api.alif-marine.com/search/products?q=t
or
localhost:8000/api.alif-marine.com/search/products?q=tho
or
localhost:8000/api.alif-marine.com/search/products?q=thomas
The retrieved json data is given below for query localhost:8000/api.alif-marine.com/search/products?q=t :
{
"results":[
{
"product_id":9,
"product_name":"thomas",
"product_image":"/media/media/tom_dushtu.jpg",
"product_available":"available",
"product_description":"jah dushtu"
},
{
"product_id":8,
"product_name":"ami dissapointed",
"product_image":"/media/media/dissapointment.jpg",
"product_available":"available",
"product_description":"I ma kinda dissapointed, you know.................."
}
]
}
Now with all those, I couldn't make it work. The autocomplete is not working. Nothing is shown when I press one key or write the name of the whole product.
. It always has shown Searching.... I tried reading the issues on the Github repo and some other things but couldn't solve it.
What am I doing wrong?
This is how the select2 library is handled:
views.py:
class BurdenTypeAutocomplete(autocomplete.Select2QuerySetView):
def get_result_label(self, obj):
return format_html(" {} / {}", obj.arabic_name,obj.englsh_name)
def get_queryset(self):
qs = BurdenTypeSales.objects.filter(effect_type="2")
if self.q:
qs = qs.filter(
Q(arabic_name__icontains=self.q)
| Q(account__number__icontains=self.q)
| Q(englsh_name__icontains=self.q)
)
return qs[:10]
Url.py:
url(r'^burden_type_autocomplete/$',views.BurdenTypeAutocomplete.as_view(),name='burden_type_autocomplete'),
form.py:
burden_type_sales = forms.ModelChoiceField(queryset=BurdenTypeSales.objects.filter(effect_type='2'),
widget=autocomplete.ModelSelect2(url='burden_type_autocomplete',attrs={'required':'required'}))

Uploading files to tastypie with Backbone?

Checked some other questions and I think my tastypie resource should look something like this:
class MultipartResource(object):
def deserialize(self, request, data, format=None):
if not format:
format = request.META.get('CONTENT_TYPE', 'application/json')
if format == 'application/x-www-form-urlencoded':
return request.POST
if format.startswith('multipart'):
data = request.POST.copy()
data.update(request.FILES)
return data
return super(MultipartResource, self).deserialize(request, data, format)
class ImageResource(MultipartResource, ModelResource):
image = fields.FileField(attribute="image")
Please tell me if that's wrong.
What I don't get, assuming the above is correct, is what to pass to the resource. Here is a file input:
<input id="file" type="file" />
If I have a backbone model img what do I set image to?
img.set("image", $("#file").val()); // tastypie doesn't store file, it stores a string
img.set("image", $("#file").files[0]); // get "{"error_message": "'dict' object has no attribute '_committed'" ...
What do I set my backbone "image" attribute to so that I can upload a file to tastypie via ajax?
You may override sync method to serialize with FormData api to be able to submit files as model's attributes.
Please note that it will work only in modern browsers. It worked with Backbone 0.9.2, I advise to check the default Backbone.sync and adopt the idea accordingly.
function getValue (object, prop, args) {
if (!(object && object[prop])) return null;
return _.isFunction(object[prop]) ?
object[prop].apply(object, args) :
object[prop];
}
var MultipartModel = Backbone.Model.extend({
sync: function (method, model, options) {
var data
, methodMap = {
'create': 'POST',
'update': 'PUT',
'delete': 'DELETE',
'read': 'GET'
}
, params = {
type: methodMap[method],
dataType: 'json',
url: getValue(model, 'url') || this.urlError()
};
if (method == 'create' || method == 'update') {
if (!!window.FormData) {
data = new FormData();
$.each(model.toJSON(), function (name, value) {
if ($.isArray(value)) {
if (value.length > 0) {
$.each(value, function(index, item_value) {
data.append(name, item_value);
})
}
} else {
data.append(name, value)
}
});
params.contentType = false;
params.processData = false;
} else {
data = model.toJSON();
params.contentType = "application/x-www-form-urlencoded";
params.processData = true;
}
params.data = data;
}
return $.ajax(_.extend(params, options));
},
urlError: function() {
throw new Error('A "url" property or function must be specified');
}
});
This is excerpt from upload view, I use <input type="file" name="file" multiple> for file uploads so user can select many files. I then listen to the change event and use collection.create to upload each file.
var MultipartCollection = Backbone.Collection.extend({model: MultipartModel});
var UploadView = Backbone.View.extend({
events: {
"change input[name=file]": "changeEvent"
},
changeEvent: function (e) {
this.uploadFiles(e.target.files);
// Empty file input value:
e.target.outerHTML = e.target.outerHTML;
},
uploadFiles: function (files) {
_.each(files, this.uploadFile, this);
return this;
},
uploadFile: function (file) {
this.collection.create({file: file});
return this;
}
})

Resources