using a part of Django URLs in views - django

I need to send a JavaScript variable to the view and based on that variable,a new page opens.I've send the variable using ajax and it works well but when I call the URL to open the page based on sent variable,the variable gets None value.
Here is my template :
<a onclick="click(this.id)" id="author[i].name" href="{% url 'app:export-pdf' %}" >export pdf</a>
author[i].name is the JavaScript variable that I send it to view in this way :
function click(name){
$.ajax({
type: 'POST',
url: '{% url 'app:export-pdf' %}',
data: {'name': name },
});
};
This is part of my view if needed :
#csrf_exempt
def battery_render_pdf_view(request):
name = request.POST.get('name')
print(name)
data = MyModel.objects.filter(name=name)
When I run the code, I'll get for example :
Mike
None
The view get None as name but it must get Mike for filtering.
What is wrong with my code?(I think it happens because I call the Url 2 times but I didn't find out how to correct it.)
Thank you all.

Finally I have found a simple way like below :
template :
export pdf
url :
path('pdf/<int:authorid>/', pdf_view, name='pdf-data')
and in view , you can access authorid by using kwargs:
def pdf_view(request,**kwargs):
author = kwargs.get('authorid',None)
data = MyModel.objects.filter(name=author)

Related

Multiple Django subforms displayed with ajax in a main form but data not registered when subforms are submited (without error)

EDIT #1
well maybe because it is not clear in my head
and your are right saying Django forms are not intented to be used with ajax that why I wonder if there is way way doing what I want using Django forms without losing power of Django forms validation
I will try to clear my demand
considering this UI below
When user reach this "patient page" = main form (image 1), he can select "Inclusion form = subform (INCL-001 for instance) in the menu
I want the corresponding form to be displayed without refresh the page ; that why I have used ajax to display the corresponding form
If the corresponding form does not exist, it is a CREATION and a blank "Inclusion form" is displayed : user can enter data and save
If the corresponding form already exist, it is a UPDATE and a prefilled "Inclusion form" is displayed : user can update data and save or delete the form
what would be an elegant way of doing that?
I have a main form (patient.html) and I want to display different subforms (inclusion.html for instance) with ajax in this form.
I manage to display a subform when user click on a button in the main form
But, data are not stored when submitted and it is quite normal as no view is linked to this subform
I have read about this in different post but I miss the concept how to...
I thinks it is a common task with web so probably Django as an easy way to do it?
thanks for advices
urls.py
app_name='ecrf'
urlpatterns = [
path('', views.index, name='index'),
path('patient/<pk>', views.patient, name='patient'),
path('sub_form', views.sub_form, name='sub_form'),
]
views.py
def patient(request,pk):
patient = {"id":1,"num":'A-001',"dat":'Mon 11, novembre 2020',"arm":1,"doc":'Slater'}
return render(request, 'ecrf/patient.html', {'patient':patient})
def sub_form(request):
if request.is_ajax():
return JsonResponse(
{
'html_inclusion': render_to_string(
'ecrf/inclusion.html',
{
'form': InclusionForm,
'language': request.session.get('language')
},
request=request
),
},
status=200
)
js
$(document).ready(function () {
...
$("#add").on("click",function (event) {
var csrftoken = getCookie('csrftoken');
$.ajax({
type: "POST",
url: '/ecrf/sub_form',
data: {
csrfmiddlewaretoken: csrftoken,
},
dataType: 'html',
success: function (data) {
$("#sub_form").children().remove();
obj = JSON.parse(data);
$("#sub_form").append(obj.html_inclusion);
},
error: function (data) {
console.log('error');
}
});
});
$("body")
.on("click", '#inclusion', function (event) {
console.log('inclusion click')
})
});

Show loading gif until the django view performs the data processing and renders the template with this data

I have a django project where the page has multiple nav links representing different agents. On clicking any nav link, the urls.py redirects to nav specific view and the view needs to perform some processing to get the data needed to render the template. However as this is syncrhonous rendering it takes a long while to load data (in the order of 15-20s).
Below is my urls.py:
from django.urls import path
from . import views
app_name = 'agent'
urlpatterns = [
path('agent1/', views.agent1, name='agent1'),
path('agent2/', views.agent2, name='agent2'),
path('agent3/', views.agent3, name='agent3'),
path('agent4/', views.agent4, name='agent4'),
]
My views method looks as below:
def agent1(request):
agent_data = Agent1.objects.all()
agent_details = get_agent_details(agent_data)
return render(request, 'manager/data.html', {'agent_data': agent_data, 'agent_details': agent_details})
I am using the {{ agent_data.name }}, {{ agent_data.code }}, {{ agent_data.qty }} and {{ agent_data.price }} along with data from agent_details dictionary in my html to populate a table's rows. How should I change my view method, so that it loads the data via AJAX (javascript) in order to show a loading gif in the meantime and also provide me the data so that I can populate the table. Could someone help me with the Ajax code and the steps as I am new to this technology and not finding any help going through the online tutorials.
So for this to work with ajax, you'll need some javascript in manager/data.html which knows the url to fetch data from.
As an example, I've got an ajax setup which checks a given email address isn't already in use;
(function($) {
$(document).ready(function() {
var validateEmailURL = $section_user_signup.data('ajax-email-url');
function validateEmailUnique() {
var valid = true;
clearError($email);
// Fetch unique status of the provided email
$.ajax({
async: false,
url: validateEmailURL,
method: 'POST',
type: 'POST',
dataType: 'json',
data: {
'email': $email.val(),
'csrftoken': $form.find('input[name="csrfmiddlewaretoken"]').val()
},
success: function (response) {
valid = true;
},
error: function (response) {
setError($email, response["responseJSON"]["error"]);
valid = false;
}
});
return valid;
}
});
})(window.jQuery);
This javascript uses the data attribute of a div for the URL to check;
<div data-ajax-email-url="{% url 'account_ajax_validate_email' %}">
The view which the ajax call goes to looks like this;
def ajax_check_email_unique(request, *args, **kwargs):
"""
Return an JsonResponse to identify if an email is unique.
"""
if not request.is_ajax():
return HttpResponseBadRequest()
if request.is_ajax and request.method == "POST":
email = request.POST.get('email')
if email_address_exists(email):
return JsonResponse(
{
"error":
"Email address already exists. Click "
f"here "
"to login"
},
status=400
)
return JsonResponse(
{"email": email},
status=200
)
# some error occurred
return JsonResponse({"error": ""}, status=400)
The important thing for any view which will be used by javascript is that you return a JsonResponse.
So if I was you, I'd setup a new view for ajax, and that makes your existing one really simple;
def agent1_ajax(request):
agent_data = Agent1.objects.all()
agent_details = get_agent_details(agent_data)
return JsonResponse({
"agent_data": agent_data, "agent_details": agent_details
}, status=200)
def agent1(request):
return render(request, 'manager/data.html', {})
And as far as a loading gif goes, you'd need an element that contains the gif and then you can bind to the ajax event to show/hide;
$(document).ajaxStart(function() {
$("#loading").show();
});
$(document).ajaxStop(function() {
$("#loading").hide();
});

How to properly return Json reponse to template for ajax/jquery?

Here I am trying to search with the help of ajax and jquery with my django view. When I try to search like this by returning the JsonReponse instead of html_template it doesn't return data below the corresponding id in html
But When I return html from django view and create the new html for this searching results and including this template in the original template works perfectly but I find this a longer process So I tried to return json reponse from view and use that json objects in the template like this but it is not working.
How can I solve this ? I think I need to work on the ajax part .
def search_users(request):
q = request.GET.get('q')
if q:
users = get_user_model().objects.filter(is_active=True).filter(profile__full_name__icontains=q)
data = {'users': users}
else:
users = get_user_model().objects.filter(is_active=True)
data = {'users':users}
return JsonResponse(data)
ajax
$(function() {
$('#search_users').keyup(function() {
$.ajax({
type: "GET",
url: "{% url 'dashboard:search_users' %}",
data: {
'q' : $('#search_users').val(),
},
success: searchSuccess,
dataType: 'json'
});
});
});
function searchSuccess(data, textStatus, jqXHR)
{
$('#search_users_results').json(data) #doing html instead of json works after returning html from django view
}
In the terminal
TypeError: Object of type QuerySet is not JSON serializable
[15/Mar/2020 14:02:53] "GET /admin/dashboard/search/users/?q=tyj HTTP/1.1" 500 22660
You have to extract values out of the query before sending it across instead of sending the model instance as it can't be serialized, is what the exception is saying.
So, you can just append .values() in the end and put in the list as below -
data = {'users': list(users.values())}
You may refer to it here.

How to update database after clicking on html element?

In my flask application, I have a points column in the database, which is initialized to 0 on user registration. Now, I want to be able to update the points in database after clicking an html element.
class User(UserMixin, db.Model):
points = db.Column(db.Integer)
#bp.route('/activity1')
#login_required
def activity1():
return render_template('activity1.html', title='Activity 1')
Activity1.html has the point-generating html element
#bp.route('/register', methods=['GET', 'POST'])
def register():
...
form = RegistrationForm()
if form.validate_on_submit():
user.points = 0
db.session.add(user)
db.session.commit()
...
<a data-toggle="collapse" class="w3-large" href="#tip4" onclick="getPoints()">...</a>
<script>
function getPoints(){
points += 20; #How do i access the database.points in this case?
}
</script>
I'm not sure if I understand the code correctly, but are you asking how to update the number of points from activity1.html in the last code snippet? That won't work, the HTML is rendered on the server and once presented to the browser, there's no link between the two.
If you need to pass some data to the template while rendering it, you have to pass it in the render_template call, e.g.
render_template('activity1.html', title='Activity 1', user=user)
Then you can access it in the template like this:
<script>
function getPoints(){
points = {{ user.points|int }} + 20;
// post to backend to update data in database (using jQuery)
$.ajax({
type: 'POST',
contentType: 'application/json',
data: {
id: "{{ user.id }}",
points: points
},
dataType: 'json',
url: 'http://xxx/update_points',
success: function (e) {
// successful call
},
error: function(error) {
// an error occured
}
});
}
</script>
If you then want to update the user points in the database, you'll have to make a request to the server, which will take care of this. On the server side in Flask, define a view to handle this request:
#bp.route('/update_points', methods=['POST'])
def update_points():
data = request.get_json()
# don't know exactly what's the model and how to get the 'user' instance
user = User.get_user_by_id(data['id'])
user.points = data['points']
db.session.add(user)
db.session.commit()
Take it as an example code, I didn't test it and ommited quite a lot of details (e.g. how to get user instance in update_points etc.) Also, I might have missed what you are really asking for.

django - passing data from server to js function via class based view

Django 1.6.3 +
Need to pass data to a class based view. where I want my jquery function to handle the data passed from the server. How would that be done ?
1.
Create a javascript/jquery function in your view which makes an $.ajax({options}); call to the url you want to send & receive data from (See #4 for an example).
2.
Have your views.py file import the json & HttpResponse module.
import json
from django.http import HttpResponse
3.
Add a function in your views.py to handle the request
def ExampleHandler(request):
Within this function, you can access parameters like request.POST['paramname'] or request.GET['paramname']. See https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.GET for more information.
To return data to the ajax call, store your data in a dictionary like this:
result = {
'success': True,
'foo': bar,
'more': data
}
and return the json like this:
return HttpResponse(json.dumps(result), content_type="application/json")
4.
Your original javascript function will look similar to this now:
function exampleRequest() {
$.ajax({
type: 'POST',
url: '/url-mapped-to-your-view',
data: {data: 'some-data-to-send-to-views'}, // May need to add a CSRF Token as post data (eg: csrfmiddlewaretoken: "{{ csrf_token }}")
error: function() {
alert('There was an issue getting the data...');
},
success: function(data) {
// Accessing data passed back from request, handle it how you wish.
alert(data.foo);
alert(data.more);
}
)};
}
5.
Ensure the url you make the ajax call to is correctly mapped in urls.py
You can probably pass data via args or kwargs
in views.py
class YourView(TemplateView):
def get_context_data(self, **kwargs):
context = super(YourView, self).get_context_data(**kwargs)
context['yourdata'] = self.kwargs['data']
return context
in urls.py
url(r'(?P<data>\w+)$', YourView.as_view()),