Problem iterating through MongoDB data using Flask & Jinja2 - python

brand new to Flask/Python and i'm trying to iterate through a list of data from MongoDB using Flask. The data is grabbed with no issues but the result i get is all of the database entries stuffed into one div. Below i've provided some screenshots to further explain the problem.
The 2 MongoDB Entries:
The idea is to have 2 separate cards displaying the 2 entries. The card will display the name_moving, once clicked, the rest of the info will appear in a modal.
HTML Template Code:
<div id="modal1" class="modal request_info_wrap">
{% for user_details in user_details: %}
<div class="modal-content request_info_card">
<h4 class="request_name_header">{{ user_details.user_name }} {{ user_details.user_lname }}</h4>
<p class="request_info"><span class="request_title">Request
Address:</span><br>{{ user_details.user_street }}<br>{{ user_details.user_postcode }}</p><br>
<p class="request_info"><span class="request_title">Contact
Number:</span><br>{{ user_details.user_contact }}</p><br>
<p class="request_info"><span class="request_title">Requested
Date:</span><br>{{ user_details.user_date }}</p><br>
<div class="deep_clean_section">
<p class="request_info" style="color: #000;"><span class="request_title">Deep Clean
for:</span><br>{{ user_details.carpet_clean }}<br>{{ user_details.floor_steam }}<br>
{{ user_details.white_goods }}<br>{{ user_details.window_clean }}
</p>
</div><br>
<hr style="margin: 0;">
<p class="request_info"><span class="request_title">Customer
Message:</span><br>{{ user_details.user_message }}</p>
</div>
<div class="modal-footer job_card_btn_wrap">
<a href="#" class="modal-close replyto_btn">Reply to
{{ user_details.user_name }}</a>
</div>
{% endfor %}
</div>
</div>
The issue i'm having is that both entries show within the same div (shown below) whereas im trying to get each MondoDB entry to show individually when clicked.
Python/Flask Code:
#app.route("/deep_clean_info", methods=["GET", "POST"])
def deep_clean_info():
if request.method == "POST":
user_details = {
"user_name": request.form.get("user_name"),
"user_lname": request.form.get("user_lname"),
"user_contact": request.form.get("user_contact"),
"user_street": request.form.get("user_street"),
"user_postcode": request.form.get("user_postcode"),
"user_message": request.form.get("user_message"),
"user_date": request.form.get("user_date"),
"carpet_clean": request.form.get("carpet_clean"),
"floor_steam": request.form.get("floor_steam"),
"white_goods": request.form.get("white_goods"),
"window_clean": request.form.get("window_clean"),
}
mongo.db.user_details.insert_one(user_details)
flash("Request sent to cleaner")
return redirect(url_for("deep_clean_info"))
details = mongo.db.user_details.find().sort("user_details", 1)
return render_template("deep_clean_details.html", user_details=details)
I do think the issue is with my jinja2 for loop in my template but any help would be greatly appreciated, also if any additional information is needed i'll be more than happy to provide. Thanks!
EDIT
HTML Template that seemed to iterate fine, although i dont want to use this style to display the data.
<ul class="collapsible popout pending_jobs">
{% for user_details in user_details %}
<li>
<div class="collapsible-header request_item_header">
<i class="fas fa-comment-dots"></i>
{{ user_details.user_name }} {{ user_details.user_lname }}
</div>
<div class="collapsible-body request_info">
<div class="row">
<span class="row info_headers">Address:<br>
<span class="light_text info_text" id="customer_address">
{{ user_details.user_street }}</span>
</span><br>
<span class="info_headers">Contact Number:<br>
<span class="light_text info_text" id="customer_contact">{{ user_details.user_contact }}</span>
</span><br>
</div>
<span class="info_headers row customer_request_style">Customer Request:<br>
<span class="light_text italic_text" id="customer_request">{{ user_details.user_message }}</span>
</span><br>
<span class="info_headers">Cleaning Date:<br>
<span class="light_text italic_text" id="customer_request">{{ user_details.user_date }}</span>
</span><br>
<a href="{{ url_for('cleaner_chat') }}"><button class="respond_to_user">Respond to
{{ user_details.user_name }}?</button></a>
</div>
</li>
{% endfor %}
</ul>

Related

Python Jinja2 loop index to make id unique

I'm using jinja2 template with Flask and MongoDB and I need to display users' cars in a template.
I was able to render cars in the profile template with car information and buttons to edit or delete a car. The problem is that if a user has multiple cars, only the first DELETE CAR button actually works (where I have an include modals to confirm) but nothing happens when click on the second or third delete button. Apparently I duplicated the id that needs to be unique. But I cannot achieve the results.
Here is my template: profile.html
{% extends 'layout/base.html' %}
{% block content %}
{% include 'components/navigation/navigation.html' %}
<div class="container">
<div class="row g-3 justify-content-center">
<div class="col-6 mt-5">
<div class="card">
<div class="card-body">
<h3 class="text-center profileHeader">
{{ username }}'s profile
</h3>
</div>
</div>
</div>
</div>
<div class="row row justify-content-center mt-4">
{% for car in cars %}
{% if session.user|lower == car.created_by|lower %}
<div class="card mb-3" style="max-width: 840px;">
<div class="row g-0">
<div class="col-md-4">
<img src="{{ car.car_image }}" class="imgCard" alt="ferrari image">
</div>
<div class="col-md-8">
<div class="card-body">
<ul class="list-group list-group-flush">
<li class="list-group-item"><strong>Year</strong>: {{ car.car_year }} </li>
<li class="list-group-item"><strong>Name</strong>: {{ car.car_name }}</li>
<li class="list-group-item"><strong>Designer</strong>: {{ car.car_design }}</li>
</ul>
<ul class="list-group list-group-flush">
<li class="list-group-item"><strong>Engine</strong>: {{ car.spec_engine }}</li>
<li class="list-group-item"><strong>Power</strong>: {{ car.car_power }}</li>
<li class="list-group-item"><strong>Trasmission</strong>: {{ car.trasmission }}</li>
<li class="list-group-item"><strong>Races</strong>: {{ car.races }}</li>
<li class="list-group-item"><strong>Wins</strong>: {{ car.wins }}</li>
<li class="list-group-item"><strong>Podiums</strong>: {{ car.podiums }}</li>
<li class="list-group-item"><strong>Poles</strong>: {{ car.poles }}</li>
<li class="list-group-item"><strong>Fast Laps</strong>: {{ car.fast_laps }}</li>
<li class="list-group-item"><strong>Constructor Championship</strong>: {{
car.constructor_champ
}}</li>
<li class="list-group-item"><strong>Driver Championship</strong>: {{ car.drivers_champ }}
</li>
<li class="list-group-item"><strong>Description</strong>: {{ car.description }}</li>
<p><em>by: {{ car.created_by }}</em></p>
</ul>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<a id="myBtn" class="btn btn-danger"><i class=" fas fa-trash-alt"></i> Delete</a>
<a href="{{ url_for('editcar', car_id=car._id) }}" class="btn btn-danger" id="edit-btn"><i
class="far fa-edit"></i> Edit</a>
{% with car_id=car._id %}
{% include 'components/modals/confirm.html' %}
{% endwith %}
</div>
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
</div>
enter code here
</div>
{% endblock %}
Just make unique the tag id of delete button, so the trigger will be unique in every button. How to make unique ? just add the car._id on tag id
<a id="myBtn-{{car._id}}" class="btn btn-danger"><i class=" fas fa-trash-alt"></i> Delete</a>
As #Darn pointed out, your ids need to be unique. But that is not the cause of your issue here.
I assume you have some Javascript code that gets triggered when user clicks on the delete link. The issue is probably from how that code is being triggered. The code needs to be written in such a way that it is bound to dynamically generated elements (you're generating the delete links on the fly i.e. afte the code for the delete was already bound; that delete code needs to also apply to each element when it is created).
You should bind the delete action to a class e.g.
$(".fa-trash-alt").on("click", function(){
$(this).parent() ...... // this is the link to the instance of the link that was clicked
});

How to create a dynamic bootstrap carousel, using flask/python?

For context:
I'm building a social network. Just like with Facebook, each profile has a tab titled "images", which is a collection of thumbnails from the profile owner's posts.
My goal:
Just like with Facebook, I'd like the user navigating the page to be able to click on any thumbnail image, launching a bootstrap carousel and displaying that specific image in a much larger view. The user could then use the carousel-control class to scroll through the profile owner's other images.
Current situation:
The thumbnails display, you can click on any thumbnail and launch the carousel, but all of the profile owner's images appear stacked, as if they're all active.
I'm using a jinja2 for loop and a url_for statement to access the images. I also use a loop counter within an if statement to make it so only one image is active, but its obviously not working :(
It was this 4 year old stackoverflow post that I used to attempt solving this problem to begin with.
When using the carousel with a few images added statically it works properly, but I need it to be dynamic for obvious reasons.
I'm unsure how to go about showing just the specific image that was clicked on, and having the ability to scroll through the others.
Any help will be greatly appreciated!
Here is my HTML
<div id="carouselExampleControls" class="carousel slide" data-ride="carousel">
<div class="carousel-inner">
{% for post in user.posts %}
{% if post.post_img != None %}
<div class="container">
<div class="item {% if loop.counter == 1 %} active {% endif %}" id="slide{{ loop.counter }}">
<img src="{{ url_for('static', filename='post_pics/' + post.post_img) }}">
</div>
<a class="carousel-control-prev" href="#pageCarousel" role="button" data-slide="prev">
<span class="carousel-control-prev-icon bg-primary" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#pageCarousel" role="button" data-slide="next">
<span class="carousel-control-next-icon bg-primary" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
{% endif %}
{% endfor %}
</div>
</div>
You can move the a tags outside the inner-carousel div, maybe like below ( its untested)
If you look at the documentaion, the a tags have to be outside.
<div id="carouselExampleControls" class="carousel slide" data-ride="carousel">
<div class="carousel-inner">
{% for post in user.posts %}
{% if post.post_img != None %}
<div class="carousel-item {% if loop.index == 1 %} active {% endif %}" id="slide{{ loop.index }}">
<img src="{{ url_for('static', filename='post_pics/' + post.post_img) }}">
</div>
{% endif %}
{% endfor %}
</div>
<a class="carousel-control-prev" href="#pageCarousel" role="button" data-slide="prev">
<span class="carousel-control-prev-icon bg-primary" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#pageCarousel" role="button" data-slide="next">
<span class="carousel-control-next-icon bg-primary" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>

Create a Bootstrap accordian for items in a python for loop

I am trying to create a Bootstrap accordian for a list of items in a Django database. When rendered, currently my code will only collapse and expand on the first item in the for loop. For other items, when I click on these the first item expands/collapses, not the item being clicked on. Looking for a solution please.
<div class="panel-group">
<div class="panel panel-default">
{% for issue in issues %}
<div class="panel-heading">
<div class="panel-title">
<a data-toggle="collapse" data-target="#collapse1"><h3><i class="fas fa-chevron-down"></i> {{ issue.title }}</h3></a>
</div>
</div>
<div id="collapse1" class="panel-collapse collapse">
<p><strong>Type: </strong>{{ issue.type }}</p>
<p class="issue-description"><strong>Description: </strong>{{ issue.description }}</p>
<p><strong>Requested By: </strong>{{ issue.requested_by }}</p>
<p><strong>Date Created: </strong>{{ issue.date_created }}</p>
<p><strong>Status: </strong>{{ issue.status }}</p>
<p><strong>Date Completed: </strong>{{ issue.completed_date }}</p>
<p><strong>Upvotes: </strong>{{ issue.upvotes }}</p>
</div>
{% endfor %}
</div>
</div>
Give your div unique id like <div id="collapse-{{ issue.pk }}" class="panel-collapse collapse"> and also reference it in data-target: data-target="#collapse-{{ issue.pk }}"

Using Django numeric variable in css

I'm trying to get a bootstrap progress bar to work, but I'm running into a problem. I want to get the progress bar width from a Django variable, I use the templates language for this. The problem is, HTML changes the float variable (i.e 32.54) to a string (i.e 32,54). I'm not sure why this happens (my guess is encoding) but the width attribute will not work if the variable is not a number.
To clarify, this is my code.
Views.py:
def details(request):
estudio = request.GET.get('estudio', '')
uni = request.GET.get('uni', '')
campus = request.GET.get('campus', '')
result = Titulaciones.objects.raw('SELECT * FROM tasas t INNER JOIN titulaciones tit on t.codigo_titulacion = tit.codigo_titulacion INNER JOIN impartida_en imp ON tit.codigo_titulacion = imp.codigo_titulacion INNER JOIN centros cent ON imp.codigo_centro = cent.codigo_centro WHERE cent.universidad = %s and tit.nombre = %s and cent.campus =%s', [uni, estudio, campus]);
return render(request, 'proyecto_uni/details.html', {'result':result})
(If I print here, the variable still shows as a number).
details.html:
{% extends "base.html" %}
{% block content %}
{% for foo in result %}
<ul class="nav nav-tabs">
<li role="presentation"><a href="#tab1" >General</a></li>
<li role="presentation">Asignaturas</li>
<li role="presentation">Resultados</li>
</ul>
<!-- TAB 1 -->
<div id="tab1">
<div class="panel panel-primary">
<!-- Default panel contents -->
<div class="panel-heading">{{foo.nombre}}</div>
<div class="panel-body">
<h4>Universidad:</h4>
<p>{{ foo.universidad }}</p>
<hr class="m-y-2">
<h4>Campus:</h4>
<p>{{ foo.campus }}</p>
<hr class="m-y-2">
<h4>Descripción:</h4>
<p>Aquí debería ir la descripción</p>
<hr class="m-y-2">
<h4>Nota de corte:</h4>
<p>{{ foo.nota_corte }}</p>
</div>
</div>
</div>
<!-- TAB 2 -->
<div id="tab2">
<p>tab2</p>
</div>
<!-- TAB 3 -->
<div id="tab3">
<div class="panel panel-primary">
<div class="panel-heading">{{foo.nombre}}</div>
<div class="panel-body">
<div class="progress">
<div class="progress-bar progress-bar-success" style="width: {{foo.rendimiento}}%">
<span class="sr-only">{{foo.rendimiento}}% Complete (success)</span>
<!-- The problem is right above, in the width style tag -->
</div>
<div class="progress-bar progress-bar-warning" style="width: 2%">
<span class="sr-only">22% Complete (warning)</span>
</div>
<div class="progress-bar progress-bar-danger" style="width: 1%">
<span class="sr-only">1% Complete (danger)</span>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
{% endblock%}
I posted all the code to make it easier to understand, hope I didn't make it more confusing. Anyways, thanks in advance!
Django formats numbers according to your localization settings. You can turn localization off by using:
{% load l10n %}
{% localize off %}
{{ foo.rendimiento }}
{% endlocalize %}
You can also unlocalize one single value:
{% load l10n %}
{{foo.rendimiento|unlocalize}}
Django format localization documentation

jijna2 for loop variable preservation?

I'm working on a web app and trying to add functionality where you make an anonymous post and then someone can add an answer to it. I'm using Flask for backend. I have the posts stored in an SQLAlchemy database. By default, a post doesn't have an answer. To dispay the posts, I just print each one with a for loop using jinja2. In that for loop, I also print an "answer" button after each post that brings up a Foundation modal that is supposed to let the user enter their answer. The problem is that the action attribute references the post ID ({{post.id}}), which by the end of the loop refers to the last post. Here's my code:
{% for post in s: %}
{% if post.nh == hood %}
<li>
<td> {{ post.date.strftime('%Y-%m-%d %H:%M:%S') }} </td>
<br>
<td> {{ post.text }} {{post.nh}} </td>
<br>
Answer
<div id="reply_modal" class="reveal-modal" data-reveal aria-labelledby="modalTitle" aria-hidden="true" role="dialog">
<p>{{ post.text }}</p>
<form action='/{{post.id}}/{{hood}}' method="post">
<div class="row">
<div class="large-12 columns">
<textarea placeholder="Write your answer here"name="user_input" required></textarea>
</div>
<div class="right">
<button type="submit">Submit</button>
</div>
</div>
</form>
<a class="close-reveal-modal" aria-label="Close">×</a>
</div>
<br>
{% if post.answer != 'none' %}
<li>
<div align="right">
<td> {{ post.answer }} </td>
</div>
</li>
{% endif %}
</li>
{% endif %}
{% endfor %}
I basically need to preserve {{post.id}} for each "answer" button so that the answer gets added to the correct post. I would appreciate any suggestions.

Categories