Error in Django Get request that dosen't make sense - python

I have a basic Django app right now which allows users to add items to a database. When the product is added, the list of items should update when a new item is added via the form, and display that Product and all the other Products already in the database. Here is the code I have so far:
This is the views.py file with my current implementation of the method that should get the products at the bottom:
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from products.models import Product
from django.http import HttpResponse, JsonResponse
def index(request):
return render(request, 'index.html')
#csrf_exempt
def createProduct(request):
if request.method == 'POST':
name = request.POST.get('name')
description = request.POST.get('description')
price = request.POST.get('price')
newProduct = Product(
name = name,
description = description,
price = price
)
newProduct.save()
return HttpResponse('')
def viewProduct(request):
if request.method == 'GET':
ProductList = Product.objects.all()
products=[]
for Product in ProductList:
products.append({"name": Product.name, "description": Product.description, "price": Product.price})
return JsonResponse(products)
The index.html page:
<!DOCTYPE html>
<html>
<body>
<div>
<h2 id="title">Create product</h2>
<input id="name">Name</input>
<br>
<input id="description">Description</input>
<br>
<input id="price">Price</input>
<br>
<button id="add-product">ADD PRODUCT</button>
</div>
<div id="productList">
</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript">
document.getElementById('add-product').onclick = function(){
sendData();
getData();
}
function sendData(){
var order = {
name: document.getElementById('name').value,
description: document.getElementById('description').value,
price: document.getElementById('price').value
};
$.ajax({
type: "POST",
url: 'create/product',
data: order,
success: function(newProduct){
console.log("success"),
$('#name').val(""),
$('#description').val(""),
$('#price').val("")
}
});
};
function getData(){
$.ajax({
url: 'view/product',
dataType: 'json',
type: 'GET',
success: function(data){
$.each(data.Product, function(index, element){
$('body').append($('productList', {
text: element.name
}));
});
}
});
}
</script>
</html>
And the urls.py file:
from django.contrib import admin
from django.urls import path
from products import views
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.index),
path('create/product', views.createProduct),
path('view/product', views.viewProduct)
]
So far, adding a product in is fine and causes no issues. However, after writing the getData() method and including it, this part dosen't work and returns the following error:
File "C:\Users\install\Documents\tutorial\products\views.py", line 29, in viewProduct
ProductList = Product.objects.all()
UnboundLocalError: local variable 'Product' referenced before assignment
I'm confused by this error as I'm not assigning Product anywhere else in this file so not sure why it's returning this error. When I do this same assignment in the Shell, it doesn't have a problem with it and returns all the objects. Can someone help me resolve this? Thanks.

The problem is here:
def viewProduct(request):
if request.method == 'GET':
ProductList = Product.objects.all()
products=[]
for Product in ProductList: # <= This is where cause the problem
products.append({"name": Product.name, "description": Product.description, "price": Product.price})
return JsonResponse(products)
You have to change for Product in ProductList to Something else like for _Product in ProductList
Try this one:
def viewProduct(request):
if request.method == 'GET':
ProductList = Product.objects.all()
products=[]
for prod in ProductList:
products.append({"name": prod.name, "description": prod.description, "price": prod.price})
return JsonResponse(products)

Related

Django -> 'WSGIRequest' object has no attribute 'data' -> Error in json.loads(request.data)

I saw a similar question but the answer is rather vague. I created a function based view for updateItem. I am trying to get json data to load based on my request. but am getting the error -> object has no attribute 'data'
Views.py file:
def updateItem(request):
data = json.loads(request.data)
productId = data['productId']
action = data['action']
print("productID", productId, "action", action)
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("Item was added!", safe=False)
JS File:
function updateUserOrder(productId, action) {
console.log('User is logged in...');
let url = '/update_item/';
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken,
},
body: JSON.stringify({ productId: productId, action: action }),
})
.then((res) => {
return res.json();
})
.then((data) => {
console.log('data', data);
});
}
urls python file:
urlpatterns = [
path("",views.store,name="store"),
path("cart/",views.cart,name="cart"),
path("checkout/",views.checkout,name="checkout"),
path("update_item/",views.updateItem,name="update_item"),
]
The Error seems to also occur in my fetch function in the JS file. With my method POST. Can't find a solution, what am I doing wrong here?
The main problem is that you are trying to access 'request.data', there is no such attribute. What you want is to retrieve data from the POST request.
(Also, note that good practice is to have your views and variable names in snake_case form, whereas camelCase is used for classes):
def updateItem(request):
data = json.loads(request.POST.get('data'))
...
return JsonResponse("Item was added!", safe=False)
Although, to complete my answer, I must say that I had problems with your JS function, with the csrf token not being properly attached. My test solution:
views.py
from django.shortcuts import render
from django.http import JsonResponse
import json
def update_item(request):
return render(request, 'update_item.html', {})
def update_item_ajax(request):
data = json.loads(request.POST.get('data'))
print(data)
...
return JsonResponse({'message': '"Item was added!"'}, safe=False)
# output of update_item_ajax print
{'productId': 1, 'action': 'myaction'}
urls.py
from django.urls import path
from core import views
app_name = 'core'
urlpatterns = [
path('update/item/', views.update_item, name='update-item'),
path('update/item/ajax/', views.update_item_ajax, name='update-item-ajax'),
]
update_item.html
{% extends 'base.html' %}
{% block content %}
<button onclick="updateUserOrder(1, 'action')"> update item </button>
{% endblock %}
{% block script %}
<script>
function updateUserOrder(productId, action) {
console.log('User is logged in...');
let url = "{% url 'core:update-item-ajax' %}";
var payload = {
productId: productId,
action: action
};
var data = new FormData();
data.append( 'data' , JSON.stringify( payload ) );
data.append('csrfmiddlewaretoken', '{{ csrf_token }}');
fetch(url,
{
method: 'POST',
body: data,
})
.then(function(res){ return res.json(); })
.then(function(data){ console.log(data); });
}
</script>
{% endblock %}
Try:
data = json.loads(request.body)
Because the request doesn't have data, since you pass the data as body: JSON.stringify({ productId: productId, action: action }),

Why my url appears as a post request when its get django

I have some templates in a django project. I'm trying to save them in the the url with a post request even though I specify it in the html document.
Here's my views.py
`
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from .forms import WcaForm, IdForm
from . import wcaScraper
# Create your views here.
def id(response):
form = IdForm(response.GET)
return render(response, "main/id.html", {"form": form})
def idresults(response):
print(response.method)
if response.method == "GET":
print(wcaScraper.getDataByName(response.GET.get('name')))
return render(response, "main/nameresults.html", {"ids": wcaScraper.getDataByName(response.GET.get('name'))})
def search(response):
form = WcaForm(response.GET)
return render(response, "main/search.html", {"form": form})
def results(response):
wcaData = wcaScraper.getDataById(response.GET.get('id'))
variablePassed = {
"id": response.GET.get('id'),
"single3": wcaData[0].single,
"avg3": wcaData[0].avg,
"single2": wcaData[1].single,
"avg2": wcaData[1].avg,
"single4": wcaData[2].single,
"avg4": wcaData[2].avg,
"single5": wcaData[3].single,
"avg5": wcaData[3].avg,
"single6": wcaData[4].single,
"avg6": wcaData[4].avg,
"single7": wcaData[5].single,
"avg7": wcaData[5].avg,
"blind3single": wcaData[6].single,
"blind3avg": wcaData[6].avg,
"fmsingle": wcaData[7].single,
"fmavg": wcaData[7].avg,
"ohsingle": wcaData[8].single,
"ohavg": wcaData[8].avg,
"clocksingle": wcaData[9].single,
"clockavg": wcaData[9].avg,
"megasingle": wcaData[10].single,
"megaavg": wcaData[10].avg,
"pyrasingle": wcaData[11].single,
"pyraavg": wcaData[11].avg,
"skewbsingle": wcaData[12].single,
"skewbavg": wcaData[12].avg,
"squaresingle": wcaData[13].single,
"squareavg": wcaData[13].avg,
"blind4single": wcaData[14].single,
"blind4avg": wcaData[14].avg,
"blind5single": wcaData[15].single,
"blind5avg": wcaData[15].avg,
"multisingle": wcaData[16].single,
"multiavg": wcaData[16].avg,
}
return render(response, "main/results.html", variablePassed)
`
And my html template
<html>
<h1>Search by name</h1>
<form method="get" action="/idresults">
{% csrf_token %} {{form}}
<button type="submit">Search</button>
</form>
<p>or</p>
Search by WCA Id
</html>
I tried printing the method and I got `GET
But the url looks like this
http://localhost:8000/idresults/?csrfmiddlewaretoken=v1jXO1Tei1eU0l8FbgF49qeJU5zKJlTQUUkggmW0oYgrG5WcLOvJhBb08PBY3klg&name=zemdegs
Your url does not appear as a POST, but as a GET. If your problem is the token, just remove the {%csrf_token%} from your template.

Using ajax jquery for search form

I'm working on a Django project where I want to use ajax jquery to complete my search in my search form.
Tried everything, but it does not seem to work.
Pls, where have I missed it?
used this tutorial
views.py
import json
def search(request):
if request.method == 'POST':
form = SearchForm(request.POST)
if form.is_valid():
query = form.cleaned_data['query']
catid = form.cleaned_data['catid']
if catid == 0:
products = Product.objects.filter(name__icontains=query)
else:
products = Product.objects.filter(name__icontains=query, category_id=catid)
category = Category.objects.all()
context = {
'products': products,
'category': category,
'query': query,
}
return render(request, 'shop/product/search.html', context)
return HttpResponseRedirect('/')
def search_auto(request):
if request.is_ajax():
q = request.GET.get('term', '')
products = Product.objects.filter(name__icontains=q)
results = []
for pl in products:
product_json = {}
product_json = pl.name
results.append(product_json)
data = json.dumps(results)
else:
data = 'fail'
mimetype = 'application/json'
return HttpResponse(data, mimetype)
<script>
$(function() {$("#query").autocomplete({
url: "{% url 'shop:search_auto' %}",
select: function (event, ui) {AutoCompleteSelectHandler(event, ui)},
minLength: 2,
});
});
function AutoCompleteSelectHandler(event, ui)
{var selectedObj = ui.item;}
</script>
path('search', views.search_auto, name='search_auto'),
Thanks.

Ajax function not working for next element played by 'for' in django template

I meet difficulties as below :
I have a blog page. In blog ,i create 'comment' function to comment post. And comments has 'like' function. For this ,i create two view function ,one of them simple function ,second is api function. And create jquery ajax for to call api function. After api calling ,it update data in db. Problem is :
If i create two comment ,ajax function works only for first comment for to like comment. It looks like ,for first comment CommentLikeAPIToggle works ,for next comments CommentLikeToggle works. Here is my codes :
views.py
class CommentLikeToggle(RedirectView):
def get_redirect_url( self, *args, **kwargs):
id = self.kwargs.get('id')
obj = get_object_or_404(Comment,id=id)
url_ = obj.content_object.get_absolute_url()
user = self.request.user
if user.is_authenticated():
if user in obj.likes.all():
obj.likes.remove(user)
else:
obj.likes.add(user)
return url_
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authentication, permissions
class CommentLikeAPIToggle(APIView):
authentication_classes = (authentication.SessionAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
def get(self, request,id=None, format=None):
obj = get_object_or_404(Comment,id=id)
url_ = obj.get_absolute_url()
user = self.request.user
updated = False
liked = False
if user.is_authenticated():
if user in obj.likes.all():
liked = False
obj.likes.remove(user)
else:
liked = True
obj.likes.add(user)
updated = True
data = {
'updated':updated,
'liked':liked
}
return Response(data)
Ajax function :
function updateComLike (newCount,btn,verb){
btn.text(" "+newCount+ " " + verb);
btn.attr({"data-likes": newCount,"class":"fa fa-thumbs-up"})
}
$("#com-like").click(function(e){
e.preventDefault()
var this_ = $(this)
var likeUrl = this_.attr("data-href")
var likeCount = parseInt(this_.attr("data-likes"))
$.ajax({
url: likeUrl,
method: "GET",
data : {},
success: function(data){
var newLikes;
if (data.liked){
newLikes = likeCount + 1
updateComLike(newLikes,this_ ,gettext("Unlike"))
} else {
newLikes = likeCount - 1
updateComLike(newLikes,this_ ,gettext("Like"))
}
}, error: function(error){
}
})
})
Template tag :
{% for comment in comments %}
{{ comment.content }}
<footer>
<a data-href="{{comment.get_api_com_like_url}}" data-likes="
{{comment.likes.count}}" href="{{comment.get_com_like_url}}" id="com-like">
<i class="fa fa-thumbs-up"></i> {{comment.likes.count}}
{% if request.user in comment.likes.all %} {% trans "Unlike" %}
{%else%}{%trans "Like" %}{% endif %}
</a>
</footer>
{% endfor %}
Urls :
url(r'^api/(?P<id>\d+)/com-like/$',CommentLikeAPIToggle.as_view(), name='com-like-api-toggle'),
url(r'^(?P<id>\d+)/com-like/$',CommentLikeToggle.as_view(), name='com-like-toggle'),
I have found my problem and solved it myself. The problem is :i'm using id in template tags. And id should be unique to each element. So i used class instead of id and problem fixed
{{comment.likes.count}}" href="{{comment.get_com_like_url}}" class="com-like">
And in the ajax
$('a.com-like').click(function(e){

Django - How to use render_to_response whose request is $http

In Django it is possible to use the render_to_response when the request comes from a $http of angularjs?
Example:
<!--proposta.html-->
<div ng-app='App' ng-controller="MyCtrl">
<input type="submit" value="Gerar" ng-click="post_dados(x)">
</div>
This button passes a parameter to the function in post_dados() in file data_app.js
var myApp = angular.module('App', []);
function MyCtrl($scope,$http,$sce) {
$scope.retorno
$scope.post_dados = function (lista) {
$http({
method:'POST',
url:'/send_proposta/',
data: lista,
headers:{'Content-Type': 'application/x-www-form-urlencoded'},
}).success(function(retorno){
$scope.retorno=retorno
})
}
}
urls.py
urlpatterns = patterns('',
url(r'^send_proposta/$', 'mge.core.views.send_proposta'),)
views.py
def send_proposta(request):
proposta_tratada, header = tratar_proposta(request.POST)
if proposta_tratada=='erro':
json_erro=simplejson.dumps('Incorrect reporting of the Proposal, fill again')
return HttpResponse(json_erro, content_type ="application/json")
else:
table_edit=valido(proposta_tratada, header)
return render_to_response('rateio.html', {'x' : table_edit})
The return HttpResponse sends the message to the .success (function (return) {...} put the return render_to_response ('rateio.html', {x:. table_edit}) does not send the information to the rateio.html, just goes to the rateio.html if the source is a form.
It is possible to use the render_to_response with the $http? If possible, how could I do it?

Categories

Resources