Display JSON data when render a HTML template with FLASK - python

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>
`

Related

How to pass jinja2 loop variable to app route function with flask?

I have an html page that displays documents and their preview sorted by their pagerank value. I want to make it so that when the user clicks a document, it takes them to the corresponding document
html:
<div class="col-sm-6 text-white">
<h1 class="display-1">Boolean Model</h1>
{% for doc, pr in q_res_bool.items() %} // e.g. "doc1.txt: 0.6459865341"
<a href="/document">
<div class="m-3">
<h2 class="mt-5">{{ doc }} <span class="h6 text-dark-emphasis">({{ pr[:5] }})</span></h2>
<p class="col-7">{{ boolPreview[doc] }}</p>
</div>
</a>
{% endfor %}
</div>
This is the general idea that i want (document route in app.py):
# Document page
#app.route('/document')
def view_document(doc):
with open(f"docs/{doc}") as f:
document = f.read()
return render_template("result.html", document=document)
How do i pass the variable in the loop to this function as parameter?
I thought of putting something along the lines of
<input type="hidden" id="{{ doc }}" name="{{ doc }}" value="{{ doc }}">
in my html, going by this article and getting the value with request.args.get() but i end up with the same problem of not knowing what to pass as parameter
example screenshot of html:
I solved it by changing my link tag to <a href="/docs/{{ doc }}">
and then accessing it via a variable rule in my app.py:
#app.route('/docs/<doc>', methods=['GET', 'POST'])
def view_document(doc):
print("route received")
with open(f"docs/{doc}") as f:
document = f.read()
return render_template("result.html", document = document, title = doc)

How to dynamically re-render template?

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){ });
});

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>

Links that I have in 'navbar' overlaps each other:/

Hello everyone:) Links that I have in 'navbar' overlaps each other when I make a transition into another link. For instance, I have a navbar menu with four different links (home, catalog, distributors and contacts) and 'home' is a base webpage. I.e when I make a transition from the base webpage 'http://127.0.0.1:8000/' to catalog I get this http://127.0.0.1:8000/catalog (all right) but then I make a transition into section 'distributors' and then I get this 'http://127.0.0.1:8000/catalog/distributors (and it's not normal) How to rectify this?
My url patterns seems right :/
urlpatterns = [
url(r'^$', views.home, name='home'),
url(r'^catalog/$', views.catalog, name='catalog'),
url(r'^distributors/$', views.distributors, name='distributors'),
url(r'^contacts/$', views.contacts, name='Contacts'),
]
template:
<div class="header">
<div id="inner">
<div class="col">
<div class="inner">
<div class="image"><p>HOME</p></div>
<div class="filter1"></div>
<div class="filter2"></div>
<div class="txt">
<p>We greet you on the main</p>
<p>page of our website!</p>
</div>
</div>
</div>
<div class="col">
<div class="inner">
<div class="image"><p>CATALOG</p></div>
<div class="filter1"></div>
<div class="filter2"></div>
<div class="txt">
<p>Browse through our catalog</p>
<p>and select the good just for you.</p>
</div>
</div>
</div>
<div class="col">
<div class="inner">
<div class="image"><p>DISTRIBUTORS</p></div>
<div class="filter1"></div>
<div class="filter2"></div>
<div class="txt">
<p>We are currently expanding our</p>
<p>distributor network into new markets.</p>
</div>
</div>
</div>
<div class="col">
<div class="inner">
<div class="image"><p>CONTACTS</p></div>
<div class="filter1"></div>
<div class="filter2"></div>
<div class="txt">
<p>You can always communicate with us</p>
<p>using section "Contacts". </p>
</div>
</div>
</div>
</div>
</div>
views:
def home(request):
products_images = ProductImage.objects.filter(is_active=True, is_main=True, product__is_active=True)
products_images_with = products_images.filter(product__category__id=1)
products_images_without = products_images.filter(product__category__id=2)
return render(request, 'landing/home.html', locals())
def catalog(request):
products_images = ProductImage.objects.filter(is_active=True, is_main=True, product__is_active=True)
return render(request, 'landing/catalog.html', locals())
def distributors(request):
return render(request, 'landing/distributors.html', locals())
def contacts(request):
return render(request, 'landing/Contacts.html', locals())
Can someone help me with this problem? Django version 1.11.2
As #David D. answered, you should use the method of url building as it provides you flexibility.
But, if for some reason you want that absolute URLs should be specified in href, then while using absolute urls the above problem can be solved by prepending a forward slash to each url name when assigning to href.
So your new urls should look like :
CATALOG
DISTRIBUTORS
CONTACTS
The reason it works is that / represents root of website, so using '/' routes you to the root and using '/catalog' routes you to the catalog page directly from the root.
The problem is the way you use links in your Django templates.
Take a look to: https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#url
You have to use a {% url 'url-name-here' %} sothat Django will build url by itself.
For example, in your case:
<div class="image"><p>CATALOG</p></div>
This way:
it's a lot easier for you, you just provide the url name and let Django generated the real url.
you don't repeat yourself; if you want to change the path of the url, you only need to do it one time in urls.py.

Extracting HTML content

I have extracted below HTML content from an URL using Scrapy
<div id="data">
<div style="position:absolute">
<h4 class="course">Python</h4>
<h4 class="count">45</h4>
</div>
<h1 style="position:absolute">Available</h1>
<h2 style="position:absolute">Weekend</h1>
<h1 style="position:absolute">Paid Version</h1>
</div>
and using xpath
headerResponse = response.xpath('//div[#id="data"]').extract()
I have loaded them into headerResponse variable. Now I want to get value, since it doesnt have id or class how to extract them?

Categories