Pyramid and json. Please demystify - python

I have a Pyramid web app that GETs data from the user, fetches some data from the backend based on the values posted to the view, and then render the fetched results.
This is the workflow:
user->enter name->fetch age,other_details based on 'name' from DB->return a neat table with fetched values
I use ajax to do the first part. i.e., posting values from webpage to view.
Here's the relevant code to POST
<script>
var studentname=$(#stuname).val();
$.ajax({
type: "POST",
url: "/trypass",
data: {name:studentname},
cache: false,
success: function(result) {
alert("Successfully inserted!");
}
});
</script>
<input type="text" id="stuname"></input>
<div id="tablegoeshere"><!--I need fetched results here in a table.--></div>
My views that handle the posted request(Just a semifunctional try):
#view_config(route_name='try', renderer='/trypass.pt')
#view_config(route_name='tryjson',renderer='json')
def upload_view(request):
student_name = request.POST.get('name')
age=DBSession.query(Student).filter(name==student_name).first()
return {"age":age.id} #I dont need this. I need the whole tuple returned but dont know how.
You can see I have stacked a json renderer below my view decorator, but in a different route. I followed it from the documentation but This does nothing than return the values in a new route which is of no use to me.
I researched a lot but not convinced why would I want to use a json renderer to render the returned tuples; and most importantly, HOW.
What I want to know is, how/where do I pass the json values and return it within the same template(trypass.pt)? I have a dedicated to fill in with the parsed json results. But I am absolutely clueless on how to do this. Please guide me. Thank you very much in advance.
MORE EDITS:-
After more research I found out that the getjson() method in javascript gets a json input and we can parse it. But my question still remains. How is the passing done? And am I AJAXing the right way? I also saw there are callbacks in AJAX which probably fetches my response and renders it to my html page. Point me in the right direction please.

Here is a slightly different way of doing it. This way only returns the html back to your ajax without any additional json data like the other answer.
student.pt
<table >
<tr>
<td>Student Age</td>
</tr>
<tr>
<td>${age}</td>
</tr>
</table>
test.js
$.ajax({
type: "POST",
url: "tryjson",
data: {name:studentname},
cache: false,
success: function(html) {
alert("Successfully return our ajax data and html!");
;now insert my html somewhere
}
});
views.py
#view_config(name='tryjson', renderer='templates/student.pt')
def server_view1(request):
student_name = request.POST.get('name')
age=DBSession.query(Student).filter(name==student_name).first()
return {'age':age.id}

Below is an example of "what I think you are asking". I tried to make it very basic so you can see what is going on. Hopefully it will get you where you need to be.
Also, once the ajax request returns with the rendered html (result['html']) you will need to insert it into the DOM.
Of course this is just one way of doing this using AJAX.
You need to study up on chameleon templating and fully understand that so you can create your table in 'student.pt'
student.pt
<table >
<tr>
<td>Student Age</td>
</tr>
<tr>
<td>${age}</td>
</tr>
</table>
test.js
$.ajax({
type: "POST",
url: "tryjson",
data: {name:studentname},
cache: false,
success: function(result) {
alert("Successfully return our ajax data and html!");
html = result['html'] #do want you want with the html here (rendered with "student_table.pt")
age = result['age'] #return this json data for example
}
});
views.py
from pyramid.renderers import render
#view_config(name='tryjson', renderer='json')
def server_view1(request):
student_name = request.POST.get('name')
age=DBSession.query(Student).filter(name==student_name).first()
template_vars = dict()
template_vars['age'] = age.id #the template will need this data so it can fill in.
result = dict()
result['html'] = render('templates/student.pt', template_vars, request)
result['age'] = age.id #Return this data for example
return result

Related

How to load Django ListView via Ajax

Basically code works as I expected, but my ListView is not refreshing. Everything works fine, but template does not load itself, I must push reload button (all data are loaded correctly then).
I done simple form/input for testing and there is no problem with views. My project requires calendar widget for picking months, and simplest way to do this I found on the internet was Ajax approach.
Ajax function:
$(document).ready(function () {
$(function () {
$("#datetimepicker1").datetimepicker({
viewMode: 'months',
format: 'MM/YYYY',
}).on('dp.change', function (e) {
var url = "/booking/update_months/{{hotel_id}}";
$.ajax({
type: 'GET',
url: url,
dataType: 'json',
data: {
month: e.date.month(),
},
success: function (data) {
},
error: function (data) {
}
});
})
});
});
Url "/booking/update_months/{{hotel_id}}" refers to first View function I'm using for this functionality:
#csrf_exempt
def update_months(request, hotel_id):
if request.GET.get('month'):
month = request.GET.get('month')
request.session['month'] = int(month) + 1
return HttpResponseRedirect(reverse('booking:hotel_statistics', args=(hotel_id,)))
else:
return render_to_response(request, 'booking/hotel_statistics.html')
Then in HotelStatistics ListView I'm doing some stuff in get_context_data function, nothing special here. Just by some "prints" I've tested that the code is being executed until the end of the class.
class HotelStatistics(ListView):
model = Reservation
context_object_name = 'reservations'
template_name = 'booking/hotel_statistics.html'
def get_context_data(self, **kwargs):
.
.
.
return context
I'm pretty sure that I'm missing something with Ajax functionality, It's my first approach to this language. Thanks in advance for your help.
Why are you using AJAX here? Unless I am missing something, you should just have the date picker inside an HTTP GET form that is submitted.
template.html
<!-- The action attribute hardcoded URL value should be replaced with a Django url templatetag. This will allow the url to be resolved based on the router configuration. i.e. {% url "booking:update_months" hotel_id %} -->
<form action="/booking/update_months/{{ hotel_id }}" method="GET">
<input id="date" name="date">
<button type="submit">Update</button>
</form>
<script>
$(document).ready(function() {
$("#date").datetimepicker({
viewMode: 'months',
format: 'yyyy-mm-dd',
});
});
</script>
view.py
#csrf_exempt
def update_months(request, hotel_id):
date = request.GET.get("date")
if date:
request.session["month"] = datetime.strptime(date, "%Y-%m-%d").month
return redirect("booking:hotel_statistics", False, hotel_id)
return render(request, "booking/hotel_statistics.html")
The code above submits an HTTP GET form, resulting in a server side 301 and therefore a "refresh" of your statistics page with the update session data.
Notice, we are sending up the full date information. I am not sure if you are doing this separately, but if you are allowing users to update each date part independent, you could now bring that together into a single update_date function.

Django Search Bar Implementation

I'm trying to implement a search bar to query my database and show only the matches. When I hit submit it just gives me back 'SEARCH', which is what I set as the default instead of printing an error.
ajax.py
...
def chunkSearcher(request):
test = request.GET.get('search_box', "SEARCH")
print(test)
....
Searcher.html
<form type="get" action="." style="margin: 0">
<input id="search_box" type="text" name="search_box" value="Search..." >
<button id="search_submit" type="submit" >Submit</button>
urls.py
url(r'^ajax/chunk/Searcher/$',
ajax.chunkSearcher, name='chunkSearcher')
views.py (It actually works here for some reason but it won't recognize the same two lines of code in my ajax code
def searcher(request):
# test = request.GET.get('search_box', "SEARCH")
# print(test)
this_main = Searcher(
request = request,
num_elements = Candidate.objects.all().count(),
size = 'col-xs-12',
title = 'Search',
modelname = 'Searcher',
listing_fields = [
{'readable_name': 'Name', 'model_attribute': 'full_name()', 'subtext_model': 'email', 'color': 'False'},
{'readable_name': 'Status', 'model_attribute': 'get_status_display()', 'color': 'True'},
{'readable_name': 'Automated Status', 'model_attribute': 'get_auto_status()', 'color': 'True'},
{'readable_name': 'Submitter', 'model_attribute': 'submitter', 'color': 'True'},
],
listing_actions = [
{'tooltip': 'Search', 'color': 'success', 'icon': 'plus', 'permission': 'prog_port.add_candidate', 'modal': 'candidateform', 'controller': 'addCandidate'},
],
)
context = {
'nav' : Nav(request),
'main' : this_main,
'fb' : TestFeedback()
}
return render(request, 'prog_port/base.html', context)
widgets.py
class Searcher:
def __init__(self, request,
num_elements,
size = 'col-xs-12',
modelname = None,
title = None,
listing_fields = None,
listing_actions = None):#!!
self.template = 'prog_port/widgets/Searcher.html'
self.size = size
self.modelname = modelname
self.num_elements = num_elements
self.num_pages = int(math.ceil( num_elements / 25.0))
self.title = title
self.listing_fields = [x['readable_name'] for x in listing_fields]
self.listing_actions = listing_actions
for action in self.listing_actions:
action['restricted'] = False
if 'permission' in action:
if not request.user.has_perm(action['permission']):
action['restricted'] = True
Getting this working without Ajax would be a bit quicker to start. When the action attribute of your form is pointed towards the URL of the current page (rather than towards the URL of your ajax view), the GET request is sent to the view that corresponds to that page's URL - your searcher view in your case. That's why you were able to get the expected values to print when you had those two lines in that view.
Importantly, since the searcher view is the one rendering your page, having access to your search_box value in that view lets you filter or otherwise manipulate the queryset being passed into the view's context and ultimately display only the restricted/filtered items you want shown.
A separate Ajax view doesn't have access to all of that stuff right off of the bat. To dynamically update your search results with a separate Ajax view, that view will need to respond to your request with all of the information necessary to re-render the page appropriately. Practically speaking, that usually means one of two things:
Your search results are displayed within a div or other defined content area, and your Ajax view returns the HTML necessary to populate that content area with the appropriate stuff, or
Your initial view renders its template based on some serialized JSON, and your Ajax view provides updated information in that format which is then used to re-render the template.
This is a good starting point for getting the hang of ajax with django. Notice in the example code given how the view responds to the ajax call with some data (a HTTPResponse or a rendered template), and how that data is then used in the success/failure functions.
If your ajax view returned the HTML necessary to render search results, you could use your success function to update the search results div (or table or whatever) on your page with that new HTML. For example:
views.py
def index(request):
return render(request, "index.html")
def ajax_update(request):
return HttpResponse("<h1>Updated Header</h1>")
index.html
...
<div id="update_this_header">
<h1>Old header</h1>
</div>
<button id='updater'>
...
<script>
$("#updater").click(function() {
$.ajax({
url: #url to ajax_update view
success : function(data) {
$("#update_this_header").html(data)
},
failure : function(data) {
...
}
});
});
</script>
Now clicking the updater button should update the contents of the update_this_header div with the HTML returned in the HttpResponse from our ajax_update view (I admit I didn't test this, forgive me if there's a typo). Updating your search results works the same way; you just need to do more processing in your ajax view to respond with the correct HTML.
I hope this helps make things somewhat clearer; please let me know if I can (try to) explain anything more fully. The important takeaway here is that an ajax view will provide you with Some Data. It's up to you to make sure your template can take that data and properly display it.

Render_template second time after page is already loaded

I am trying to query a database through my website and dynamically add columns with the results using Jinja templates. I am using flask and on my views function. I am rendering the values like this
return render_template('query.html',my_list=my_list )
The thing is that when I load the page the user hasn't queried the database yet, so my_list is empty. The user queries the database by pressing a button on the html page and making an ajax request through jquery. My question now is if its possible to return my_list using jinja templates even after the page is already loaded, meaning I have to return render_template a second time (after submit button) to get the values for my_list.
p.s. I prefer not to use json parsing.
Here is some sample code. I query the database with the values of intranetID of column SubmitterID and platform of column Platforms to return the whole entry to the database with the values of the rest of the columns as well.
#app.route('/querydbvalues',methods=['POST', 'GET'])
def querydbvalues():
if request.method == 'POST' or request.method == 'GET':
results = models.mydatabase.query.filter_by(SubmitterID=qIntranetID,Platforms=qPlatform).all()
my_list = [i.user for i in results]
return render_template('query.html',my_list=my_list )
and on my html page
{% for n in my_list %}
<li>{{n}}</li>
{% endfor %}
on the Javascript file when you press the button i make the ajax request like this
$("#SearchDatabase").click(function(){
var tmp = document.getElementById("qIntranetID").value;
var tmp2 = document.getElementById("qPlatform").value;
jQuery.ajax({
dataType: "json",
url:"/querydbvalues", //tell the script where to send requests
data:{text:tmp,text2:tmp2},
type:'GET',
contentType: 'application/json',
success: function(results){
//do something
}
});
});
The Ajax call is a completely separate request. You can do what you want in that request, including render templates.

POSTing to a URL in a controller does not trigger render_template in Flask

I suppose this should be very simple but I think I'm missing something.
Simple description: I have a page that lists specific words. Each word has an ID. I'm passing this ID to a function, which then posts it to a URL. What I'm attempting to do is to pass the ID, query it in the backend, and get transferred to the edit page with the query result.
Here's my code:
AngularJS function
$scope.editDefinition = function (searchItem) {
var param = { id: searchItem.id };
var url = "/table-based";
$http.post(url, param).success(function (data) {
console.log(data);
});
};
Flask/Python route function
#app.route("/table-based", methods=["GET", "POST"])
def edit_definition():
if request.method == "POST":
j = json.loads(request.data)
uid = j["id"]
cdef = db.getDefinitionById(uid)
return render_template("edit.html", definition=cdef)
return render_template("edit.html")
HTML
<div ng-init="init('{{ definition |tojson|safe }}')" ng-controller="editCtrl">
<ng-include src="'/_partial_edit_form'"></ng-include>
</div>
EditCtrl has the relevant $scope.init function to receive definition. Basically, it returns a response that contains the HTML of the edit.html template, but it does not redirect to the URL.
What gives?
You haven't implemented anything that will cause the browser to redirect to your new template page. In the data returned you should just see the html generated by render_template.
You have two options that I can see. The first would be to store the cdef in flask's g or session object and then reload the page with angular $route.reload() or $window.location.reload() and have flask pick up the cdef from g or session on GET.
The second option would be to refactor your code so that you have angular doing the page rendering, then you just update your definition object on POST. In this case, flask would return json.dumps(cdef) instead of the render template and you would use the angular templating to render it.
The second option is much better, and is pretty much exactly what Angular is designed to do. When I create Angular-Flask apps, I very rarely use render_template, instead I have Angular doing all the rendering after retrieving the data as JSON from a flask-based API.

How to make view that add product working correct in django/python

I have view in django that add product to the cart( i use django-carton 1.2). That my code:
def add(request,product_id):
cart = Cart(request.session)
product = Product.objects.get(pk=product_id)
if product.quantity >=1:
cart.add(product, price=product.price)
product.quantity-=1
product.save()
return render (request,'shopping/show-cart.html')
else:
return HttpResponse("No product ")
After that view has worked a certain product add to the cart, cart with all products is showing. The problem: when in browser I make function "reload current page" it increase quantity of products in my cart. At the same my remove product view is working, but it only try delete the product when page reload from the function of browser
You should only do actions that modify data - like add and delete - on a POST request, not a GET. You need to create a form in your page, even if it just contains a single button, and check if request.method == 'POST' in the view before doing anything.
Either include a form tag within your html that POSTS information or you can use an Ajax request call.
<script type="text/javascript">
$(document).ready(function(){
$('#add_cart_button').click(function(e)
{
$.ajax({
url: 'xxxxxxx',
type: 'POST',
dataType: 'html',
data: {
'somevariable' : 'somevalue'
},
async: false,
success: function(data){
$('#target').html(data);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("Status: " + textStatus); alert("Error: " + errorThrown);
}
});
When you make the Ajax call, it sends whatever you have in your data dictionary to the specified url. From there, Django implements whatever function you want to process that data on the backend and returns the information back. The success function basically gets that information back and does whatever you want with it. In your case, you probably just want to re-render that chunk of HTML that displays the items in your cart.The target tag within the success function is where that chunk of HTML will be rendered, so include a target div tag in your html where you want it to be displayed.
You can access the data from the ajax request in your view by doing request.POST.get('key',somedefaultvalue) (if you want to have a default value if it can't find the dictionary or if it's empty) or just request.POST[key].

Categories

Resources