I'm trying to make a search function in my Django project using AJAX. But the functions in views.py don't seem to work properly. And maybe I have some other mistakes. Could you please tell me what I need to correct?
This is my AJAX file:
$(document).ready( function(){
$('#suggestion').keyup(function(){
var query;
query = $(this).val();
$.get('/friends_plans/suggest_users/', {suggestion: query}, function(data){
$('#user').html(data);
});
});
});
This is part of my template:
<div>
<ul class="nav nav-list">
<li class="nav-header">Find user</li>
<form>
<li><input class="search-query span10" type="text" name="suggestion" value=" " id="suggestion" /></li>
</form>
</ul>
</div>
<div id="user">
</div>
These ara functions from views.py:
def suggest_users(request):
users_list = []
starts_with = ''
if request.method == 'GET':
starts_with = request.GET['suggestion']
users_list = get_users_list(5, starts_with)
return render(request, 'friends_plans/list.html', {'users_list': users_list})
def get_users_list(max_results=0, starts_with=''):
users_list = []
if starts_with:
users_list = Person.objects.filter(username__istartswith=starts_with)
if max_results > 0:
if len(users_list) > 0:
users_list = users_list[:max_results]
return users_list
This is from urls.py:
url(r'^suggest_users/$', views.suggest_users, name='suggest_users')
The istartswith method doesn't work properly with the variable but does with the constant, I can't understand why. And suggest_users function doesn't return users_list to the object with id user ($('#user').html(data)), nothing appears on the page. But maybe there are some other mistakes.
Django's render function renders HTML after parsing it with Jinja. If you want to write a view that acts as an endpoint for an AJAX function, you do not want that view to return render.
Instead you should use return JsonResponse. JsonResponse accepts a dictionary as an argument. And it builds a proper JSON object for you. :) Which will then be picked up by your AJAX's success function.
Here's an example of how to use JsonResponse:
from django.http import JsonResponse
def some_endpoint(request, *args, **kwargs):
data = dict()
data["foo"] = "bar"
data["username"] = User.objects.get(id=request["id"]).username
return JsonResponse(data)
This will cause your view to return a JSON Object, which is what your AJAX function is looking for.
Second suggestion I would make would be to use jQuery's $.ajax() function rather than jQuery's shortcut .get() function. The advantage of this would be learning all the parameters that go along with AJAX calls.
Here's an example of jQuery's $.ajax() function.
$(document).ready( function(){
$('#suggestion').keyup(function(){
var query = $(this).val();
$.ajax(function(){
type: "GET",
url: "/friends_plans/suggest_users/",
data: {suggestion: query},
success: function(data){
console.log("SUCCESS");
console.log(data);
},
failure: function(data){
console.log("FAIL");
console.log(data);
},
});
});
});
Related
I have a very basic view that is supposed to render a page and pass some data to this page, here is how i do it:
def myview(request):
request = mydb.objects.filter(user=request.user)
return render(request,
"main/mytemplate.html",
context={"data":request})
When the page is loaded, the data is passed to the template, so to show that data, i'll only have to go to my html and add this:
{{data}}
But how can i do the same from a view that is not the same view that renders the page?
Let's say that this is a view that i can call with an Ajax request, so when the Ajax request is triggered, the view should send data in the same way and i want to be able to use it in the Django template language.
Here is an example:
def secondview(request):
request = mydb.objects.filter(item='free')
return HttpResponse(request)
This view is called from an Ajax request, it will send a response with the data, but i don't want to get the data in this format or in json format, instead i want to use it from the Django template language, just as i did with the first example. Is there any way to do it? Or can i only pass data to the template in the context?
1) Instead of returning HttpResponse in your secondview do this
def secondview(request):
from django.template.loader import render_to_string
x = 1
return render_to_string('template_name.jinja', locals())
2) If you want to display that response in your html, do this in your html,
<div id="x"> </div>
function someFunc(){
$.ajax({
url: "someurl",
type: 'GET',
success: function (response) {
document.getElementById("x").innerHtml = response
},
error: function (xhr, err) {
console.log(xhr.responseText);
},
cache: false,
contentType: false,
processData: false
});
I hope I've answered all of your questions, if not let me know.
def myview(request):
request = mydb.objects.filter(user=request.user)
context = {"data":request}
return render(request, "main/mytemplate.html", context)
For example, if I have the following code in index.html:
<div id='1'></div>
<div id='2'></div>
<div id='3'></div>
And, I have the following code in Python:
from flask import *
#app.route("/")
def index():
return render_template("index.html")
#app.route('/experts')
def route1():
return render_template("experts.html", data=data)
So, among the three div blocks. When I click on any one of them. I want the program to know which one I click on, and pass the value of id (1,2,3) into the data variable in python so that I can use it on "expert.html".
What are some good ways I can achieve it? Thank you in advanced!
Instead of divs, you can use buttons. That way, ajax can be utilized in the front end to retrieve the id of the button clicked and pass it to the backend:
"index.html":
<html>
<body>
<button id='1'>Button1</button>
<button id='2'>Button2</button>
<button id='3'>Button3</button>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$('button').click(function(event) {
var the_id = event.target.id;
$.ajax({
url: "/get_id",
type: "get",
data: {the_id: the_id},
success: function(response) {
window.location.replace('/experts');
},
error: function(xhr) {
//Do Something to handle error
}
});
});
</script>
</html>
Then, a route to receive the id can be created, the results from the ajax can be stored in flask.session, and a "success" object can be passed back to the ajax in the index.html template. From the jquery in the template, the app can be redirected to /expert:
import flask
app = flask.Flask(__name__)
app.secret_key = 'SOME_SECRET_KEY'
#app.route('/get_id')
def expert():
button_id = flask.request.args.get('the_id')
flask.session['button_id'] = button_id
return flask.jsonify({'success':True})
#app.route('/experts', methods=['GET'])
def experts():
return render_template("experts.html", data=flask.session['button_id'])
I am currently working on a system where the login checking of username and password is checked by a python function. If the login details are correct, it will be redirected to a profile page (which i named dashboard). My problem is that my dahsboard/profile route reutrns a json if it is a POST and has also correct login details. I want this json data to be displayed in the html file. I managed to do it but I have used the variables in my jinja template. Although I have accomplished my goal (display the credentials in the html page), I would want it to be handled by ajax. How do I accomplish that?
Below are the codes I have tried so far (passing the data to the jinja variables)
#app.route('/dashboard', methods=['GET', 'POST'])
def dashboard():
if request.method == 'GET':
#get the username passed along with the redirect
data1= getdatafromdb('getdata1',(request.args.get('uname'),))[0][0]
data2= getdatafromdb('getdata2',(code,))[0]
if 'Error' in str(data2):
return jsonify({'status': 'error', 'message': data2[0][0]})
return render_template('dashboard.html', firstname=data2[1],
middleinitial=data2[2],
lastname=data2[3],
contact=data2[4],
code=data2[5],
affiliation=data2[6],
city=data2[7])
elif request.method == 'POST':
return True
return render_template('dashboard.html')
Currently, it appears that you are running your validation process in your /dashboard route, which is not correct if you wish to redirect your user to that very page once their credentials are validated. Instead, you need to create your separate login method with ajax. First, from the / (home) route, render the template that contains the input boxes with ajax:
home.html:
<html>
<body>
<input type='text' name='username' id='username'>
<div class='username_failed'></div>
<input type='password' name='password' id='password'>
<div class='password_failed'></div>
<button type='button' class='login'>Login</button>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$('.login').click(function() {
var username = $('#username').val();
var password = $('#password').val();
$.ajax({
url: "/login",
type: "get",
data: {username: username, password:password},
success: function(response) {
if (!response.status){
$('.'+response.issue+'_failed').html('<p>'+response.message+'</p>')
}
else{
window.location.replace('/dashboard'); //redirect to dashboard
}
},
error: function(xhr) {
//Do Something to handle error
}
});
});
});
</script>
</html>
Then, the login route will valid the input dynamically from the ajax in home.html. Previously, you need to create a function to validate the username and password. A possibility is to first check if they are empty, and then query the database:
import typing
def check_if_valid(username:str, password:str) -> typing.Dict[str, typing.Any]:
if not username or not password:
return {'status':False, 'issue':'username' if not username else 'password', 'message':f'{[username, password][username]} cannot be empty'}
_username = check_valid_username_from_db(username)
_password = check_valid_password_from_db(username, password)
if not _username:
return {'status':False, 'issue':'username', 'message':'Invalid username'}
if not _password:
return {'status':False, 'issue':'password', 'message':'Invalid username or password'}
return {'status':True}
#app.route('/login')
def login():
username = flask.requests.args.get('username')
password = flask.requests.args.get('password')
_r = check_if_valid(username, password)
if _r.status:
data2= getdatafromdb('getdata2',(code,))[0]
for i, a in enumerate(['firstname', 'middleinitial', 'lastname', 'contact', 'code', 'affiliation', 'city']):
flask.session[a] = data2[i]
flask.session['user_validated'] = _r.status
return flask.jsonify(_r)
Now, all your user data, if the user was successfully validated, will be stored as part of the session. Now, you can create your dashboard page, first with the html for the dashboard:
dashboard.html:
<html>
<body>
<h1>Welcome, {{firstname}}</h1>
<h4>Your data:</h4>
{%for d in data%}
<span>{{d.title}}: {{d.value}}</span>
{%endfor%}
</body>
</html>
Then, create the dashboard route with user validator:
def isloggedin(f):
def wrapper(*args):
if not flask.session['user_validated']:
return '<p>Not logged in</p>'
return f(*args)
return wrapper
#app.route('/dashboard', methods=['GET'])
#isloggedin
def dashboard():
from collections import namedtuple
headers = ['firstname', 'middleinitial', 'lastname', 'contact', 'code', 'affiliation', 'city']
data = namedtuple('data', ['title', 'value'])
return flask.render_template('dashboard.html', firstname = flask.session['firstname'], data = [data(a, flask.session[a]) for a in headers[1:]])
Lastly, link all together with the home route:
#app.route('/', methods=['GET'])
def home():
return flask.render_template('home.html')
Here's my View,
class ObjLike(RedirectView):
def get_redirect_url(self, *args, **kwargs):
id = self.kwargs.get('id')
obj = get_object_or_404(Data, id=id)
user = self.request.user
if user.is_authenticated():
if user in obj.likes.all():
obj.likes.remove(user)
else:
obj.likes.add(user)
So after this view how can I redirect user to the same page?
I used "return redirect(request.META['HTTP_REFERER'])" but it gives an error "name 'request' is not defined"
I can't use the get absolute URL method, i'm using this view at several places.
So, how can I do that?
to like an object with ajax calls do this
first in html we want to make a like button:
<button id="like">Like!</button>
the add a script that contain the ajax:
<script>
$(document).ready(function() {
$("#like").click(function(event){
$.ajax({
type:"POST",
url:"{% url 'like' Obj.id %}",
success: function(data){
confirm("liked")
}
});
return false;
});
});
</script>
the we add the like url to the urlpatterns list:
url(r'like/obj/(?P<pk>[0-9]+)/', views.like, name="like"),
adding the view :
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def like(request, pk)
obj = Obj.objects.get(id=pk)
obj.likes += 1
obj.save()
return HttpResponse("liked")
Note: you can customize the like view to check if user liked already
I'm using ajax in django first times .. I read some tutorials on the net and I'm trying to make a simple form which posts some information via ajax.
Here is my html form
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
function send_request()
{
$.ajax({
type:"POST",
url:"/ajaxredirect/",
});
}
</script>
<button type="button" onclick="send_request();">change content</button>
and it is my view
def Ajaxquery(request):
if request.is_ajax():
return HttpResponse("ok")
else:
return HttpResponse("error")
it does nothing when i am click on change content button in browser.
Any suggestions would be apperciated
Here is basic request/response setup I have made use of. I got the JSONResponse and AjaxResponse mixins from the Django Braces Module. I also made sure to include the following Django CSRF fix to prevent my AJAX request from being treated as a cross site request forgery.
JQuery:
<script type="text/javascript">
function send_request() {
$.ajax({
type: 'POST',
url: '/ajaxredirect/',
data: $('#your_form').serialize(),
crossDomain: false,
success: function(ctx) { console.log(ctx); },
});
}
</script>
Views.py
from django.views.generic import View
from braces.views import JSONResponseMixin, AjaxResponseMixin
class AjaxResponseView(JSONResponseMixin, AjaxResponseMixin, View):
def post_ajax(self, request, *args, **kwargs):
data = request.POST.items() # form data
ctx = {'hi': 'hello'}
return self.render_json_response(ctx)