How to dynamically re-render template? - python

Currently I am trying to create a dynamic filter for listing model objects in a template. Here is the django view:
def view_data(request):
text = request.GET.get('text')
persons = None
if text:
try:
persons = models.Person.objects.get(code__regex=text)
except models.Person.DoesNotExist:
pass
return render(request, 'view_data.html',
{'persons': persons if not isinstance(persons, models.Person) else [persons]})
The related part from the template:
<div class="jumbotron row">
<form>
<label>Alanyok szűrése</label>
<input id="filter" type="text" placeholder="Keresett alany">
</form>
</div>
<div class="row">
<div class="col-4">
<div class="list-group" id="list-tab" role="tablist">
{% for person in persons %}
<a class="list-group-item list-group-item-action" id="list-{{person.code}}" data-toggle="list" href="#" role="tab" aria-controls="{{person.code}}">{{person.code}}</a>
{% endfor %}
</div>
</div>
<div class="col-8">
<div class="visualisation content">
<div class="canvas_div">
<canvas id="Canvas1" width="540" height="250" style="border:1px solid #202020;">
</canvas>
</div>
</div>
</div>
</div>
The input field with filter id has a callback on keyup event which sends a request to django with the content of the input field which is used in the view for query.
Here is the callback:
$( "#filter" ).keyup(function() {
$.get("", {text: $('#filter').val()});
});
When I checked it with Pycharm debugger, the render returns the correct html but on the client side the html doesn't change. How to re-render with the new object list?

Take a part of your html code that you want to replace and place it inside a new html file like this:
new_html:
<div class="list-group" id="list-tab" role="tablist">
{% for person in persons %}
<a class="list-group-item list-group-item-action"
id="list-{{person.code}}" data-toggle="list"
href="#" role="tab" aria-controls="{{person.code}}">
{{person.code}}
</a>
{% endfor %}
</div>
now in your view replace the name of your old html file ( that you are rendering ) with the new html file like this:
return render(request, 'new_html.html',
{'persons': persons if not isinstance(persons,models.Person) else [persons]})
and now in your ajax you can dynamically load this new_html like this :
$( "#filter" ).keyup(function() {
$.get("",
{text: $('#filter').val()},
function(data){
$( "#list-tab" ).replaceWith( data );
}
);
});

You are not doing nothing with the returned data. Add a callback function in the get method call. You get the response from the server in the first argument. Use that to hide and show contents on the page. Or you can even replace elements in the DOM. See jquery.replaceWith.
$( "#filter" ).keyup(function() {
$.get("", {text: $('#filter').val()}, function(response){ });
});

Related

Display JSON data when render a HTML template with FLASK

I have aproblem when i try to render the JSON data in the HTML template.
I dont know if the problem is in the Python code or in the HTML code.
I've tested the python code of the search funtion (returns a JSON with a list o products) and returns a valid JSON (the JSON than i expected).
But i still havig issues with the HTML.
I've searched a lot, but nothing helped me.
The function of the HTML template is to display the products of my ecommerce. In this template i'll show the results of a previous search.
Here is the code of the python app:
search = request.form['search']
if search != "":
for product in mycol.find({"name": {"$regex": f".*{search}.*", "$options": "i"}}):
datainfo = json.loads(json_util.dumps(product))
return render_template("search.html", product=datainfo)
else:
return render_template("index.html")
The HTML card code:
<div>
<div class="results_container">
<div class="row">
<div class="card">
<ul>
{% for product in product %}
<li class="table-row">
<div id="Product">{{product['name']}}</div>
<div id="Price">{{product['price']}}</div>
<div id="Description">{{product['description']}}</div>
<div id="Category">{{product['category']}}</div>
<div id="Seller">{{product['user_name']}}</div>
<div>
Buy
</div>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
</div>
`

Python Flask cookie consent

I want to set a banner that asks for permission to store cookies on my website(because GDPR). I've tried like this:
HTML:
{% block cookies %}
{% if cookies_check %}
{% else %}
<div class="fixed-bottom p-4" id="cookie-consent-container">
<div class="toast bg-dark text-white w-100 mw-100" role="alert">
<div class="toast-body p-4 d-flex flex-column">
<h4>Cookie Warning</h4>
<p>
This website stores data such as cookies to enable site functionality including analytics and personalization. By using this website, you automatically accept that we use cookies.
</p>
<div class="ml-auto">
<button type="button" class="btn btn-outline-light mr-3" id="btnDeny">
Deny
</button>
<button type="button" class="btn btn-light" id="btnAccept">
Accept
</button>
</div>
</div>
</div>
</div>
<script>
var fn = function () {
document.cookie = "cookie_consent=true";
document.getElementById('cookie-consent-container').hidden = true;
};
document.getElementById('btnAccept').onclick = fn;
</script>
{% endif %}
{% endblock cookies %}
and jinja2
#app.context_processor
def inject_template_scope():
injections = dict()
print(injections)
def cookies_check():
value = request.cookies.get('cookie_consent')
print(value)
return value == 'true'
injections.update(cookies_check=cookies_check)
return injections
The prints are for debugging. The problem is that the list is always empty and the banner is never showing. What should I do to make this work? Does that mean that the site is not generating any cookie to begin with? If so how can I add a cookie when the site is loaded?
A cookie can be added,read,deleted using document.cookie
document.cookie = "username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 UTC";
By default cookie delete after browser is closed.

How to render common things in footer.html in Django

I have set up Django templates, which include index.html, header.html and footer.html.
In footer.html, I want to set dynamically a phone number, email and address. I can see I can pass it through context from views.py, but footer.html will included in all the templates, so I will need to pass it in every function in views.py, which is not good.
So what I want is to create one common function and I want to call it from footer.html. Is that the right way to do this? Or if you have any other idea, then please let me know how to do that.
views.py:
def index(request):
portal_contact_email = preferences.MyPreferences.portal_contact_email
context = {'portal_contact_email': portal_contact_email,}
return render(request, 'mysite/index.html', context)
footer.html:
<footer class="bg-dark footer-section">
<div class="section">
<div class="container">
<div class="row">
<div class="col-md-4">
<h5 class="text-light">Email</h5>
<p class="text-white paragraph-lg font-secondary">{{ portal_contact_email }} </p>
</div>
<div class="col-md-4">
<h5 class="text-light">Phone</h5>
<p class="text-white paragraph-lg font-secondary"></p>
</div>
<div class="col-md-4">
<h5 class="text-light">Address</h5>
<p class="text-white paragraph-lg font-secondary"></p>
</div>
</div>
</div>
</div>
<div class="border-top text-center border-dark py-5">
<p class="mb-0 text-light">Copyright #<script>
var CurrentYear = new Date().getFullYear()
document.write(CurrentYear)
</script>
{# a theme by themefisher.com#}
</p>
</div>
</footer>
For this purpose you could create a custom ContextProcessor.
According to the docs, ContextProcessors
take a request object as their argument and return a dictionary of items to be merged into the context
A custom ContextProcessor in your case could look like this:
def footer_data(request):
return {'phone_number': 'xyz', ...}
Then append it to your settings.py so it is actually being used:
TEMPLATES = [
{
...
'OPTIONS': {
'context_processors': [
'myapp.my_context_processors.footer_data',
...
And in your templates you can access these variables simply with {{ phone_numer }}.

Flask - how to get id of post after clicking on title

I create a simply website about books. I display the title and description in books.html
<div id="book-container">
<p><h2>{{ b.title }}</h2></p>
<div><p>{{ b.description }}</p></div>
<br>
</div>
and my route file
#app.route('/show_books', methods=['GET', 'POST'])
def show_books():
books = Book.query.all()
return render_template('books.html', title='Home', books=books)
I have problem, because I want to display more information about book after clicking on title. What is the best way to do it? Thanks for help!
Ok, I find other solution but it doesnt work well:
book.html:
<div id="book-container">
{{ b.title }}
<div><p>{{ b.description }}</p></div>
<br>
</div>
routes.py:
#app.route('/detail_book/<title>')
def detail_book(title):
book = Book.query.filter_by(title=title).first_or_404()
return render_template('detail_book.html', book=book)
detail_book.html:
DETAILS
<div id="book-container">
{{ b.id }}
<h2>{{ b.title }}</h2>
<div><p>{{ b.description }}</p></div>
<br>
</div>
After clicking on title my url looks like:
http://localhost:5000/detail_book/Painted%20Man
And in consol: jinja2.exceptions.UndefinedError: 'b' is undefined
And I really have no idea how to solve this problem
You can use this to access the title you click. And this.id will give you the id of this element:
<div id="book-container">
<h2 id="{{ b.title}}" class="titles">{{ b.title }}</h2>
<div><p>{{ b.description }}</p></div>
<br>
</div>
<script type=text/javascript>
$(function(){
$('.titles').bind('click', function(){
alert(this.id);
});
});
</script>
By clicking on the title, you will see a modal indicating the id of the current element (in this case the id will be the title of the book).
The idea here is to add the class .titles to all the titles that will appear on your page and recover, with this.id, the id of the element you click. Then you can make an Ajax request to find the additional information corresponding to the specific element on which you clicked.
It looks like detail_book has a variable book not b.
In your render template you use the variable book.
Below is what the html should look like.
DETAILS
<div id="book-container">
{{ book.id }}
<h2>{{ book.title }}</h2>
<div><p>{{ book.description }}</p></div>
<br>
</div>

Send data from django views to angularjs controller

I am trying to send data from django views.py file to angularjs controller.js file but unable to send it.
The problem is this that I am unable to send data from views file to controller. And when I run my code then the value {%steps%} doesn't change to the value I have assigned in views file.
I don't want to use Django rest framework for doing this.
Is there any other way of achieving this? If yes, then please help me out.
views.py:
from django.shortcuts import render
from django.conf import settings
from user_data.models import GetData
import json
def home(req):
return render(req, 'index.html')
def userData(req):
if req.method == 'GET':
user_data = GetData().getAllData()
context_dict = {'user_data1' : json.dumps(user_data[0]),
'user_data2' : json.dumps(user_data[1]),
'user_steps' : json.dumps(2000)}
return render(req, 'index.html', context_dict)
controller.js :
'use strict';
MetronicApp.controller('DashboardController', function($rootScope, $scope, $http, $timeout) {
$scope.$on('$viewContentLoaded', function() {
// initialize core components
Metronic.initAjax();
});
$scope.steps = {{user_steps|safe}};
});
html file:-
<div ng-controller="DashboardController" class="margin-top-10">
<div class="row ">
<div class="col-md-12 col-sm-12">
<div class="portlet light ">
<div class="portlet-title">
<div class="caption">
<i class="icon-cursor font-purple-intense hide"></i>
<span class="caption-subject font-purple-intense bold uppercase">Tracker Report</span>
</div>
<div class="actions">
<a href="javascript:;" class="btn btn-sm btn-circle btn-default easy-pie-chart-reload">
<i class="fa fa-repeat"></i> Reload </a>
</div>
</div>
<div class="portlet-body">
<div class="row">
<div class="col-md-3">
<div class="easy-pie-chart">
<div class="number transactions" data-percent="55">
<span>{$ steps $}</span>
</div>
<!-- <a class="title" href="#"> -->
Steps <!-- <i class="icon-arrow-right"></i> -->
</a>
</div>
</div>
<div class="margin-bottom-10 visible-sm">
</div>
<div class="col-md-3">
<div class="easy-pie-chart">
<div class="number visits" data-percent="85">
<span>
+85 </span>
%
</div>
<!-- <a class="title" href="#"> -->
Sleep<!-- <i class="icon-arrow-right"></i> -->
</a>
</div>
</div>
<div class="margin-bottom-10 visible-sm">
</div>
<div class="col-md-3">
<div class="easy-pie-chart">
<div class="number bounce" data-percent="46">
<span>
+46 </span>
%
</div>
<!-- <a class="title" href="#"> -->
Calories <!-- <i class="icon-arrow-right"></i> -->
</a>
</div>
</div>
<div class="margin-bottom-10 visible-sm">
</div>
<div class="col-md-3">
<div class="easy-pie-chart">
<div class="number bounce" data-percent="32">
<span>
+32 </span>
%
</div>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
This is basically what I have done in one of my major django projects (but I am not 100% sure, whether this is or this ain't what you are looking for, as an answer).
So, instead of views.py, I have made a custom.py file in which I make custom APIs and call them (using urlpatterns) in the urls.py of my django app. And I have another set of APIs for which I am using django rest framework, for which I make viewsets rather than simple views. Just in case, you are interested, you might like reading this SO link.
But since, you specifically mentioned that you don't want to use django rest frameworks, I will give you an example of the custom.py file, as mentioned above.
Below you will find a sample of an API defined in a custom.py,
#api_view(['GET'])
def get_user_details(request):
"""
API View that gives a user detail
---
parameters:
- name: email
description: The email of the user based on which his/her information has been extracted
required: true
type: string
responseMessages:
- code: 400
message: Email required as GET parameters.
message: User not found.
- code: 200
mesage: User details sent successfully
consumes:
- application/json
- application/xml
produces:
- application/json
- application/xml
"""
email = request.query_params.get('email', None)
if email is None:
return HttpResponseBadRequest("Email required as GET parameters.")
try:
user = User.objects.get(username=email)
except User.DoesNotExist:
return HttpResponseBadRequest("User not found.")
response_data = {'id': user.id, 'first_name': user.first_name, 'last_name': user.last_name,}
return HttpResponse(json.dumps(response_data), content_type="application/json")
And subsequently, the urls.py in my django app looks like:
urlpatterns = router.urls
urlpatterns = urlpatterns + [
url(r'get_user_details/', get_user_details),
]
My controller would look something like this:
CheckEmail : function (current) {
return $http({
method: 'GET',
url: baseAPI + 'admin/get_user_details/',
params: {email: current},
})
},
And then subsequently, you may be able to render the variable you wish to print in your html file using handles.
Hope, it helps.

Categories