Creating forms with Pyramid web framework and Jinja2 templates - python

I am a newbie trying to build a simple web framework to support a SQLAlchemy DB. I am using Pyramid and Jinja2 templates. I am planning on using server-side rendering of static HTML instead of JSON. I have gone over the Pyramid tutorials repeatedly, spent days on JINJA's website, looked up questions here on good ol' Stack, but haven't been able to gather a clear understanding of how to achieve the following:
My issue at the moment is how to create a template that adds created objects using the get() method. I am having a hard time figuring out how to add these objects using the JINJA2 template syntax, e.g. {{ name }} in a form.
Here is a snippet example of the route, view and template:
CODE:
__init__.py
Each entity that makes up an assessment in the db, e.g. user, elements, video, categories, etc. have routes like this:
config.add_route('assessments', '/assessments')
config.add_route('assessment', '/assessments/{id}')
views.py
The design for the RESTful API is the same for EVERY entity mentioned above:
#view_defaults(route_name='assessments', renderer='templates/editor_view.jinja2') # editor view for creating assessment
class AssessmentsViews(object):
API = api
def __init__(self, request):
self.request = request
#view_config(request_method='GET')
def get(self):
assessments = self.API.retrieve_assessments()
return {}
#view_config(request_method='POST')
def post_assessment(self):
name = self.request.params['name']
text = self.request.params['text']
user = self.request.params['username']
video = self.request.params['videoname']
catogories = self.request.params['category_names']
assessment = self.API.create_assessment(name, text, user, video, categories)
return HTTPAccepted(location = request.route_url('assessments/{id}'))
#view_defaults(route_name='assessment', renderer='templates/user_view.jinja2') #user_view for the user to take the assessment
class AssessmentViews(object):
API = api
def __init__(self, request):
self.request = request
def get_assessment(self):
assessment_id = int(self.request.matchdict['id'])
assessment = self.API.retrieve_assessment(assessment_id)
return {'name': assessment.name, 'text': assessment.text, 'user': assessment.user, 'video':assessment.video, 'categories': assessment.categories}
#view_config(request_method='GET')
def get(self):
assessment = self.get_assessment()
if assessment is None:
raise HTTPNotFound()
return HTTPFound(location=request.route_url('/assessments/{id}'))
#view_config(request_method='PUT')
#code
#view_config(request_method='DELETE')
#code
template
A template meant for a user to enter their ratings (take an assessment), but how does one add the categories to the form? Is it by a redirect? or by JINJA code?
# add {{categories}} from Assessment where in this form?
<form method='POST' action ='/category_ratings'>
<dl>
<dt><label for = 'category_rating_int'> {{category}} </label></dt>
<dd>{{ forms.input('category_rating_int', type=category_rating_int, '') }}</dd>
<dt><label for = 'category_rating_int'> Rating </label></dt>
<dd>{{ forms.input('category_rating_int', type=category_rating_int) }}</dd>
<dt><label for = 'category_rating_int'> Rating </label></dt>
<dd>{{ forms.input('category_rating_int', type=category_rating_int) }}</dd>
<dt><label for = 'category_rating_int'> Rating </label></dt>
<dd>{{ forms.input('category_rating_int', type=category_rating_int) }}</dd>
<dd><input type="submit" name="submit" value="Submit" /></dd>
</dl>
</form>

Related

How to implement Bing News Search API via MS Cognitive Search into a website

I'm a bit clueless when it comes to API's, but I believe this is the code I need It's a python program that calls the Bing News Search API through Microsoft Cognitive Services, which is the new way to call the API. My question is how do I implement/embed the results of this into my actual website (consisting of an html, css, js, and server.js file)? Basically, which parts need to go where? I greatly appreciate any help you can give me. Thanks!
import requests, requests.utils
from py_ms_cognitive_search import PyMsCognitiveSearch
##
##
## News Search
##
##
class PyMsCognitiveNewsException(Exception):
pass
class PyMsCognitiveNewsSearch(PyMsCognitiveSearch):
SEARCH_NEWS_BASE = 'https://api.cognitive.microsoft.com/bing/v5.0/news/search'
def __init__(self, api_key, query, safe=False, custom_params=''):
query_url = self.SEARCH_NEWS_BASE + custom_params
PyMsCognitiveSearch.__init__(self, api_key, query, query_url, safe=safe)
def _search(self, limit, format):
'''
Returns a list of result objects, with the url for the next page MsCognitive search url.
'''
payload = {
'q' : self.query,
'count' : '50', #currently 50 is max per search.
'offset': self.current_offset,
#'mkt' : 'en-us', #optional
#'safesearch' : 'Moderate', #optional
}
headers = { 'Ocp-Apim-Subscription-Key' : self.api_key }
response = requests.get(self.QUERY_URL, params=payload, headers=headers)
json_results = self.get_json_results(response)
packaged_results = [NewsResult(single_result_json) for single_result_json in json_results["value"]]
self.current_offset += min(50, limit, len(packaged_results))
return packaged_results
class NewsResult(object):
'''
The class represents a SINGLE news result.
Each result will come with the following:
the variable json will contain the full json object of the result.
category: category of the news
name: name of the article (title)
url: the url used to display.
image_url: url of the thumbnail
date_published: the date the article was published
description: description for the result
Not included: about, provider, mentions
'''
def __init__(self, result):
self.json = result
self.category = result.get('category')
#self.about = result['about']
self.name = result.get('name')
self.url = result.get('url')
try:
self.image_url = result['image']['thumbnail']['contentUrl']
except KeyError as kE:
self.image_url = None
self.date_published = result.get('datePublished')
self.description = result.get('description')
The _search function returns a results list (packaged_results). If you wanted to show those in a website, you'd have to load/render the html file with a Python script. This is where frameworks like Django come in handy, where a view and a template are used.
A basic view for a search page in Django (goes into views.py module of the application):
def search(request):
result_list = []
if request.method=='POST':
query = request.POST['query'].strip()
if query:
result_list = _search(query)
return render(request, 'web/search.html', {'result_list': result_list})
And in the body of the search.html template (using the Django template language, and the question's author class for each News result ):
<div>
{% if result_list %}
<h3>Results</h3>
<!-- Display search results -->
<div>
{% for result in result_list %}
<div>
<h4>
{{ result.category }}</a>
</h4>
<p>{{ result.about }}</p>
</div>
{% endfor %}
</div>
{% endif %}
</div>
If you wish to use Django for this particular problem, here's the documentation on writing views and another one for the Django templates, which are all HTML files.
https://docs.djangoproject.com/en/1.10/topics/http/views/
https://docs.djangoproject.com/en/1.10/topics/templates/

How can Ajax work with a dynamic Django dropdown list?

I'm making this little web app that takes 2 addresses, calculates the distance using google maps, and calculates the gas cost based on the vehicles mpg rating. Everything is complete except for this last part that I believe would work best with AJAX.
I have 3 lists (year, make, model), and I need the list of car models to be restricted based on the year and make of the car. After selecting, I have a button that once clicked, will verify if it is a valid vehicle in the database and pull the vehicle's mpg rating to do some basic math on it.
The problem is I don't really know how to approach this problem. I've searched some inquiries the past few hours and I'm getting a lot of things related to model forms and Django choice fields which I don't want to get into if I don't have to. My idea is to just change the innerText/value, and check it against my django database.
I also came across this answer from SO:
How do I integrate Ajax with Django applications?
and am a bit confused by it. If I understand correctly, the AJAX GET request will extract data in javascript objects the same as if I visited that url as a user. Does this mean I could just create another html template and post every vehicle in the database onto that page from which I can extract info and create my dynamic lists from?
Looking for the most straightforward way to dynamically generate my lists with ajax and verify the year, make, and model with my database which will then return the car's mpg.
models.py:
class Car(models.Model):
year = models.IntegerField(default=0)
make = models.CharField(max_length=60)
model = models.CharField(max_length=60)
mpg = models.IntegerField(default=0)
def __str__(self):
return ("{0} {1} {2}".format(self.year, self.make, self.model))
views.py: (right now, it just lists every vehicle and has no way to verify the vehicle on the spot)
def index(request):
context_dic = {}
car_list = Car.objects.order_by('make')
car_list_model = Car.objects.order_by('model')
context_dic['car_list'] = car_list
context_dic['years'] = []
context_dic['makes'] = []
context_dic['models'] = []
for year in range(1995, 2016):
context_dic['years'].append(year)
for make in car_list:
if make.make not in context_dic['makes']:
context_dic['makes'].append(make.make)
else:
continue
for model in car_list_model:
if model.model not in context_dic['models']:
context_dic['models'].append(model.model)
else:
continue
return render(request, 'ConverterApp/index.html', context_dic)
html: (x3 for the make and model)
<div id="specifics">
<div class="dropdown" id="year-dropdown">
<button class="btn btn-default dropdown-toggle" type="button"
id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
Year
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
{% for year in years %}
<li>{{ year }}</li>
{% endfor %}
</ul>
</div>
javascript: (just shows the value right now, but can't verify with the database)
$('#calculate').on('click', function ()
{
$(this).siblings()[0].textContent = (
document.getElementById("dropdownMenu1").textContent
+ " " + document.getElementById("dropdownMenu2").textContent
+ " " + document.getElementById("dropdownMenu3").textContent
+ " " + document.getElementById("specifics-gas").value
)
});
});
//this part changes the year, make, model to what the user selects //from the list
$('li').on('click', function () {
$(this).parent().siblings()[0].innerHTML = this.innerHTML
//console.log(this.textContent)
});
Suppose you have to populate a static list of all the brand names in a drop-down and the second dropdown is supposed to be populated based on the selection in first.
Assuming two simple Django models defining Brands and Showrooms.
Views.py
class YourView(TemplateView):
template_name = 'template.html'
def get_context_data(self, **kwargs):
brands = Brands.objects.all()
context = super(YourView, self).get_context_data(**kwargs)
context.update({'brands': brands})
return context
def get_showrooms(request, **kwargs):
brand = Brands.objects.get(id=kwargs['brand_id'])
showroom_list = list(brand.showrooms.values('id', 'name'))
return HttpResponse(simplejson.dumps(showroom_list), content_type="application/json"
HTML
<label>Select Brand</label>
<select id="brands" name="brands" class="form-control">
<option value="">Select Brand</option>
{% for brand in brands %}
<option id="{{ brand.id }}" value="{{ brand.id }}">
{{ brand.name }}
</option>
{% endfor %}
</select>
<label>Select Showrroom</label>
<div id="showroom_list">
<select name="showrooms" class="form-control">
</select>
</div
Ajax
$('select[name=brands]').change(function(){
brand_id = $(this).val();
request_url = '/sales/get_showrooms/' + brand_id + '/';
$.ajax({
url: request_url,
success: function(data){
$.each(data, function(index, text){
$('select[name=showrooms]').append(
$('<option></option>').val(index).html(text)
);
};
});
You can make the RESTful calls in request_url.
You can further populate the third dropdown based on the selection in second and so on. Also, you can access the selected option and perform the further stuff.
The chosen plugin can help you in optimizing your dropdowns.
I would go for a REST service, like Django Rest Framework, and then use jquery to autopopulate the dropdowns.
If installing a REST service is a hassle, you could write a couple of views to get the data in json format...
For instance, if you have a REST service in /myapp/api, you could populate the Cars like this:
$.ajax({
url: "/myapp/api/cars?format=json",
dataType: "json",
success: function( data ) {
var makes=[];
for (var i in data) {
car = data[i];
if (makes.indexOf(car.make) < 0){ // avoid duplicate brands
makes.push(car.make);
$('#makeselect').append($('<option>', {
value: car.id,
text: car.make
}));
}
}
}
});
Then, attach a handler when the "make" selector has changed, and populate the model and year accordingly using another REST call, like /myapp/api/cars?make=Ford
I'm not sure what you're confused about. Why would you put every car into a page? When you build a normal non-Ajax page, you pass some data - eg the slug or ID of a database object - via the URL, you query the database for that specific object, and return its data via an HTML template.
The exact same logic applies for Ajax, except that you probably don't want an HTML template; you can just return JSON, which is easy for JS to understand.

How to initialise data on a non model form?

I have a little question regarding Forms / Views which don't use a Model object. I seem to have it set up almost the way it should, but I can't seem to figure out how to pass data around to initialise the fields in my edit form.
What I have to do is get data from a REST server which was developed using Delphi. So this django thingie won't be using the normal django ORM model thing. Currently I have it working so my app displays a list of departmets which it got using a REST call to the server. Each department has it's ID as a hyperlink.
My next step / thing I would like to do is display a form in which the user can edit some values for the selected department. Logically everything seems to be hooked up together the way it should (as far as I can see). Sadly ... for whatever reason ... I can't seem to pass along information about the clicked ID or even the selected object in my list to the detail view.
Would anyone be able to help me out ? This is what I have so far :
The urls.py :
# DelphiClient/urls.py
from django.conf.urls import patterns
from django.conf.urls import url
from . import views
urlpatterns = patterns("",
url(
regex=r"^Departments$",
view=views.DelphiDepartmentsListView.as_view(),
name="Departments"
),
url(
regex=r'^Department/(?P<pk>\d+)/$',
view=views.DepartmentFormView.as_view(),
name='department_update'
),
)
The views.py :
# DelphiClient/views.py
...
from .client import DelphiClient
from .forms import DepartmentForm
class DelphiDepartmentsListView(TemplateView):
template_name = 'DelphiDepartmentList.html'
def get_context_data(self, **kwargs):
client = DelphiClient()
departments = client.get_department()
context = super(DelphiDepartmentsListView, self).get_context_data(**kwargs)
context['departments'] = departments
#client.update_department(1, 'Update From Django')
return context
class DepartmentFormView(FormView):
template_name = 'DepartmentUpdate.html'
form_class = DepartmentForm
success_url = '/DelphiClient/Departments'
def get_initial(self, **kwargs):
"""
Returns the initial data to use for forms on this view.
"""
initial = super(DepartmentFormView, self).get_initial(**kwargs)
# How can I get the ID passed along from the list view
# so I can get the correct object from my REST server and
# pass it along in the Initial ???
return initial
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
print "form.data {0}".format(form.data)
client = DelphiClient()
client.update_department(form.data["flddepartmentId"],form.data["flddepartmenet"])
return super(DepartmentFormView, self).form_valid(form)
The forms.py :
# DelphiClient/forms.py
from django import forms
from .client import DelphiClient
class DepartmentForm(forms.Form):
# How can I fill in the values for these fields using an object passed in
# thhrough Initial or the context?
flddepartmentId = forms.IntegerField(label="Department ID") #, value=1)
flddepartmenet = forms.CharField(label="New Description", max_length=100)
def update_department(self, *args, **kwargs):
#print "update_department"
#print self.data
#print self.data["flddepartmenet"]
client = DelphiClient()
client.update_department(self.data["flddepartmentId"],self.data["flddepartmenet"])
And the template for the form :
<h1>Update Department</h1>
<p>Update Department? {{ department.flddepartmentid }}</p>
<p>Something : {{ something }}</p>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<p><label for="id_flddepartmentId">Department ID:</label> <input id="id_flddepartmentId" name="flddepartmentId" type="number" value="1"></p>
<p><label for="id_flddepartmenet">New Description:</label> <input id="id_flddepartmenet" maxlength="100" name="flddepartmenet" type="text"></p>
<input type="submit" value="OK">
</form>
As you can see ... I'm close ... but no cigar yet :-) Since I'm completely new to Python / Django and have been learning on the go, I have no idea what I'm doing wrong or where I should look.
If anyone would be able to help or point me in the right direction it would be really appreciated.
The positional and name-based arguments are stored in self.args and self.kwargs respectively (see the docs on name based filtering). Therefore you can access the pk with self.kwargs['pk'].
I'm not sure that you should include flddepartmentId as an editable field in the form. It means that users could go to /Department/1/, but then enter flddepartmentId=2 when they submit the form. It might be better to remove the field from the form, then use the value from the URL when calling update_department.
client.update_department(self.kwargs['pk'],self.data["flddepartmenet"])
If you are sure that you want to include flddepartmentId in your form, then your get_initial method should look as follows:
def get_initial(self, **kwargs):
"""
Returns the initial data to use for forms on this view.
"""
initial = super(DepartmentFormView, self).get_initial(**kwargs)
initial['flddepartmentId'] = self.kwargs['pk']
return initial

Updating vote counts in Google App Engine

I am trying to create a voting button for posts using Google App Engine.
Currently I am implementing it like this:
class Latest(Handler):
def get(self):
posts = recent_posts()
qt = memcache.get('recent_posts_qt')
if qt:
qt = time.time() - qt
self.render('latest.html', articles = posts, qt = qt)
def post(self):
post_id = int(self.request.get("id"))
q = AllPost.get_by_id(post_id)
q.votes += 1
q.put()
time.sleep(0.5)
update = recent_posts(update=True) # for memcache
posts = db.GqlQuery("SELECT * FROM AllPost ORDER BY created DESC LIMIT 10")
posts = list(posts)
self.render('latest.html', articles=posts)
The html I am using is this:
<div class="article-votes">Votes: {{item.votes}}
<form action="/latest" method="post">
<input name="id" value={{item.key().id()}}>
<button>Vote+</button>
</form>
</div>
If I try to refresh the page after voting on a post, I get the "confirm form submission alert". There must be a better way to implement this without this happening. Is it possible to update the vote count and datastore without rendering the page again?
Refreshing a POST request will always trigger that confirmation window, it is a common behavior in most browsers. You can control the form POST request closely via Javascript using AJAX (XMLHTTPRequest) and that wouldn't cause another page render.

jQuery UI tabs in django templates

I have template with many tabs (jQuery UI):
<div>
Satus: <span id="status_value"> {{ purchase.get_status_display }}</span>
Owner: <span id="admin_value"> {{ purchase.owner }}</span>
</div>
<div class="tabs">
<div class="tabs-navigation">
<ul>
<li>Purchase description</li>
<li>Purchase catalog</li>
</ul>
</div>
</div>
This is view.py, first of I render main template, than using ajax render tab, In this case purchase_info_tab, for main template I need model Purchase and for purchase_info_tab I need model Purchase and we have two identical query. Сan I avoid this somehow?
#render_to('app/purchase_view.html')
def purchase_view(request, purchase_id):
try:
purchase = Purchase.objects.get(id=purchase_id)
except Purchase.DoesNotExist:
raise Http404()
return {
'purchase': purchase,
}
#render_to('app/tabs/info_tab.html')
def purchase_info_tab(request):
purchase = #I load one model twice in one page
try:
itemsgroups = ItemsGroup.objects.filter(purchase=purchase).all()
except IndexError:
raise Http404()
return {
'itemsgroups': itemsgroups,
}
There are many ways to avoid this.
The easiest is to use sessions, as such:
#render_to('app/purchase_view.html')
def purchase_view(request, purchase_id):
try:
purchase = Purchase.objects.get(id=purchase_id)
except Purchase.DoesNotExist:
raise Http404()
else:
request.session['purchase'] = purchase
# [snip]
#render_to('app/tabs/info_tab.html')
def purchase_info_tab(request):
purchase = request.session['purchase']
# [snip]
From Django's point of view, your two views are entirely separate and you cannot share information between them without stashing it in some third location such as a URL parameter or session (remember that view methods may run even on different servers depending on how the application is deployed).
However, in the example you've given there is no need to. You don't have to retrieve your purchase object to get the ItemsGroup: you can pass an ID into your query:
itemsgroups = ItemsGroup.objects.filter(purchase__id=purchase_id).all()

Categories

Resources