so i was trying to send category to django url (that takes category when visited through url) with ajax in this website, but i am getting this error which i don't seem to understand. Please help!
urls.py
urlpatterns=[
path('category/<str:category>', views.getcategory, name = 'get_category'),
]
views.py:
def get_category(request, category=None):
#To get category if requested via AJAX
if request.is_ajax and request.method == "GET":
category = request.GET.get("last_joke_id", category)
if category!=None:
return HttpResponse('\n Received via Json. \n')
else:
return HttpResponse('\n Received via URL. \n')
index.html:
<script>
function send_category(category){
$.ajax({
type: 'POST',
*url:"{% url 'get_category' %}"*, /*Error in this line*/
data: {'category':category},
success: function(response) {
console.log("\n\nCategory data Successfully recived.\n");
console.log( response );
//displayJokes(response);
}, error: function (response) {
console.log('\n\n error in retriving category data:');
console.log(response);
//return 'her';
}
})
}
</script>
Error Message:
django.urls.exceptions.NoReverseMatch: Reverse for 'get_category' with no arguments not found. 1 pattern(s) tried: ['jokes/category/(?P[^/]+)$']
It means that category is required parameter in your route, so you may fix that if you change your route and view function, like that:
urls.py
path('category/', views.getcategory, name = 'get_category'),
views.py
def getcategory(request):
category = request.GET.get("category")
if request.is_ajax and request.method == "GET":
category = request.GET.get("last_joke_id", category)
if category!=None:
return HttpResponse('\n Received via Json. \n')
else:
return HttpResponse('\n Received via URL. \n')
Or you may create two routes, with and without parameters:
path('category/', views.getcategory, name = 'get_category_default'),
path('category/<str:category>', views.getcategory, name = 'get_category'),
Then you need to set default value in your function:
def get_category(request, category=None):
...
And Finally you need to replace your get_category route to get_category_default in your js code
Related
In my django project, I built a little like-button. The problem is, that I had it only when I take a detailed view on a post, and now want to put it on the home page, where multiple posts are shown. The problem the Like Function of the button returns to the detailed page, but I want to make the return dependent from the url where the like came from, so that I can just scroll ahead on the home page or what ever page am on, without being returned to another page. So here is my views.py Like function:
def PostLike(request, pk):
post = get_object_or_404(Post, id=request.POST.get('post_id'))
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
else:
post.likes.add(request.user)
return HttpResponseRedirect(reverse('post-detail', args=[str(pk)]))
So in a nutshell: how could I change my Like function so that I am returned to the page I liked from?
Your function returns a Redirect, that's why you are redirected to the detail page.
If you want to stay on the same page after clicking 'Like' you could submit a request through Ajax and return a JsonResponse with a message or a value depending on what you get from the database query.
How to do this varies based on what JS library or framework you are using. Here is a simplistic JQuery example:
in views.py
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
def like_or_unlike(request, id):
if request.user.is_authenticated:
try:
post = get_object_or_404(Post, id=id)
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
message = 'You unliked post ' + id
else:
post.likes.add(request.user)
message = 'You liked post ' + id
except:
message = 'Error processing like for post ' + id
else:
message = 'You must be logged in to like a post.'
return JsonResponse({ 'result': message })
in urls.py
from django.urls import path
from . import views
urlpatterns = [
...
path("like/<id>/", views.like_or_unlike),
]
in template.html
<button class="{% if post.liked %}color-blue{% else %}color-white{% endif %}"
id="post_{{ post.id|stringformat:"s" }}"
onclick="postLike( '{{ post.id|stringformat:"s" }}' )"> Like this post </button>
<script>
function postLike(id) {
var element = "#post_" + id
$.ajax({
url: '/like/' + id,
type: 'get',
contentType: 'application/json',
success: function(data) {
console.log(data);
if $(element).hasClass("color-white") {
$(element).removeClass("color-white");
$(element).addClass("color-blue");
} else {
$(element).removeClass("color-blue");
$(element).addClass("color-white");
}
},
error: function(jqXhr, textStatus, errorThrown) {
console.log(errorThrown);
}
});
}
</script>
I think you should use Ajax request for it so you don't even reload page. Just handle it in JavaScript.
Otherwise you can redirect base on request.referer value to go back to the view where click was made
I use the $.ajax to request the data, but how can I let the page switch as the same time?
in my js:
$.ajax({
type:'post',
url:'/api/server_payment',
...
success:success_func,
})
function success_func(response){
...
}
In my views.py:
def server_payment(request):
if request.method == 'POST':
# I don't know what to write here, because there I will switch the web page, and then fill the request data to the switched template.
EDIT
Because I want to pass data by the ajax to the views.py , and in the views.py I want to switch the url to a new url, and in the new url , I will render the passed data.
Because use the ajax requert I will get the response in the ajax callback function.
You just pass your data from ajax to the views with the post data:
file.js
data = {
'key': value,
'another_key': another_value,
// as many as you need
...
}
$.ajax({
type:'post',
url:'/api/server_payment',
data: data
...
success:success_func,
})
function success_func(response){
...
}
Now in your view server_payment store them in the session :
def server_payment(request):
if request.method == 'POST':
request.session['key'] = request.POST.get('key')
request.session['another_key'] = request.POST.get('another_key')
...
return HttpRedirectResponse('/other/url')
And now in your other views (corresponding to the one at '/other/url', you'll access to the data in request.session. In the other views, get data by poping them to empty the request.session dict :
views.py rendering the data
def another_view(request):
data = {}
data['key'] = request.session.pop('key', "NOT_FOUND") # this will prevent from raising exception
data['another_key'] = request.session.pop('another_key', "NOT_FOUND")
...
return render('/your/template.html', data)
I want to pass data by the ajax to the views.py , and in the views.py I want to switch the url to a new url, and in the new url , I will render the passed data.
The thing I don't understand is why you don't send your post data directly in the good view to render instead of having a view getting the post data and redirecting to another one.
I am trying to POST a request to a django view but it keeps returning INTERNAL SERVER ERROR 500.
My ajax post:
$.ajax({
url : "/loginAction/",
type : "POST",
async : false,
data : {action:'loginAction',
email:email,
password:password},
success : function(response) {
$.niftyNoty({
type:"success",icon:"",title:"Login Successful. Redirecting....",container:"floating",timer:5000
});
},
error : function(xhr,errmsg,err) {
console.log(xhr.status + ": " + xhr.responseText);
$.niftyNoty({
type:"danger",icon:"",title:"Wrong Email OR Password",container:"floating",timer:5000
});
}
});
My django view:
def loginAction(request):
print "Its workjing"
if request.method == 'POST' and 'loginButton' in request.POST:
email = request.POST.get('email')
password = request.POST.get('password')
print email, password
return HttpResponse(json.dumps({}),content_type="application/json")
My urls.py
urlpatterns = [
url(r'^', views.loginPage, name='loginPage'),
url(r'^loginAction/', views.loginAction, name='loginAction')
]
The ajax POST is not hitting the django view. It is not printing Its working in console. So its not returning the json response to ajax call. I also tried normal form POST but same result. I am using django 1.9.2. I cant figure out why this error?
It returns this error code:
Internal Server Error: /loginAction/
Traceback (most recent call last):
File "/home/manish/Desktop/admin_picknbox/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 158, in get_response
% (callback.__module__, view_name))
ValueError: The view login_app.views.loginPage didn't return an HttpResponse object. It returned None instead.
EDIT:
ajax Header:
jQuery(document).ready(function($){
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
});
It seems your urls are the problem because in the error appears that the loginPage view is called although you go to /loginAction/. So try to add $ at the end of each regex as below:
urlpatterns = [
url(r'^$', views.loginPage, name='loginPage'),
url(r'^loginAction/$', views.loginAction, name='loginAction')
]
Because it appears that your first regex r'^' captures any url.
Your view function doesn't take care of all cases, in case if request.method == 'POST' and 'loginButton' in request.POST: is False, you view function doesn't return anything, hence the error. Python function, if left without explicit return statement, would return None.
Edit:
If your print statement is not even executed, then you must have 403 response from django. You need to pass csrf token when you make ajax call to prevent attack from unknown person. Django would check csrf automatically, but you need to pass it as part of the data:
data : {action:'loginAction',
email:email,
password:password,
csrfmiddlewaretoken: '{{ csrf_token }}'},
Also, you should check "action" in request.POST not "loginAction" in request.POST.
i got this error one day but i latter realize that the page returning internal server error has the same name as the html page i wanted to return. i just changed the name of the html page i wanted t return and everything worked fine
I am trying to call my view from django template via an Ajax call.
I want the form object in response from view such that I can render this form via jquery in a div element.
Is it possible ? How?
This is what i tried:
home.html
function get_edit_form(button, id)
{
$.ajax({
url: "/manage/licenses/{{mls_signup_code}}/{{agent_id}}/" + id + "/",
type: "get",
data: {id: id},
success: function(response) {
console.log(response);
$("#formdiv").html({{ response.as_p }});
}
})
}
Views.py
elif request.method == "GET":
owned_license_id = request.GET.get('id', '')
form = OwnedLicenseForm(owned_license_id)
return form
I see what you are trying to do, but you cannot render the html form this way:
$("#formdiv").html({{ response.as_p }});
I think you are confusing server side rendering (Django templates) with client side rendering. Server side rendering happens when your server is processing the request, it cannot render objects produced by javascript running in the browser.
Because response is a javascript object, obtained by jquery sending an Ajax request to your url. At this time, the page has already been rendered by Django's template engine, and sent to the browser. There is no way for Django template to even be aware of this response.
I understand you want to use the as_p() method to render the form, you can do it like this:
function get_edit_form(button, id)
{
$.ajax({
url: "/manage/licenses/{{mls_signup_code}}/{{agent_id}}/" + id + "/",
type: "get",
data: {id: id},
success: function(response) {
console.log(response);
// response is form in html format
$("#formdiv").html(response);
}
})
}
# Views.py
elif request.method == "GET":
owned_license_id = request.GET.get('id', '')
form = OwnedLicenseForm(owned_license_id)
return HttpResponse(form.as_p()) # return a html str
You can accomplish this with a combination of Django and JQuery.
Step 1: Create an ultra simple form_from_ajax.html Template
The template can be as simple as {{form.as_p}}. The point is to not inherit your base template. You're simply using this form_from_ajax.html template to render the HTML of the form.
Step 2: Create a View with a slug argument that helps you get the correct form
def payment_method_ajax(request, method): # method is your slug
"""Load a dynamic form based on the desired payment method"""
options = {
'ach': ECheckForm(), # Dynamic form #1
'credit-card': CreditCardForm(), # Dynamic form #2
}
if method in options.keys():
context = {'form': options[method]}
else:
context = None
template = 'your_app_name/form_from_ajax.html'
return render(request, template, context)
Step 3: Define the AJAX url in urls.py
[...
path(
'payment-method-ajax/<slug:method>/', # notice the slug in the URL
views.payment_method_ajax,
name='payment-method-ajax'),
...]
Step 4: Update your template where you'd like the AJAX loaded form to appear
Make some buttons to have the user select an approprate form option
<button id="btn_ach" onclick="load_payment_form(this)">ACH</button>
<button id="btn_credit_card" onclick="load_payment_form(this)">Credit Card</button>
form-fields is where the dynamic form will be loaded
<form id="id-form" style="display: none;">
{% csrf_token %}
<div id="form-fields"></div>
<input type="submit" value="Save Payment Details"/>
</form>
Make sure to add slugs to your main view's context
context = {
'target': 'Add a New Payment Method',
'h1': 'Add a New Payment Method',
'ach': 'Save an ACH Profile',
'credit_card': 'Save a Credit Card Profile',
'slugs': ['ach', 'credit-card'], # Here are the slugs ****
}
Step 5: Load the form with JQuery and the button's onclick
<script>
var ach = 'ACH';
var creditCard = 'Credit Card';
var form_urls ={
ach : '{% url "payment-method-ajax" slugs.0 %}',
creditCard : '{% url "payment-method-ajax" slugs.1 %}',
}
function load_payment_form(btn) {
if(btn.innerText==ach) {
get_url = form_urls['ach'];
type = ach;
}
else if(btn.innerText==creditCard) {
console.log('Load credit card form');
get_url = form_urls['creditCard'];
type = creditCard;
}
$.get({'url': get_url}).done(
function(data) {
document.getElementById('form-fields').innerHTML = data;})
document.getElementById("id-form").style.display = "block";
}
</script>
There are LOTS of post and pages discussing the use of Django and AJAX, and I've read hundreds over the past day or so looking for the answer to this question. A quick overview:
May of the examples show a hard-coded URL like this:
$.post("/projects/create/", {"name" : name}, function(data) {...
or some use the URL template tag, but with no parameters:
$.post("{% url create_project %}", {"name" : name}, function(data) {...
However, I'd like to include a Django-style parameter in a URL. Here's my url definition:
url(r'ajax/entity_name/(?P<pk>\w+)/$',EntityAjaxView.as_view(),name='entity_name'),
Yes, I'm using a class based view, and it is based on DetailView. This view looks by default for a pk value to be provided in the URL, and in a normal template I would use:
{% url entity_name id_number %}
to provide a link. In my code, I want to grab the value entered in an input box for the pk value. Here is a snippet of my JavaScript (which doesn't work):
var id_number = $('#id_endowmententity_set-' + rownum + '-id_number').val()
$.ajax({
type: "GET",
url: '{% url entity_name id_number %}',
So, my question is, can I use the URL template tag with a value from an input box?
(I know that I could use POST instead of GET and pass the id_number in the POST data, but that won't work well with the DetailView.)
Django is a server-side application. Javascript is client-side. Django templates get rendered on the server, so {% url entity_name id_number %} is evaluated on the server side, and then it's value is returned to the client. Just because of this, it's impossible for you to combine Django templates with javascript. However there are couple of things you can do to solve your problem.
Since you are making an ajax call, and the ajax call depends on some user input, usually the best route for the client to send any type of user input to the server is by either using querystring (thing after ? in the URL) or by sending a POST data. So the simplest thing is to change your your url not to include the pk in the url, but for the view to get that as part of GET or POST data.
url(r'ajax/entity_name/$', EntityAjaxView.as_view(), name='entity_name'),
and the view (sorry I'm not familiar with class based views):
def entity_name(request):
pk = request.GET.get('pk')
...
That seems to me to be the most elegant solution. If however you absolutely need to construct the url on the client side, you can generate a template url on the server side and then replace whatever parts you need on the client side to get the full url. This however requires more maintenance and therefore is more error prone. Simple js example of this approach:
var id_number = $('#id_endowmententity_set-' + rownum + '-id_number').val(),
url = '{% url entity_name 0 %}'.replace('0', id_number);
$.ajax({
type: "GET",
url: url,
...
});
It is possible to set an Ajax url on the element you are selecting using an attribute and it will behave like Django urls. Importantly, you can even access the url in Javascript file. I use it a lot
HTML
<div class="card-body" id="js-products" data-url="{% url 'chart-data' %}">
<div class="chart-area">
<canvas id="testChart"></canvas>
</div>
</div>
Note: the data-url attribute set on parent div
JAVASCRIPT
$(document).ready(function () {
var endpoint = $("#js-products").attr("data-url");
var defaultData = [];
var labels = []
$.ajax({
method: 'GET',
url: endpoint,
success: function (data) {
labels = data.labels
defaultData = data.data_default
setChart()
},
error: function (error_data) {
console.log(error_data)
}
})
function setChart() {
var ctx = document.getElementById('testChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
responsive: true,
data: {
labels: labels,
datasets: [{
label: 'Monthly Performance',
data: defaultData,
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
});
DJANGO VIEWS
Am using django rest framework class view but you can use either of function or class based view
class ChartData(APIView):
authentication_classes = []
permission_classes = []
def get(self, request, format=None):
labels = ['Products', 'User', 'May']
data_default = [SeedProduct.objects.all().count(),
User.objects.all().count(), 4]
data = {
'labels': labels,
'data_default': data_default,
}
return Response(data)
DJANGO URLS:
import the view class from views
path('api/chart/data', views.ChartData.as_view(), name="chart-data"),
It's pretty time consuming to go round trip to a server just to fetch a URL. The best strategy to keep URLs dry and avoid this is to generate javascript that emulates Django's native url reverse function and then serve that code statically with the rest of your client side JS.
django-render-static does just that.
This worked for me.
my URL was:
path('myurl/<str:type>', views.myfunction, name='myfunction')
my views.py file:
def myfunction(request,type):
return render(request, "payment.html", context)
In my template, I solved the issue by:
<button type="button" class="btn"
onclick="myfunction('forward');">My Button Name
</button>
<script>
function myfunction(type){
let url = "{% url 'appName:myfunction' 'ok' %}".replace('ok', type);
$.ajax({
method: 'POST',
url: url,
data: {
csrfmiddlewaretoken: '{{ csrf_token }}'
}
});
}
</script>