Here is my route function :
#app.route('/home/shelter/<int:shelter_id>/', methods=['GET','POST'])
def showShelterDetails(shelter_id):
shelter = session.query(Shelter).filter_by(id = shelter_id).one()
if request.method == 'POST':
if request.form['shelterName']:
shelter.name = request.form['shelterName']
session.add(shelter)
session.commit()
flash("Shelter("+shelter.name+") edited successfully!")
return render_template('shelterdetails.html', shelter_id=shelter_id, shelter=shelter)
else:
flash(u'Error Occured!','error')
return render_template('shelterdetails.html', shelter_id=shelter_id, shelter=shelter)
if request.form['shelterAddress']:
shelter.name = request.form['shelterAddress']
session.add(shelter)
session.commit()
flash("Shelter("+shelter.name+") address edited successfully!")
return render_template('shelterdetails.html', shelter_id=shelter_id, shelter=shelter)
else:
flash(u'Error Occured!','error')
return render_template('shelterdetails.html', shelter_id=shelter_id, shelter=shelter)
else:
return render_template('shelterdetails.html', shelter_id = shelter_id, shelter = shelter)
Here is my HTML template :
{% extends "master.html" %}
{% block title %}Home{% endblock %}
{% block body %}
{% with messages = get_flashed_messages(category_filter=["message"]) %}
{% if messages %}
<div class="alert alert-success">
{% for message in messages %}
<strong>{{message}}!</strong>
{% endfor %}
</div>
{% endif %}
{% endwith %}
{% with errors = get_flashed_messages(category_filter=["error"]) %}
{% if errors %}
<div class="alert alert-danger">
{% for message in errors %}
<strong>{{message}}!</strong>
{% endfor %}
</div>
{% endif %}
{% endwith %}
<form action="{{ url_for('showShelterDetails',shelter_id=shelter_id )}}" method = 'post'>
<fieldset class="form-group">
<label for="shelterName">Name :</label>
<input type="text" class="form-control" style="width:500px" name="shelterName" value='{{ shelter.name }}' >
</fieldset>
<fieldset class="form-group">
<label for="shelterName">Address :</label>
<input type="text" class="form-control" style="width:500px" name="shelterAddress" value='{{ shelter.address }}'>
</fieldset>
My problem is : The POST method doesn't check whether the shelterAddress field is empty or blank or not. Also while returning the success or failure messages. Only the top 1 message gets printed.
Why do the other messages not get printed ? Also why doesn't it check for empty fieds ?
EDIT 1:
Changed my view function to :
#app.route('/home/shelter/<int:shelter_id>/', methods=['GET','POST'])
def showShelterDetails(shelter_id):
shelter = session.query(Shelter).filter_by(id = shelter_id).one()
if request.method == 'POST':
if request.form['shelterName']!="":
shelter.name = request.form['shelterName']
session.add(shelter)
session.commit()
flash("Shelter("+shelter.name+") edited successfully!")
if request.form['shelterAddress']!= "":
shelter.name = request.form['shelterAddress']
session.add(shelter)
session.commit()
flash("Shelter("+shelter.name+") address edited successfully!")
else:
return render_template('shelterdetails.html', shelter_id = shelter_id, shelter = shelter)
ValueError: View function did not return a response
That's because you're returning early whether request.form['shelterName'] is truthy or not. You probably want one return statement at the very end of your view function instead.
Related
In an auction web. I'm trying to terminate adding any input (bids, comments and add to watchlist) by any user to the database if the owner of the product press on 'close ' button so I tried to implement this pseudo code:
in views.py
function listing:
t = 1
if t == 1:
if owner clicks on the close button:
...
t = 2
if the user adds a comment:
...
if the user adds a bid:
...
if user clicks on add to watchlist button:
...
else:
return message ('Auction has ended')
I have implemented this code and the listing page accepted entries and inputs after the owner of the listing clicked on the 'close' button. I also tried to change the value of t to a boolean value ( t = True, if t == True, if user clicked: return t = False) but it didn't work. so what is the problem.
def entry(request, name):
enter = listing.objects.get(title = name)
f= bids.objects.filter(product_id = enter)
x = 0
z = ""
last = None
ended = None
like = "k"
t = 1
if t == 1:
if request.method == 'POST' and request.POST.get("bid"):
biddd = int(request.POST['bid'])
user = request.user
if biddd > x:
bids.objects.create(bid= biddd , product_id= listing.objects.get(title = name).id, user = user)
for object in f:
if object.bid > x:
if object.bid > x:
x = object.bid
if request.method == 'POST' and request.POST.get('close_bid'):
final = listing.objects.get(title = name)
last = bids.objects.get(bid = x, product = final).user
t = 2
elif request.method == 'POST' and request.POST.get("bid"):
bidd = int(request.POST['bid'])
if bidd >= x:
messages.info(request, 'bid accepted')
z = "#0a720e"
else:
messages.info(request, 'bid already present')
z = "#f44336"
elif request.method == 'POST' and request.POST.get("watchlist"):
if request.user.is_authenticated:
productt = listing.objects.get(title = name)
user = request.user
exist = watchlist.objects.filter(product = productt, user = user)
if exist.exists():
messages.info(request, 'Already added to your watchlist')
else:
watchlist.objects.create(product = productt, user = user)
else:
return render(request, "auctions/login.html")
elif request.method == 'POST' and request.POST.get("comments"):
if request.user.is_authenticated:
comment = request.POST['comments']
product = listing.objects.get(title = name)
user = request.user
comments.objects.create(comment = comment, user = user, product = product)
else:
return render(request, "auctions/login.html")
commentproduct = listing.objects.get(title = name)
commentss= comments.objects.filter( product = commentproduct)
else:
messages.info(request, 'Auction has ended')
return render(request, "auctions/entry.html" , {"enter":enter, "bid": f, "x": x, "z":z, "comments":commentss, "winner": last, "ended": ended, "l": l})
in entry.html:
{% extends "auctions/layout.html" %}
{% load static %}
{% block body %}
<h1>Listing: {{enter}}</h1>
<img src="{{enter.image}}">
<p>{{enter.description}}</p>
<h3>Current Bid: {{x}}</h3>
<form action = "#" method="POST">
{% csrf_token %}
<label>Add bid:</label>
<input type="number" name="bid">
<input type="submit">
</form>
{% for message in messages %}
<div class="alert" style="background-color:{{z}}">
<span class="closebtn" onclick="this.parentElement.style.display='none';">×</span>
{{message}}
</div>
{% endfor %}
<form method='POST' action='#'>
{% csrf_token %}
<button type="submit" name="watchlist" value="Add to watchlist"> Add to watchlist</button>
</form>
{% for message in messages %}
<h5>{{message}}</h5>
{% endfor %}
<h2>Details:</h2>
<p><strong>Owner:</strong> {{enter.author}}</p>
<p><strong>Category:</strong> {{enter.category}}</p>
<br>
<h2>Add a comment:</h2>
<form method="POST" action="#">
{% csrf_token %}
<textarea name="comments" placeholder="Add a comment" style="width:600px"></textarea>
<input type="submit" value="Add comment">
</form>
{% if user.is_authenticated and user == enter.author %}
<form method='POST' action='#'>
{% csrf_token %}
<button type="submit" name="close_bid" value="Close bid"> Close Bid</button>
</form>
{% endif %}
<h2>Comments:</h2>
{% for comment in comments %}
<h3>{{comment.user}}:</h3>
<p>{{comment.comment}}</p>
{% endfor %}
{% if user.is_authenticated and user == winner %}
<div class="alert" style="background-color:green">
<span class="closebtn" onclick="this.parentElement.style.display='none';">×</span>
You won!
</div>
{% elif not user.is_authenticated %}
<p></p>
{% else %}
<div class="alert" style="background-color:red">
<span class="closebtn" onclick="this.parentElement.style.display='none';">×</span>
You lost!
</div>
{% endif %}
{% if user.is_authenticated and user == winner %}
<p>
You won!
</p>
{% elif not user.is_authenticated %}
<p>.</p>
{% else %}
<p>you lost</p>
{% endif %}
{% endblock %}
When I click on the submit button, my form validation is equal to True, however nothing displays. The catch is, if I press the submit button again, then everything displays and I no longer have to click the button twice going forward. Up until I restart the server again. I am perplexed and I would greatly appreciate if anyone can tell me what I'm doing wrong.
If I were to remove the validate_on_submit() function the form works fine, but doesn't validate. Which I do not want.
Edit 1
I've added print('------ {0}'.format(request.form)) and print(form.errors) to my code for debugging purposes.
When I insert the values into my form print('------ {0}'.format(request.form)) it prints out the following below:
------ ImmutableMultiDict([('csrf_token', 'IjFiMDE3OGVlZjVjYTYzODQ0MGE2MGMyYWI5NWFjOWYwNjZjMjlmN2Ii.YMFPNw.UtuYhwUnCAlmzdsGNaTEFPM9eek'), ('name', 'Bitcoin'), ('intial_investment', '1500'), ('coin_price', '500'), ('submit', 'Submit')])
While print(form.errors) prints the following:
{'csrf_token': ['The CSRF token is invalid.']}
I would like to believe the root cause of my issue is due to the CSRF being invalid.
However, how can it be invalid when the actual token is listed above?
Edit 2
I've removed {{ form.csrf_token() }} and request.form. Since I don't need to pass in the request when I instance the form.
However, the original issue still persist.
My routes.py
#application.route("/", methods=["GET", "POST"])
def home():
form = Crypto_Form()
coins = None
print('------ {0}'.format(request.form))
print(form.errors)
if form.validate_on_submit():
try:
TWOPLACES = Decimal(10) ** -2
Decimal('3.214').quantize(TWOPLACES)
user_input = form.name.data
coin_name = user_input.lower().replace(" ", "-")
coin_gecko_name = cg.get_coins_markets(vs_currency='usd', ids=[coin_name.lower()], order='market_cap_desc', per_page='1', page='1', sparkline='false')[0]
initial_investment = form.intial_investment.data
coin_image = cg.get_coins_markets(vs_currency='usd', ids=[coin_name.lower()], order='market_cap_desc', per_page='1', page='1', sparkline='false')[0]
coin_price = float(cg.get_price(ids=[coin_name.lower()], vs_currencies='usd')[coin_name.lower()]['usd'])
presale_price = form.coin_price.data
multiplier = Decimal(float(coin_price) / float(presale_price)).quantize(TWOPLACES)
profit = round((float(initial_investment) / float(presale_price)) * float(coin_price))
twenty_four_hour_change = Decimal(cg.get_price(ids=[coin_name.lower()], vs_currencies='usd', include_24hr_change='true')[coin_name.lower()]['usd_24h_change']).quantize(TWOPLACES)
ath = cg.get_coins_markets(vs_currency='usd', ids=[coin_name.lower()], order='market_cap_desc', per_page='1', page='1', sparkline='false')[0]
ath_change_percentage = cg.get_coins_markets(vs_currency='usd', ids=[coin_name.lower()], order='market_cap_desc', per_page='1', page='1', sparkline='false')[0]
coin = Coin(
crypto_name=coin_gecko_name['name'],
coin_initial_invesment=initial_investment,
image=coin_image['image'],
current_price=coin_price,
presale_price=presale_price,
multiple= multiplier,
profit=profit,
twenty_four_hour=twenty_four_hour_change,
all_time_high=ath['ath'],
all_time_percentage_change=Decimal(ath['ath_change_percentage']).quantize(TWOPLACES)
)
db.session.add(coin)
db.session.commit()
except Exception as e:
db.session.rollback()
print('Failed to add coin')
print(e)
coins = Coin.query.all()
coin_profit = Coin.query.with_entities(func.sum(Coin.profit).label('total')).first().total
if coin_profit is None:
coin_profit = 0
return render_template("home.html", coins=coins, value=coin_profit, form=form)
My forms.py
class Crypto_Form(Form):
name = StringField("Enter Coin Name", [validators.DataRequired(message="Please enter the Crypto Currency name.")])
intial_investment = DecimalField("Enter Initial Investment", [validators.DataRequired(message="Please enter a number")])
coin_price = DecimalField("Enter Coin Price", [validators.DataRequired(message="Please enter a number")])
submit = SubmitField("Submit")
My Jinja form
<form class="justify-content-center" method="POST" name="Crypto_Info" role="form">
{{ form.hidden_tag()
<div class="form-group">
{{ form.name.label(class="form-control-label") }}
{% if form.name.errors %}
{{ form.name(class="form-control form-control-lg is-invalid")}}
<div class="invalid-feedback">
{% for error in form.name.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.name(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form-group">
{{ form.intial_investment.label(class="form-control-label") }}
{% if form.intial_investment.errors %}
{{ form.intial_investment(class="form-control form-control-lg is-invalid")}}
<div class="invalid-feedback">
{% for error in form.intial_investment.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.intial_investment(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form-group">
{{ form.coin_price.label(class="form-control-label") }}
{% if form.coin_price.errors %}
{{ form.coin_price(class="form-control form-control-lg is-invalid")}}
<div class="invalid-feedback">
{% for error in form.coin_price.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.coin_price(class="form-control form-control-lg") }}
{% endif %}
</div>
<div>
{{ form.submit(class="btn btn-primary") }}
</div>
</form>
I have been researching how can I avoid using snippet of code over and over. The answer probably will involve using (generic) Class-based functions. However, I am a beginner in Django and this seems confusing. Here is my view in views.py:
#login_required(login_url='/login')
def view_list(request, listing_id):
bid = Bid.objects.all().filter(listing=listing_id).order_by('-id')
b_u = bid[0].user
listing = Listing.objects.get(pk=listing_id)
if request.method == "GET":
return render(request, "auctions/view_list.html", {
"form": BidForm(),
"total_bids": bid.count(),
"bid": None if bid == 0 else bid[0].bid,
"listing": listing,
"bid_user": "Your bid is the current bid." if request.user == b_u else None
})
else:
form = BidForm(request.POST)
if form.is_valid():
value = form.cleaned_data
if value['bid'] <= bid[0].bid:
error_check = True
return render(request, "auctions/view_list.html", {
"error_check": error_check,
"alert": f"Your bid is lower than the current bid $({bid[0].bid})! Try placing a higher one.",
"form": BidForm(),
"total_bids": bid.count(),
"bid": None if bid == 0 else bid[0].bid,
"listing": listing,
"bid_user": "Your bid is the current bid." if request.user == b_u else None
})
else:
error_check = False
new_bid = form.save(commit=False)
new_bid.user_id = request.user.id
new_bid.listing_id = listing.id
new_bid.save()
return render(request, "auctions/view_list.html", {
"error_check": error_check,
"alert": "Your bid was successfully placed!",
"form": BidForm(),
"total_bids": bid.count(),
"bid": None if bid == 0 else bid[0].bid,
"listing": listing,
"bid_user": "Your bid is the current bid." if request.user == b_u else None
})
And here is my template code:
{% extends "auctions/layout.html" %}
{% load humanize %}
{% load crispy_forms_tags %}
{% block body %}
{% if error_check == True %}
<div class="alert alert-warning" role="alert">
{{ alert }}
</div>
{% elif error_check == False %}
<div class="alert alert-success" role="alert">
{{ alert }}
</div>
{% endif %}
<div>
<h3>Listing: {{ listing.title }}</h3>
<img src="{{ listing.image }}" alt="Listings' Images">
<p>{{ listing.description }}</p>
{% if not bid %}
<strong>${{ listing.price|stringformat:"1.2f" }}</strong>
{% else %}
<strong>${{ bid|stringformat:"1.2f" }}</strong>
{% endif %}
<p> {{ total_bids }} bid(s) so far. {% if bid_user %} {{ bid_user }} {% endif %}</p>
<form method="POST" name="bidding" action="{% url 'view_list' listing.id %}">
{% csrf_token %}
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">$</span>
</div>
<div style="margin: 0; padding: 0 2px; height: 6px;">
{% crispy form %}
</div>
<div class="input-group-append" >
<span class="input-group-text">.00</span>
</div>
<input type="submit" class="btn btn-primary" value="Place Bid">
</div>
</form>
<h4>Details</h4>
<li>Listed by: {{ listing.user }} </li>
<li>Category: {{ listing.category }} </li>
<li>Listing created at: {{ listing.created_at }} </li>
</div>
{% endblock %}
So how can I avoid all this repetition and make the code more succinct. Also, this way when the user places a successful bid, the rendered template does not contain the new information from the form.
The pattern is very simple
def some_view(request):
form = SomeForm(request.POST or None)
if request.method == 'POST' and form.is_valid():
# Form processing
return render(request, "auctions/view_list.html", {
"form": form
})
views.py
def create(request):
choicenumber = 3
submitbutton = request.POST.get('submit', False)
choicebutton = request.POST.get('add_choice', False)
if choicebutton:
choicenumber += 1
render(request, 'polls/create.html', {
'questionfields': Question.__dict__,
'choicenumber': choicenumber,
})
if submitbutton:
new_question = Question.objects.create(question_text=request.POST.get('question_text', ''),
pub_date=timezone.now())
if new_question.question_text == '':
context = {
'questionfields': Question.__dict__,
'error_message': "No poll question entered.",
'choicenumber': choicenumber,
}
del new_question
return render(request, 'polls/create.html', context)
else:
for i in range(choicenumber + 1):
choice = request.POST.get(('choice' + str(i)), '')
if choice:
choice_obj = Choice.objects.create(question=new_question, choice_text=choice)
new_question.choice_set.add(choice_obj)
new_question.save()
return HttpResponseRedirect(reverse('polls:detail', args=(new_question.id,)))
else:
return render(request, 'polls/create.html', context)
create.html
{% extends "polls/base.html" %}
{% block title %}Create a Poll{% endblock title %}
{% block header %}Create:{% endblock header %}
{% load custom_tags %}
{% block content %}
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:create' %}" method="post"> {% csrf_token %}
{% for field in questionfields %}
{% if field == 'question_text' %}
<label for="{{ field }}">{{ field|capfirst|replace }}:</label>
<input type="text" name="{{ field }}" id="{{ field }}">
<br>
{% endif %}
{% endfor %}
<br>
{% for choice in choicenumber|rangeof %}
<br>
<label for="choice{{ forloop.counter }}">Choice {{ forloop.counter }}:</label>
<input type="text" name="choice{{ forloop.counter }}" id="choice{{ forloop.counter }}">
<br>
{% endfor %}
<br>
<input type="button" name="add_choice" value="Add choice">
<br>
<br>
<input type="submit" value="Create" name="submit">
</form>
{% endblock content %}
I recently added the add_choice button to my template:
<input type="button" name="add_choice" value="Add choice">
Using this, I tried using a request.POST.get() to check if it has been clicked, and if so for it to increment 'choicenumber' and re-render the view with the increased value of choicenumber:
if choicebutton:
choicenumber += 1
return render(request, 'polls/create.html', {
'questionfields': Question.__dict__,
'choicenumber': choicenumber,
})
Since the increment causes choicenumber to increase, within the create.html the for loop for producing the input boxes for each choice --
{% for choice in choicenumber|rangeof %}
<br>
<label for="choice{{ forloop.counter }}">Choice {{ forloop.counter }}:</label>
<input type="text" name="choice{{ forloop.counter }}" id="choice{{ forloop.counter }}">
<br>
{% endfor %}
-- should loop once more than usual on the re-render. This does not happen however, and the website renders as originally.
Does anyone know how to make this work properly or improve my code? I am very new to the Django framework, so any advice would be great. Thanks!
EDIT::
updated views.py
def create(request):
choicenumber = 3
context = {
'questionfields': Question.__dict__,
'choicenumber': choicenumber,
}
submitbutton = request.POST.get('submit', False)
choicebutton = request.POST.get('add_choice', False)
if request.method == 'GET':
request.session['choicenumber'] = 0
if request.method == 'POST':
if choicebutton:
request.session['choicenumber'] += 1
if submitbutton:
new_question = Question.objects.create(question_text=request.POST.get('question_text', ''),
pub_date=timezone.now())
if new_question.question_text == '':
context = {
'questionfields': Question.__dict__,
'error_message': "No poll question entered.",
'choicenumber': choicenumber,
}
del new_question
return render(request, 'polls/create.html', context)
else:
for i in range(choicenumber + 1):
choice = request.POST.get(('choice' + str(i)), '')
if choice:
choice_obj = Choice.objects.create(question=new_question, choice_text=choice)
new_question.choice_set.add(choice_obj)
new_question.save()
return HttpResponseRedirect(reverse('polls:detail', args=(new_question.id,)))
else:
return render(request, 'polls/create.html', context)
EDIT 2::
updated create.html
{% extends "polls/base.html" %}
{% block title %}Create a Poll{% endblock title %}
{% block header %}Create:{% endblock header %}
{% load custom_tags %}
{% block content %}
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:create' %}" method="post"> {% csrf_token %}
{% for field in questionfields %}
{% if field == 'question_text' %}
<label for="{{ field }}">{{ field|capfirst|replace }}:</label>
<input type="text" name="{{ field }}" id="{{ field }}">
<br>
{% endif %}
{% endfor %}
<br>
{% for choice in {{ request.session.choicenumber }}|rangeof %}
# the update is here: choicenumber -> {{ request.session.choicenumber }}
# this defaults as 0 though, even if it is defined as 3.
<br>
<label for="choice{{ forloop.counter }}">Choice {{ forloop.counter }}:</label>
<input type="text" name="choice{{ forloop.counter }}" id="choice{{ forloop.counter }}">
<br>
{% endfor %}
<br>
<input type="button" name="add_choice" value="Add choice">
<br>
<br>
<input type="submit" value="Create" name="submit">
</form>
{% endblock content %}
I am working in ang django project onlinevoting. In my template I use
looping to loop all the positions and also the candidates. I have trouble in saving many data at once in one attribute for example in my model I have:
class Vote(models.Model):
candidate_id = models.ForeignKey('Candidate', blank=True, null=True)
election_id = models.ForeignKey('Election', blank=True, null=True)
user_id = models.ForeignKey('User', blank=True, null=True)
def __str__(self):
return "%s %s" % (user_id.first_name, election_id.year)
and in my template vote.html:
<form method="POST" class="form-horizontal" role="form">
{% if success %}
<div class="alert alert-success">
×
<strong>Success!</strong> {{ success }}
</div>
{% endif %}
{% if exist %}
<div class="alert alert-warning">
×
<strong>Warning!</strong> {{ exist }}
</div>
{% endif %}
{% csrf_token %}
<div class="form-group ">
{% for position in positions %}
<label for="cname" class="control-label col-lg-2">{{ position }}<span class="required">*</span></label>
{% for candidate in candidates %}
{% if position.pk == candidate.position_id.pk %}
<div class="col-lg-3">
<input type="checkbox" name="candidate_id" value="{{ candidate.pk }}">{{ candidate }}<br>
</div>
{% endif %}
{% endfor %}
</div>
{% endfor %}
<button class="btn btn-primary" type="submit">Save</button>
<button class="btn btn-default" type="button">Cancel</button>
</div>
</div>
</form>
How can I add/save all the candidates? because the user can select many candidates and I want to save them at once. This is my views.py
def vote(request):
if request.user.is_authenticated and request.user.is_admin:
candidates = Candidate.objects.all()
election = Election.objects.all().filter(is_active=True)
positions = Position.objects.all()
user = get_object_or_404(User, pk=request.user.pk)
try:
if request.method == 'POST':
candidate_id = request.POST['candidate_id']
vote = Vote.objects.create(candidate_id=candidate_id)
vote.save()
vote.election_id = election
vote.save()
vote.user_id = user
vote.save()
else:
form = VoteForm()
return render(request,'system/vote.html', {'form':form, 'candidates': candidates,
'election': election, 'user': user,
'positions': positions})
except:
exist = "ERROR!"
form = VoteForm()
return render(request,'system/vote.html', {'form':form, 'exist': exist})
elif not request.user.is_authenticated:
return redirect('system.views.user_login')