Flask - Delete image from static (boostrap card) - flask

I'm trying to create a functionnality where the user is able to upload and delete some images on the fly. The deleting part works but not completely... it successfully deletes an image from my static folder, but for some reason it only deletes the first image it finds, and not the one that linked to the bootrap card.
For some reason it is not properly identifying the correct value and I can't figure out why :
1. Flask
#app.route('/deleteImg', methods=['GET', 'POST'])
def deleteImg(row):
if request.method == 'POST':
image_to_del = request.values.get('image_to_del', None)
print(f'image_to_del:{image_to_del}')
os.remove(os.path.join(UPLOAD_FOLDER,image_to_del))
return redirect('/uploadimg')
return render_template('uploadimg.html')
2. HTML
<form action="{{url_for('deleteImg')}}" method="POST">
<div class="row">
{% for row in pics %}
<div class="col-md-3 mt-3">
<div class="card">
<img src="{{ url_for('static', filename='pics/'+row)}}" alt="{{row}}" class="card_img_top" height="200">
<input type="hidden" name="image_to_del" class="image_to_del" value="{{row}}">Filename : {{row}}</input>
<h5 class="text-cent" >Filename : {{row}}</h5>
</div>
<div class="card-footer text-center">
<input type="submit" value="Delete" class="btn btn-success" />
</div>
</div>
{% endfor %}
</div>
</form>

I found this solution for those who might be interested. This is based on the work of "Cairocoders" Flask delete image from db
1. FLASK
#app.route('/deletelogo/<string:get_ig>', methods=['GET', 'POST'])
def deletelogo(get_ig):
print(f'get_ig :{get_ig}')
os.remove(os.path.join(LOGO_FOLDER,get_ig))
return redirect('/logoimg')
2. HTML
<div class="row">
{% for row in pics %}
<div class="col-md-3 mt-3">
<div class="card">
<img src="{{ url_for('static', filename='logo/'+row)}}" alt="{{row}}" class="card_img_top" height="200">
<input type="hidden" name="image_to_del" class="image_to_del" value="{{row}}">Filename : {{row}}</input>
<h5 class="text-cent" >Filename : {{row}}</h5>
</div>
<div class="card-footer text-center">
<td><p><span class="glyphicon glyphicon-trash"></span></p></td>
</div>
</div>

Related

django returns MultiValueDictKeyError at / 'q'

django returns MultiValueDictKeyError at /
'q' in my dashboard template when I'm trying to add search functionality into my app. I want when a user type something on the search input to return the value that user searched for. but i endup getting an error when i try to do it myself.
MultiValueDictKeyError at /
'q'
def dashboard(request):
photos = Photo.objects.all()
query = request.GET['q']
card_list = Photo.objects.filter(category__contains=query)
context = {'photos': photos, 'card_list':card_list}
return render(request, 'dashboard.html', context)
<div class="container">
<div class="row justify-content-center">
<form action="" method="GET">
<input type="text" name="q" class="form-control">
<br>
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
</div>
</div>
<br>
<div class="container">
<div class="row justify-content-center">
{% for photo in photos reversed %}
<div class="col-md-4">
<div class="card my-2">
<img class="image-thumbail" src="{{photo.image.url}}" alt="Card
image cap">
<div class="card-body">
<h2 style="color: yellowgreen; font-family: Arial, Helvetica,
sans-serif;">
{{photo.user.username.upper}}
</h2>
<br>
<h3>{{photo.category}}</h3>
<h4>{{photo.price}}</h4>
</div>
<a href="{% url 'Photo-view' photo.id %}" class="btn btn-warning btn-
sm m-1">Buy Now</a>
</div>
</div>
{% empty %}
<h3>No Files...</h3>
{% endfor %}
</div>
</div>
try this
query = request.GET['q']
query = request.GET.get('q', '') # use get to access the q
The get() method returns the value of the item with the specified key.

How is it possible to get data from one form that has multiple textareas in Django

I'd like to get data from one form that has multiple textareas inside , In my views: 'compare_ingredients' I've tried requesting data from my form id 'compareform' also the textarea id 'ingredients', but when I enter something into one texture and click on submit it comes back as 'None' when I print. Here is my html and views:
html :
<div class="container-fluid">
<h4>Please enter in your ingredients:</h4>
<h6>(Seperate each item by comma)</h6>
<br>
<button class="add_item">Add Item</button>
<br>
<div class="row row-cols-1 row-cols-md-2 mx-auto">
<form action="{% url 'compare_ingredients' %}" method="POST" name="compareform" id="compare">
{% csrf_token %}
<br>
<button type="submit" class="btn btn-info sub_btn">Submit</button>
<button type="submit" class="btn btn-secondary back_button">
Back
</button>
<br>
<br>
<div class="row form_row">
<div class="col mb-4">
<h5>Item 1</h5>
<div class="card form_card">
<div class="card-body compare_cardbody">
<textarea name="ingredients1" id="ingredients" cols="30" rows="10" form="compareform"></textarea>
</div>
</div>
</div>
<div class="col mb-4">
<h5>Item 2</h5>
<div class="card form_card">
<div class="card-body compare_cardbody">
<textarea name="ingredients2" id="ingredients" cols="30" rows="10" form="compareform"></textarea>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
views.py:
def compare_ingredients(request):
if request.method == "POST":
ingredients = request.POST.get('compareform')
print(ingredients)
return render(request, 'result/compare.html')
ok, I figured it out , the problem was in the html textarea I had the name of the form as 'compareform' when it should have been 'compare' :
<textarea name="ingredients2" id="ingredients" cols="30" rows="10" form="compare"></textarea>
then in my views I did:
ingredients1 = request.POST.get('ingredients1')

How to delete multiple objects in django?

I am trying to delete django model multiple objects using html checkboxes but i can't. Kindly guide me what I need to do complete my this task.
I try the following code for this purpose but i failed.
views.py
class DeleteProducts(SuccessMessageMixin, View):
success_url = reverse_lazy('stock:stock')
success_message = "Products are deleted successfully."
def post(self, request, *args, **kwargs):
products = self.request.POST.getlist('product')
Product.objects.filter(pk__in=products).delete()
messages.success(self.request, self.success_message, extra_tags='alert-danger')
return redirect('stock:stock')
In template i used checkboxes prefectly or not??
template.html
<form method="POST" action="{% url 'stock:deleteproducts' %}">
{% csrf_token %}
{% for product in page_obj %}
<div class="row" >
<input type="checkbox" value="{{ product.id }}">
<div class="col-sm-2" >
<h5>{{ product.id }}</h5>
<img src="{{ product.Picture.url }}" height="120px" />
</div>
<div class="col-sm-4" >
<h5><u>Product Name</u>: {{ product.pro_name }}</h5>
<h6><u>Company Name</u>: {{product.companyName}}</h6>
<div class="row" >
<div class="col-sm" >
<p>Purchase Price: <b>{{product.Purchase_Price}}</b></p>
</div>
<div class="col-sm" >
<p class="pt-0">Sale Price: <b>{{product.Sale_Price}}</b> </p>
</div>
</div>
<div class="row" >
<div class="col-sm" >
<p>Quantity <b>{{product.Quantity}}</b></p>
</div>
<div class="col-sm" >
<p> Added By: <b>{{product.saler}}</b> </p>
</div>
</div>
</div>
<div class="col-sm-4" >
<p><b>Added Date</b>:{{ product.pub_date }}</p>
<hr/>
<center>
<a href="{% url 'stock:editproduct' product.id %}" class="btn btn-success" >Edit</a>
</center>
</div>
</div>
<hr/>
{% endfor %}
<input type="submit" class="btn btn-danger" value="Delete" >
</form>
urls.py
path('delete/', login_required(DeleteProducts.as_view(), login_url='login'), name='deleteproducts'),
You need to assign name="product" attribute to checkboxes since you are trying to get it with self.request.POST.getlist('product'):
<input type="checkbox" value="{{ product.id }}" name="product">

How can I pass an image ID from the view into my routes.py, when the images are displayed in the view via a for loop?

I'm building a simple portfolio website where the owner will be able to manage a gallery page, Adding, Editing and Removing posts. I am printing the images from the DB using a for loop and need a way in order to get either the name of the image or the ID of the image and send the value back to the route in order to delete the row from the DB. Any suggestion would be much appreciated.
Additional information:
Using Flask w/ SQLalchemy & WTforms
Sample of how I'm displaying the images and accompanying data:
{% for image in Posts | reverse %}
<div class="row pt-3">
<div class="col">
<img class="img-fluid rounded" src="static/gallery_images/{{image.image }}" alt="">
</div>
</div>
<div class="row pt-4">
<div class="col">
<h3 style="display: inline">{{image.title}}</h3>
<p class="font-italic text-muted" style="display: inline">
{% if image.sold_flag %}
- Sold
{% else %}
- Available
{% endif %}
</p>
<p class="text-muted">{{image.date_posted.strftime('%d/%m/%Y')}}</p>
</div>
</div>
<div class="row">
<div class="col">
<p class="font-weight-normal">{{ image.description }}</p>
</div>
</div>
<div class="row">
{% if current_user.is_authenticated %}
<div class="col text-left">
<button type="button" class="btn btn-dark">Edit</button>
<button type="button" class="btn btn-danger">Delete</button>
</div>
{% endif %}
</div>
<hr class="border">
{% endfor %}
There are multiple ways to store the id and use it for a route call. Using purely what you have shared, you can add a call to the button to the respective endpoints:
Assuming you have a method images.delete(id) to delete images and that you want to keep with the button tag on your code:
<a href={{url_for('delete.edit', id=image.id)}}>
<button type="button" class="btn btn-dark">
Delete
</button>
</a>
However, I would really recommend for you to use a form to submit the delete, as opposed to a GET request generated above. This way you can have it secured with WTForm CSRF token.
Example:
HTML
<form action="{{url_for('delete.edit', id=image.id)}}" method="POST" role="form">
{{ form.hidden_tag() }}
</form>
Python
## Make sure to create the delete form
class DeleteImage(Form):
pass

Flask url_for could not build endpoint based on working code. Asks if I want index?

My Flask app already serves up several pages. I just made channels.html. For a route, I copied down and changed /messages, which already works. I then tried adding a link from messages.html to channels.html, but received the error: Could not build url for endpoint 'channels'. Did you mean 'index' instead? The error references the line Channels in messages.html. I checked spelling, syntax, decorator placement, and duplicative names; everything looks ok. Plus, the new code was built off of code that was previously tested.
So, why the error?
#app.route('/channels', methods=["GET", "POST"])
def channels():
return render_template("channels.html")
#app.route('/messages', methods=["GET", "POST"])
def messages():
return render_template("messages.html")
messages.html (top part)
{% extends "layout.html" %}
{% block body %}
<div class="container">
<div class="row" style="min-height: 100vh">
<div class="col-md-3 border border-danger rounded">
<div class="row mt-2 justify-content-start">
Header
</div>
<!-- <div class="row mt-2 justify-content-start" id="channelHeader">
Channels
</div>-->
<div class="row mt-2 justify-content-start" id="channels">
Channels
</div>
<div class="row justify-content-start" id="dmsg">
Direct Messages
</div>
</div>
<div class="col-md-9 border border-danger rounded">
{% endblock %}
channels.html
{% extends "layout.html" %}
{% block body %}
<div class="container">
<div class="display-3">
<strong>Create A Channel</strong>
</div>
<form action="{{ url_for('channels') }}" id="channelForm" class="mt-4">
<!-- Will need check for duplicate email -->
<div class="form-group">
<label for="channelName">Channel Name</label>
<input type="text" class="form-control" id="channelName" aria-describedby="channelName" placeholder="Enter Channel Name">
</div>
<!-- Will need check for duplicate username -->
<div class="form-group">
<label for="inviteUsers">Invite Other Users (optional)</label>
<input type="text" class="form-control" id="inviteUsers" aria-describedby="inviteUsers" placeholder="Search by name">
</div>
<div class="form-group">
<label for="purpose">Purpose</label>
<textarea type="text" class="form-control" id="purpose" rows="3" placeholder="Purpose">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
{% endblock %}