load dynamic data in html modal in Django - python

I have single html page with dynamic images from database in Django.
I also have a modal in the same page set to invisible and opens when image is clicked.
My intension is when I click on any image it should open a html model with the clicked image and its description text from db.
How do I display data of the current clicked image and its description.
I have tried to pass {{profile.image.url}} but this gives one information on click to all images.
I didn't have to give sample code on this.

You can achieve this by passing the id of the object you want to retrieve using AJAX request.
Let's suppose, this is your HTML table
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>Title</th>
<th>Date</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for incident in page_obj %}
<tr>
<td>{{ incident.id }}</td>
<td>{{ incident.title }}</td>
<td>{{ incident.created }}</td>
<td>
<span class="badge badge-pill badge-success">{{ incident.get_status_display }}</span>
</td>
<td>
<button class="btn btn-sm btn-outline-info" onclick="populateForm('{{ incident.id }}')" data-toggle="modal" data-target="#incidentModal">Edit</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
Use this type of function according to your model and fields
function populateForm(id) {
$.ajax({
url: "{% url 'incidents:update' 1 %}".replace("1", id),
type: "GET",
success(response) {
let incident = JSON.parse(response)[0].fields;
$("#id_title").val(incident.title);
$("#id_description").val(incident.description);
$("#id_responder").val(incident.responder);
$("#id_status").val(incident.status);
$("#id_functional_impact").val(incident.functional_impact);
$("#id_information_impact").val(incident.information_impact);
$("#id_recovery_impact").val(incident.recovery_impact);
},
});
}
views.py
from django.core import serializers
from django.http import JsonResponse, Http404
from django.views.generic import UpdateView
from incidents.models import Incident
from incidents.forms import IncidentForm
class IncidentUpdateView(UpdateView):
form_class = IncidentForm
model = Incident
def get_success_url(self):
return reverse('incidents:list')
def get(self, request, pk):
if request.is_ajax():
incident = get_object_or_404(Incident, pk=pk)
response = serializers.serialize("json", [incident])
return JsonResponse(response, safe=False)
raise Http404('Page not found')

There are 2 options on how to achieve this:
render modals for all images with django and open them when user clicks one of the images.
create 1 modal and write some javascript to fetch information about the clicked image in the background. Note, that you'll also need to create an endpoint in Django that will accept image ID and return image information.

Related

How to render multiple update forms in Django

here is my problem.
I have a list of objects that I display in a table and all works just fine except that I would like to edit them inside a modal and submit them using AJAX.
I though that it was a simple idea to render, for each row, a form with the inputs pre-filled and then submit the selected form with AJAX.
I wonder if there is a relatively simplified way to render the UpdateForm without writing manually all the input fields.
Something like this:
<table>
{% for transaction in transactions %}
<tr>
<td>{{ transaction.date|date:"d.m.Y" }}</td>
<td>{{ transaction.amount }}</td>
<td>
Edit
<div class="modal" id="edit{{ transaction.id }}">
{{ transaction_form }}
</div>
</td>
<tr>
{% endfor %}
</table>
But how can I pass the form from the view?
The way I'm currently doing it is that when the user click on edit the page refresh and the modal is displayed with the form prefilled but it is (a) slow to open and (b) I don't think it is a nice way to do it.
This is my current code
views.py
class ProjectDetailView(DetailView):
model = Project
template_name = "template.html"
context_object_name = "project"
def get_transactions(self):
transactions = Transaction.objects.filter(project=self.get_object())
return transactions
def get_transaction_form(self):
form = TransactionForm()
if self.request.POST:
form = TransactionForm(self.request.POST)
elif 'edit_entry' in self.request.GET:
form = TransactionForm(instance=self.get_entry())
return form
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['transactions'] = self.get_transactions()
context['transaction_form'] = self.get_transaction_form()
return context
template.html
<table>
{% for transaction in transactions %}
<tr>
<td>{{ transaction.date|date:"d.m.Y" }}</td>
<td>{{ transaction.amount }}</td>
<td>
Edit
</td>
<tr>
{% endfor %}
</table>
<div class="modal" id="edit-modal">
{{ transaction_form }}
</div>
<script>
{% if 'edit_entry' in request.GET %}
$('#edit-modal').modal('show')
{% endif %}
</script>
Thank you for any feedback
This solution needs you work with Javascript to do that,
when the user clicks 'Edit' for an object on your page,
you send AJAX request (using Fetch API or Jquery) to your view,
The view will return HTML of the form and you put this HTML in the modal's body
Show the modal with an action button to submit the form.
As the user clicks submit, your code submits the form through Ajax, you can use Formdata or AjaxForm for that, the view which return an JSON or HTML which indicates if the data is saved successfully or not.
The problem I'm not a Class-Based View guy so I can't give you specifics from Django side.

Not able to delete an account on a login page made using flask

I'm trying to make a simple login page using python flask and MySQL. The webpage itself is being made using html, bootstrap 4 and css. I followed a tutorial to make the login page but now I want to add a way to delete an account.
This is a profile page which is visible after you login(it shows your username, password and email). The database table(called accounts) has a primary key id. The part in /// is the code I'm trying to add for creating a delete button. Please help me fix my delete account button.
#app.route('/pythonlogin/profile', methods = ['GET'])
def profile():
# Check if user is loggedin
if 'loggedin' in session:
# We need all the account info for the user so we can display it on the profile page
cursor = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
cursor.execute('SELECT * FROM accounts WHERE id = %s', (session['id'],))
account = cursor.fetchone()
# Show the profile page with account info
return render_template('profile.html', account=account)
# User is not loggedin redirect to login page
///if request.method == 'GET':
id = session['id']
mycursor = mysql.cursor()
sql = ('DELETE from accounts WHERE id = 4;')
# return redirect(url_for('logout)')
mycursor.execute(sql)
mysql.connection.commit()///
return redirect(url_for('login'))
The following is the html part called profile.html.
{% extends 'layout.html' %}
{% block title %}Profile{% endblock %}
{% block content %}
<h2>Profile Page</h2>
<div>
<p>Your account details are below:</p>
<table>
<tr>
<td>Username:</td>
<td>{{ account['username'] }}</td>
</tr>
<tr>
<td>Password:</td>
<td>{{ account['password'] }}</td>
</tr>
<tr>
<td>Email:</td>
<td>{{ account['email'] }}</td>
</tr>
<tr>
<form action="{{ url_for('logout') }}">
<td>
<button type="submit" class="btn btn-danger">Delete Account</button>
</td>
</form>
</tr>
</table>
</div>
{% endblock %}
In the provided code I can see some mistakes (logical)
If use logged in, code after return render_template('profile.html', account=account)
will not be executed
And another problem is that you are creating the URL to logout instead of the profile page <form action="{{ url_for('logout') }}">
And better to do the form with POST method.

how to get value of download button into my django view?

I have a download button in my HTML that has a href to a path on my system for the corresponding file. How can I load that path into my view when at user clicks download? Also this value is unique for each download button.
If there's any other way that I can do this without exposing my system path in the href I would much prefer to know that. Thanks in advance.
Right now I have some HTML that looks like this. How do I grab the info from item.OutputPath into my view when clicked?
<div class="dashboard-2">
<div class="tasks-finished">
<h1>Finished tasks</h1>
</div>
<div class="tasks-list">
<table>
<tr>
<th>Name</th>
<th>Task ID</th>
<th>Status</th>
</tr>
{% for item in query_finished %}
<tr>
<td>{{ item.TaskNavn }}</td>
<td>{{ item.TaskID }}</td>
<td>Download </tr>
{% endfor %}
</table>
</div>
</div>
Additonal info:
I need this value because i'm trying to save it as a variable to serve protected files using Nginx.
Exposing the system path is a bad idea in itself, but using it as an input parameter would be a huge security risk.
It is better to pass the id of your item to your download view. Something like this:
# template
<td>Download</tr>
# urls.py
path('download/<int:pk>/', views.download_item, name='item-download'),
# views.py
def download_item(request, pk):
# Make sure to perform any required checks, e.g. item.owner=request.user
item = get_object_or_404(Item, pk=pk)
output_path = item.OutputPath
...

How to add forms to a dictionary upon submission

I am creating a shopping cart as a part of the application I'm building.
I am trying to figure out how to add a form submission to a dictionary (I think this is what I need to do).
So for example this is what the page would look like(This is just test data).
Upon Clicking the add button I want the item name and price to populate in the Orders table to the right of the Pricing table(To start off). Once all orders have been added I'd click the Order button and that will order the added items in some type of list to the database using sqlalchemy. Now I feel strongly and I may be wrong that upon submitting form using add button that the form needs to be added to a dictionary. I just don't know how to save that dictionary and where that dictionary should be stored? Here is my code as of now.
routes.py
I tried putting the dictionary with in the route function but a single instance is created on each submission. So nothing is really being saved to dictionary.
#app.route('/equipment', methods=['POST', 'GET'])
def equipment():
form = OrderEquipmentForm()
eq = equipment_prices
# Tried to store forms in this dictionary but it look like a new instance
# is created on every form submission
ordersss = {}
if form.validate_on_submit():
ordersss[form.Type.data] = form.Price.data
print(form.Type.data, form.Price.data)
print(ordersss)
return redirect(url_for('equipment'))
return render_template('equipment.html', name='equipment', eq=eq, form=form)
#app.route('/equipment/cart', methods=['GET, POST'])
def cart():
return render_template('cart.html', name='cart')
Forms.py
Not sure if there needs to be function with in the actual form that adds the values to a dictionary
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
class AddEquipmentForm(FlaskForm):
Type = StringField('Type of Equipment',DataRequired())
Price = StringField('Price',DataRequired())
submit = SubmitField('Add equipment')
class OrderEquipmentForm(FlaskForm):
Type = StringField()
Price = StringField()
Order = SubmitField('Order')
# Should Dictionary go here?
# Not sure
def dict():
dict = {}
dict[Type] = Price
equipment.html
I would like to loop the element of the dictionary with in the Orders Table, if a dictionary is needed.
{% extends 'base.html' %}
{% block content %}
<div class="row">
<div class="col-6-sm">
<h1>Pricing</h1>
<table class='border'>
<thead class='border'>
<th style="width:200px;">Equipment</th>
<th style="width:200px; text-align:center;">Price</th>
<th></th>
</thead>
{% for quip in eq %}
<form method="post">
{{ form.hidden_tag() }}
<tr class ='border'>
<td>{{ quip }}</td>
<td style="text-align:center;"> <strong>${{ eq[quip] }}</strong></td>
<!-- Here I'm adding StringFields from the form but hiding them so they aren't displayed so I can submit the data somehow, hopefully to a dictionary. -->
<td style="display:none;">{{ form.Type(value=quip)}}</td>
<td style="display:none;">{{ form.Price(value=eq[quip]) }}</td>
<td><button class='btn btn-primary' type="submit">Add</button></td>
</tr>
</form>
{% endfor %}
</table>
</div>
<div class="col-6-sm">
<h1>Orders</h1>
<table>
<!-- This is where a loop of the dictionary elements of the items added would go -->
<tr>
<td></td>
<td></td>
</tr>
<button style='float:right' type="button" name="button" class='btn btn-info'>Order</button>
</table>
</div>
</div>
{% endblock %}

flask with many buttons and database update

I am trying to make a web app like a mini-tweets. The posts are pulled out from a database and I want to have an 'up vote' button for each post, like the following picture.
Each post has an id, author, body, and likes property. When an up vote is clicked, the likes property needs to be updated.
My question is how to determine which button is clicked. What would be a good strategy in this case for the route() function and the html template?
I was thinking of adding a name to each button and put post.id in the name, then check if request has it. But the number of posts are not known before hand, how should I write the request check in route() function?
My current template is as follows
<table class="table table-striped">
{% for post in posts %}
<tr>
<td> {{ post.id }} </td>
<td> <img src="{{ post.author.avatar(50) }}"> </td>
<td> <b>{{ post.body }}</b> </td>
<td> <button type="button" name='{{'up.'+ post.id|string}}' class="btn btn-default">
<span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span>
</button>
{{ post.likes}} </td>
</tr>
{% endfor %}
</table>
and the current route() is like this
#bbs.route('/', methods=['GET', 'POST'])
def index():
posts = Post.query.all()
return render_template('bbs/index.html', posts=posts)
A clean way to do that would be to add a data attribute, in your button tag and do one ajax request per upvote / downvote.
https://developer.mozilla.org/en/docs/Web/Guide/HTML/Using_data_attributes
In your case, it would be called data-id.
Then in your javascript, when the button is clicked, get this data attribute value, and craft your url as such :
/upvote/<data-id>
And call it using an ajax GET request (so the page doesn't refresh).
Now on flask side get the id as such :
#app.route('/upvote/<post_id>')
def upvote(post_id):
print('%s upvoted' % post_id)
# do your db update here and return a json encoded object
And on javascript side again, when you get your answer from flask, update your button accordingly.
Assuming you put another class in your upvote button for instance : upvote_button and you use jQuery, your javascript could look like that :
<script type='text/javascript'>
$('.upvote_button').click(function(ev){
var id = $(ev.currentTarget).attr('data-id');
$.get( "/upvote/" + id, function( data ) {
// change your button here, and remove its upvote_button class
alert(data);
});
});
</script>

Categories