So I have a for loop in my Django template that loops through a product in my products model. The product model has an amount attribute that is supposed to change when the user clicks on the 'add' button. I have made a hidden form that launches the upvote method which takes a request and a pk and increases the amount attribute by 1.
The problem is that when I click on the add button, only two of the products' amount increase. I can't get the rest of the products' amount attribute to increases.
Here's the Django template code:
<div class="card-deck d-flex justify-content-start container-fluid">
{% for product in products %}
<div class="card lead m-3" style="min-width: 18rem;">
<div class="card-body">
<h5 class="card-title">{{ product.name }}</h5>
<h6 class="card-subtitle mb-2 text-muted">{{ product.product_id }}</h6>
<hr>
<p class="card-text">
Expiration date: {{ product.expiration_date }}
</p>
<p class="card-text">
amount: {{ product.amount }} <button class="btn btn-primary btn-sm">+</button>
</p>
<p class="card-text">
tags:
{% for t in product.tag.all %}
<span class="badge badge-primary">{{ t.name }}</span>
{% endfor %}
</p>
</div>
</div>
<form action="{% url 'upvote' pid=product.id %}" method="POST" id="upvote">
{% csrf_token %}
<input type="hidden">
</form>
here's the upvote method in the views.py file:
def upvote(request, pid):
if request.method == "POST":
product = get_object_or_404(models.Product, pk=pid)
product.amount += 1
product.save()
return redirect('home')
You end up having multiple elements with the same id (upvote) which is not allowed, and the Javascript code always uses the first form element it finds and submits that one.
To have unique form ids, change the following line
<form action="{% url 'upvote' pid=product.id %}" method="POST" id="upvote">
to
<form action="{% url 'upvote' pid=product.id %}" method="POST" id="upvote_{{ product.id }}">
and the following line
<a href="javascript:{document.getElementById('upvote').submit();}">
to
<a href="javascript:{document.getElementById('upvote_{{ product.id }}').submit();}">
Related
I'm completely lost on part of my Django website. I finally figured out a way to have the same model create a template and then use that template and create another post. This works and is ideal. Now I need to put them in different locations on the screen so I basically need two for-loops and a way to decipher the two(templates and posts off of templates) apart from each other. The model has a title and a content field. When a template is created the title always starts with "Temp: ". I'm completely lost on this because I need to parse through the model and not just use an HTML parser because the content won't already be on the page and there is more than just the title that needs to be moved. I need a way I think in the views.py file to get the pk of ALL titles that start with "Temp: " and the content field tied with it and return it in a variable to the HTML file. I have been working on this for 3 days now and I just really need help.
views.py
def docpostlistview(request):
field = DocPost.objects.all()
return render(request, 'my_app/docpost_list.html', {'field': field})
HTML
<div class="blocks">
<div class="row">
<div class="col">
TESTESTESTESTESTESTESTES
</div>
{% if user.Doc.all %}
{% for post in user.Doc.all %}
<div class="col">
<div class="card card_template hoverable">
<div class="card-image">
<a href="{% url 'use_template' pk=post.pk %}" style="color: black">
<p>
{{ post.content|safe }}
</p>
</a>
</div>
<div class="card-content">
<p>
</p>
</div>
<div class="card-action">
<div class="bottom_text">
{{ post.title }}
<div class="bottom_button">
<form action="{% url 'use_template' pk=post.pk %}" method="POST">
{% csrf_token %}
<div class="card-body">
<a style="background-color: #2f3d50; border-radius: 18px; height: 30px; position: relative; top: 5px;" href="{% url 'use_template' pk=post.pk %}" class="btn btn-primary"><div style="position: relative; top: -3px;">Create</div></a><!--use_template pk=post.pk - post-list-->
</div>
</form>
</div>
</div>
</div>
</div>
<div class="wrapper">
<ul>
<li><a class="dots_img"> <img src="{% static 'threedots.png' %}" alt=""</a>
<ul>
<div class="edit_drop">
<form action="{% url 'doc-post-update' pk=post.pk %}" method="POST">
{% csrf_token %}
<div class="card-body">
<a style="background-color: #2f3d50; border-radius: 18px;" href="{% url 'doc-post-update' pk=post.pk %}" class="btn btn-primary">EDIT</a>
</div>
</form>
</div>
<div class="delete_drop">
<a style="background-color: #2f3d50; border-radius: 18px;" href="{% url 'delete_post' pk=post.pk %}" class="btn btn-danger">Delete</a>
<!--<form action="{% url 'reset' %}" method="POST">{% csrf_token %}
<button type="submit" class="btn btn-danger">Delete</button>
</form>-->
</div>
</ul>
</li>
</ul>
</div>
</div>
{% endfor %}
<hr class="hline">
{% else %}
<div class="no_template">
<p>Your new templates will appear here!</p>
</div>
<div class="no_post">
<p>Your new documents will appear here!</p>
</div>
<hr class="hline-non">
{% endif %}
<div class="blocks2">
<div class="row">
You might be interested in field lookups which utilizes the SQL WHERE clause.
https://docs.djangoproject.com/en/3.2/ref/models/querysets/#startswith
https://docs.djangoproject.com/en/3.2/ref/models/querysets/#field-lookups
https://docs.djangoproject.com/en/3.2/topics/db/queries/#field-lookups
Sample:
doc_posts = DocPost.objects.filter(title__startswith="Temp: ")
Here, doc_posts is an iterable QuerySet object containing a sequence of DocPost objects where each item's title starts with "Temp: ".
If all you want are the id and the content fields, you may use values().
https://docs.djangoproject.com/en/3.2/ref/models/querysets/#values
Sample:
id_content_seq = DocPost.objects.filter(title__startswith="Temp: ").values("id", "content")
Here, id_content_seq is an iterable QuerySet object containing a sequence of dict objects containing id and content as keys for all items where the title starts with "Temp: ".
I am trying to get a value from template to views.py of a django project. I am able to get the value of name="city" correctly but unable to get the exact value of name="category" in my views, instead I am getting the first element value for all the other elements in the loop. An idea to solve this will be very much helpful.
#category.html
{% for test in mytypes %}
<form id="myform" action="{% url 'my_city_category' %}" method="POST">
{% csrf_token %}
<a href="javascript: submitform()">
<div class="col-6 col-lg-3 col-md-4 col-sm-6 col-xl-2 hover-box mt-2 text-center">
<div class="pb-1 pt-2">
<img src="{{test.icon_image.url}}" width="100"/>
<h6 class="mt-3 text-body text-capitalize text-decoration-none">{{ test.category_type }}</h6>
<input type="hidden" name="category" value="{{ test.category_type }}"># unable to repeat the value while calling it in the views, stuck at the first value
<input type="hidden" name="city" value="{{ city }}"> #rendering the exact value
</div>
</div>
</a>
</form>
{% empty %}
<h6 class="mt-3 text-body text-capitalize text-decoration-none">No Categories Listed</h6>
{% endfor %}
#views.py
def City_specific_page(request):
city = request.POST.get('city')
category = request.POST.get('category')
business= Business.objects.filter(city__City=city, type__category_type=category)
return render(request, 'community_app/type_detail_city.html',{'business':business,'category':category,'city':city})
#urls.py
path('City', views.City_specific_page, name='my_city_category'),
Each <form> in your template includes the following tag:
<a href="javascript: submitform()">
I suspect that your submitform function is submitting the first form on the page, rather than the one that was clicked.
You can quickly determine if this is the problem by adding a submit button inside your <form> tags. Make sure it's not inside the <a> tags, eg:
<form id="myform" action="{% url 'my_city_category' %}" method="POST">
{% csrf_token %}
<button type="submit">Test</button>
<a href="javascript: submitform()">
<!-- the rest of your form code -->
Click the button labelled 'Test' to see if the correct form data is submitted.
I am creating a form to find other group members, where all members belongs to departments. Some department, but not all, departments have an internal id that can be used to identify each member. Each department also has a different term for this internal member id. Department A calls it "personal identifier," department B calls it "unique id," etc. In the database departments table, the member_id_term field stores what the department calls the internal member id. In the members table in the database, the internal_id stores the member's internal_id if they belong to a department with the internal_id system.
On the first page of the form, the user selects the department, and on the second page of the form, if the user has selected a department that uses internal member ids, they are asked to put the internal member id.
My strategy was to create a variable in views.py called member_id_term and set it to 0 if there is no form.dept.data, but to set member_id_term to form.dept.data.member_id_term when form.dept.data exists. Then, in input_find_member.html, I would conditionally display the input field for internal_id if member_id_term exists.
Problem: I don't have access to form.dept.data until I submit the form. How can I access this value before submitting the form?
Here is the code I currently have. It throws an error on member_id_term = 0 if not form.dept.data else form.dept.data.member_id_term and says that form.dept.data is none.
forms.py
class FindMemberForm(Form):
name = StringField(
'name', default='', validators=[Regexp('\w*'), Length(max=50),
Optional()]
)
internal_id = StringField('internal_id', default='', validators=[Regexp('\w*'), Length(max=55)])
dept = QuerySelectField('dept', validators=[DataRequired()],
query_factory=dept_choices, get_label='name')
views.py
#main.route('/find', methods=['GET', 'POST'])
def get_officer():
form = FindMemberForm()
member_id_term = 0 if not form.dept.data else form.dept.data.member_id_term
if form.validate_on_submit():
return redirect(url_for('main.get_gallery'), code=307)
return render_template('input_find_member.html', form=form)
{% extends "base.html" %}
{% block content %}
and here is input_find_member.html
<div role="main">
<div class="hero-section no-sub">
<div class="hero">Find a Member </div>
</div>
</div>
<div class="container" role="main">
<form action="{{ url_for('main.get_member') }}" method="post" class="form">
{{ form.hidden_tag() }}
<div class="row form-group">
<div class="col-xs-12">
<ul class="nav nav-pills nav-justified thumbnail setup-panel">
<li class="active"><a href="#step-1">
<h4 class="list-group-item-heading">Step 1</h4>
<p class="list-group-item-text">Department Information</p>
</a></li>
<li class="disabled"><a href="#step-2">
<h4 class="list-group-item-heading">Step 2</h4>
<p class="list-group-item-text">Member Info </p>
</a></li>
</ul>
</div>
</div>
<div class="row setup-content" id="step-1">
<div class="col-xs-12">
<div class="col-md-12 well text-center">
<h2><small>Select Department</small></h2>
<div class="input-group input-group-lg col-md-4 col-md-offset-4">
{{ form.dept(class="form-control") }}
</div>
{% for error in form.dept.errors %}
<p>
<span style="color: red;">[{{ error }}]</span>
</p>
{% endfor %}
<br>
<button id="activate-step-2" class="btn btn-primary btn-lg">Next Step</button>
</div>
</div>
</div>
<div class="row setup-content" id="step-2">
<div class="col-xs-12">
<div class="col-md-12 well text-center">
<h2><small>Do you know the member's name?</small></h2>
<div class="input-group input-group-lg col-md-4 col-md-offset-4">
{{ form.name(class="form-control") }}
{% for error in form.name.errors %}
<p><span style="color: red;">[{{ error }}]</span></p>
{% endfor %}
</div>
{% if member_id_term %}
<h2><small>Do you know the member's {{ member_id_term }}?*</small></h2>
<div class="input-group input-group-lg col-md-4 col-md-offset-4">
{{ form.internal_id(class="form-control") }}
{% for error in form.internal_id.errors %}
<p><span style="color: red;">[{{ error }}]</span></p>
{% endfor %}
</div>
{% endif %}
<br>
<button id="activate-step-3" class="btn btn-primary btn-lg">Next Step</button>
</div>
</div>
</div>
</form>
</div>
I've already read these pages
Flask WTForms: how do I get a form value back into Python?
Get data from WTForms form
populate WTForms select field using value selected from previous field
Thanks for reading!
I'm trying to figure out a way to delete pictures I've uploaded to a carousel in django. Does anyone have a solution to this? I can't find any online examples that are clear to me. You can assume I have imported everything, and that all models, etc. are correct.
My code is below:
carousel.html:
{% load staticfiles %}
{% load filename %}
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="myCarousel" class="carousel slide" data-ride="carousel">
<div class="carousel-inner" role="listbox">
{% for document in documents %}
<div class="item {% if forloop.first %} active {% endif %}">
<div class="row">
<div class="col">
<li>{{document.docfile.name}}</li>
<img src = "{{STATIC_URL}}img/{{document|filename}}" >
<p align="center"><form style="text-align:center" action="{% url 'webportal:delete' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.non_field_errors }}</p>
<p>{{ form.Document.label_tag }} {{ form.docfile.help_text }}</p>
<p>
{{ form.Document.errors }}
{{ form.Document }}
</p>
<p><input type="submit" value="Delete" /></p>
</form></p>
</div>
</div>
</div>
{% endfor %}
</div>
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
<span class="glyphicon glyphicon-chevron-right"></span>
<span class="sr-only">Next</span>
</a>
</div>
<!-- /.carousel -->
</div>
</div>
<form action="{% url 'webportal:carousel' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.non_field_errors }}</p>
<p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>
<p>
{{ form.docfile.errors }}
{{ form.docfile }}
</p>
<p><input type="submit" value="Upload" /></p>
</form>
</div>
Views.py
def delete(request, my_id):
Deleted=get_object_or_404(Document, docfile=my_id)
if request.method=='POST':
form=DeleteForm(request.POST, instance=Deleted)
if form.is_valid():
Deleted.delete()
return HttpResponseRedirect('http://127.0.0.1:8000/alzheimers/')
else:
form=DeleteForm(instance=Deleted)
return render_to_response(
'webportal/index.html',
{'documents': documents, 'form': form,},
context_instance=RequestContext(request)
)
# Redirect to the document list after POST
def carousel(request):
# Handle file upload
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
newdoc = Document(docfile = request.FILES['docfile'])
newdoc.save()
# Redirect to the document list after POST
return HttpResponseRedirect('http://127.0.0.1:8000/alzheimers/')
else:
form = DocumentForm() # A empty, unbound form
# Load documents for the list page
documents = Document.objects.all()
#documents=DocumentForm().
# Render list page with the documents and the form
return render_to_response(
'webportal/index.html',
{'documents': documents, 'form': form,},
context_instance=RequestContext(request)
)
You don't wanna handle too much in one view. You could, but it makes ugly hard to maintain code. Better add a separate view for deleting. With this in your template loop.
<a href='{% url 'delete_document' pk=document.pk %}'>delete</a>
Then add a new url pattern with a pk argument:
url(r'^document/delete/(?P<pk>\d+)/$', "delete_document", name="delete_document"),
And a view like:
def delete_document(request, pk):
try:
Docuent.objects.get(pk=pk).delete()
except Document.DoesNotExist:
pass
return HttpResponseRedirect(...)
I am using Flask with WTforms. I am also using the WTFRecaptcha plugin in order to use Captcha fields.
Turns out I need to use two forms on the same page. When I assign a captcha field on each form, one of the captchas is not rendered on the .html page. This is because the captcha is ALWAYS created with the same ID:
Captcha and forms declaration on my forms.py file:
from wtforms import PasswordField, StringField, validators, widgets, RadioField
from wtforms.form import Form
from wtfrecaptcha.fields import RecaptchaField
class FirstForm(Form):
"""First Form"""
#Omitting fields here
captcha_1 = RecaptchaField('Captcha', [], public_key='OMITTING_PUBLIC_KEY', private_key='OMITTING_PRIVATE_KEY', secure=True)
class Secondform(Form):
"""Second Form"""
#Omitting fields here
captcha_2 = RecaptchaField('Captcha', [], public_key='OMITTING_PUBLIC_KEY', private_key='OMITTING_PRIVATE_KEY', secure=True)
Route declaration:
#!/usr/bin/env python
from flask import Flask, render_template, request
from flask.ext.assets import Environment
from forms import FirstForm, SecondForm
from flask import request
from flask import jsonify
#app.route('/test')
def test_form():
"""Test."""
form_1 = FirstForm(request.form, captcha_1={'ip_address': request.remote_addr})
form_2 = SecondForm(request.form, captcha_2={'ip_address': request.remote_addr})
if request.method == 'POST' and (form_1.validate() or form_2.validate()) :
return "Instructions have been sent to your e-mail"
return render_template(
'test-form.html',
title='Get Started',
form_1=form_1,
form_2=form_2
)
test-form.html
{% extends "base.html" %}
{% block content %}
<div class="container block-form">
<div class="row first">
<div class="col-xs-12 col-md-7 border-right">
<h1 class="title">{{ title }}</h1>
<p>{{ description }}</p>
<div class="form-area">
<form method="post">
{% for field in form_1 %}
<div class="form-group{% if field.errors %} has-error has-feedback{% endif %}">
<div class="row">
<div class="col-xs-12 col-md-4">
{{ field.label(class="control-label") }}
</div>
<div class="col-xs-12 col-md-8">
{{ field(class="form-control") | safe }}
</div>
</div>
{% if field.errors %}
<span class="glyphicon glyphicon-remove form-control-feedback"></span>
{% endif %}
{% for error in field.errors %}
<p class="help-block text-danger">
<span class="glyphicon glyphicon-remove"></span>
{{ error }}
</p>
{% endfor %}
</div>
{% endfor %}
<br>
<button type="submit" class="btn btn-gradient">Submit</button>
</form>
</div>
</div>
</div>
<div class="row second">
<div class="col-xs-12 col-md-7 border-right">
<h1 class="title">{{ title }}</h1>
<p>{{ description }}</p>
<div class="form-area">
<form method="post">
{% for field in form_2 %}
<div class="form-group{% if field.errors %} has-error has-feedback{% endif %}">
<div class="row">
<div class="col-xs-12 col-md-4">
{{ field.label(class="control-label") }}
</div>
<div class="col-xs-12 col-md-8">
{{ field(class="form-control") | safe }}
</div>
</div>
{% if field.errors %}
<span class="glyphicon glyphicon-remove form-control-feedback"></span>
{% endif %}
{% for error in field.errors %}
<p class="help-block text-danger">
<span class="glyphicon glyphicon-remove"></span>
{{ error }}
</p>
{% endfor %}
</div>
{% endfor %}
<br>
<button type="submit" class="btn btn-gradient">Submit</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
Code rendered for captcha in form_1 (Up to the div element):
<script src="https://www.google.com/recaptcha/api/challenge?k=6LeCJvUSAAAAAAvqwJEueVdV0wyNLPtX6KWSTdXp" type="text/javascript">
//Other code here omitted
<script src="https://www.google.com/recaptcha/api/js/recaptcha.js" type="text/javascript">
//Other code here omitted
<div id="recaptcha_widget_div" class=" recaptcha_nothad_incorrect_sol recaptcha_isnot_showing_audio">
Code rendered for captcha in form_2 (Up to the div element):
<script type="text/javascript" src="https://www.google.com/recaptcha/api/challenge?k=6LeCJvUSAAAAAAvqwJEueVdV0wyNLPtX6KWSTdXp">
<script type="text/javascript" src="https://www.google.com/recaptcha/api/js/recaptcha.js"/>
<div id="recaptcha_widget_div" style="display: none;"/>
<noscript><iframe src="https://www.google.com/recaptcha/api/noscript?k=6LeCJvUSAAAAAAvqwJEueVdV0wyNLPtX6KWSTdXp" height="300" width="500" frameborder="0"></iframe>
<br> <textarea name="recaptcha_challenge_field" rows="3" cols="40"> </textarea> <input type="hidden" name="recaptcha_response_field" value="manual_challenge"></noscript>
RESULT: Only one captcha is shown.
... Therefore if I have two captcha fields (Possible on two different forms), one won't display.
Any solutions/suggestions?
This is well a well documented limitation of Recaptcha
Currently, the Google captcha mechanism offer only one captcha form per page
I would encourage you to rethink the way you are organizing your page. Forms in HTML are simple by design. Most of the tooling built around them assumes that a page does one thing and submits the result to the server in a single form submission.
Disclaimer: I don't really know anything about your code. Proceeding regardless: it smells like your design might be a too clever. What I mean by this is that if you haven't seen it done somewhere else and google's tooling doesn't support it the issue is probably with your approach.
If you need to commit the result of a single stateless transaction then a <form> is appropriate and WTForms is a great tool to generate it. If you need something richer you might consider the following:
Break your forms out into multiple pages. A simple set of hyperlinks can provide an easily navigable hierarchy.
Build your DOM with javascript and submit to a RESTful endpoint(you can even use WTForms for validation by converting the request body into a MultiDict and Recaptcha supports AJAX)
Build your <form> dynamically with javascript and switch the action to correspond to the correct form processor on your server.
This is not possible with reCAPTCHA.
See the related ASP.NET question: Multiple reCAPTCHAs in one ASP.Net page
And for possible workarounds: How do I show multiple recaptchas on a single page?