NoReverseMatch error from Python Tutorial - python-3.7

Django Tutorial part 4 I am getting a NoReverseMatch at /polls/1/
NoReverseMatch at /polls/1/
Reverse for 'polls.index' not found. 'polls.index' is not a valid view
In template /var/www/html/django_app/polls/templates/polls/detail.html, error at line 5
Reverse for 'polls.index' not found. 'polls.index' is not a valid view function or pattern name...
I have looked up and researched this question on here for a while and am hitting a wall. There are many references to the problem but none that match the problem I am seeing and the state of my current code.
urls.py
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
detail.py
<h1>{{ question.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls.vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }</label><br>
{% endfor %}
<input type="submit" value="Vote">
</form>
views.py
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
return Question.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return and HttpResponseRedirect after successfully dealin
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
I can clearly see what it saying the problem is but I can't seem to determine what is causing it.
Any extra eyes would help and be greatly appreciated!

Related

I can not recover the values ​of my checkbox in my controller

I'm working on a symfony project, I created a checkbox in twig, I want to get checked values ​​in my Controller but I still get a null, I do not know what the problem is please help:
My Action:
public function sendSmsAction(Request $request) {
if ($request->isMethod('get')) {
$ids = $request->query->get('id');
var_dump($ids);
die();
}
return $this->render('CeUtilisateurBundle:Utilisateur:sms.html.twig')
}
My Form in twig:
<form
method="GET"
action="{{path('ce_utilisateur_send_sms') }}"
id="lbad_form_sms"
name="users"
>
{% if listUsers is not empty %}
{% for usr in listUsers %}
<input
id="userchecked"
name="{{usr.id}}"
type="checkbox"
value="{{ usr.telephone }}"
/>
<span>{{ usr.username }}</span>
</form>
Aside from other issues in your example, in order to get those values you need to change the HTML part that displays checkboxes and give them different IDs, proper values and the same name:
<input id="telephone{{ usr.id }}" name="telephone[]" type="checkbox" value="{{ usr.telephone }}"/>
Notice that the name property is the same for every checkbox and has [] at the end - this allows to pass multiple values for one property.
Next to that I would suggest to use a POST request to submit the form, instead of the GET you are using. If you do so, you can get the selected phone numbers in the controller like that:
$telephones = $request->request->get('telephone');
If you want to submit the form with a GET request, then use query instead of the request:
$telephones = $request->query->get('telephone');
First, you're missing closing tags in twig for your if and for, but I assume they just got lost during copying.
Second, you give all your input elements the same id "userchecked". Each HTML element should have a unique ID, e.g. by appending your user ID.
Something similar happens with the name attribute. If you give multiple form elements the same name, only the last one will be submitted.
So your form should look something like this:
<form
method="GET"
action="{{path('ce_utilisateur_send_sms') }}"
id="lbad_form_sms"
name="users"
>
{% if listUsers is not empty %}
{% for usr in listUsers %}
<input
id="{{"userchecked_" ~ usr.id}}"
name="{{"checked_" ~ usr.id}}"
type="checkbox"
value="{{ usr.telephone }}"
/>
<span>{{ usr.username }}</span>
{% endfor %}
{% endif %}
<input type="submit" value="Envoyer un sms!"/>
</form>
To fix your controller, you have to get the input by the name field. Since it is dynamically created, it's easiest to just get all parameters and loop over them.
public function sendSmsAction(Request $request) {
if ($request->isMethod('get')) {
$parameters = $request->query->all();
foreach ($parameters as $name => $value) {
var_dump("$name: $value");
}
die();
}
return $this->render('CeUtilisateurBundle:Utilisateur:sms.html.twig')
}
Note that there will be no submitted parameter for an empty checkbox.

Flask form routing

I'm struggling with a Flask App that gives me Bad Request on a form submission. I've been through the little bit of documentation from Flask and a number of SO pages. I'm sure there's something simple I'm missing.
In a nutshell, I've developed a template to receive the form called 'placeindex.html'. The form 'name' data all matches. If I change the name of 'placeindex.html' to 'index.html' it works fine, even though I'm pointing to the 'placeindex.html' file. Code below (view):
#app.route('/add_place', methods=['GET', 'POST'])
def add_place():
username = session['username']
placename = request.form['place']
address = request.form['address']
city = request.form['city']
state = request.form['state']
zipcode = request.form['zipcode']
alias = request.form['alias']
searchword = request.args.get('key', '')
print(searchword)
Place(session['username']).new_place(placename, address, city, state, zipcode, alias, username)
return render_template('placeindex.html')
placeindex.html:
{% extends "layout.html" %}
{% block place %}
<h2>Home</h2>
{% if session.username %}
<h3>Add new 'placeindex'</h3>
<form action="{{ url_for('add_place') }}" method="post">
<dl>
<dt>Name:</dt>
<dd><input type="text" size="30" name="place"></dd>
<dt>Address:</dt>
<dd><input type="text" size="30" name="address"></dd>
<dt>City:</dt>
<dd><input type="text" size="30" name="city"></dd>
<dt>State:</dt>
<dd><input type="text" size="2" name="state"></dd>
<dt>Zip Code:</dt>
<dd><input type="text" size="10" name="zipcode"></dd>
<dt>Nickname:</dt>
<dd><input type="text" size="30" name="alias"></dd>
</dl>
<input type="submit" value="Save">
</form>
{% endif %}
<br>
<h3>My Places</h3>
{% include "display_posts.html" %}
{% endblock %}
I've stripped out all the validation code to try to figure this out.
layout.html (in case it helps):
<!doctype html>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}">
<div class="page">
<div class="metanav">
{% if session.username %}
Logged in as {{ session.username }}
{% endif %}
Home
{% if not session.username %}
Register
Login
{% else %}
Profile
Logout
Places
Trips
Delegates
{% endif %}
</div>
{% for message in get_flashed_messages() %}
<div class="flash">{{ message }}</div>
{% endfor %}
{% block body %}{% endblock %}
{% block post %}{% endblock %}
{% block place %}{% endblock %}
{% block trip %}{% endblock %}
</div>
Once I open the 'index.html' version of the file and send form data, it refreshes to the correct file, but I can't go there directly without the BAD REQUEST page.
Thanks
The issue is that you are accessing request.form without checking if request.form is populated. form contains arguments in the body of the HTTP request ... and GET requests don't have a body.
As discussed in Form sending error, Flask - when Flask is asked for a form variable that doesn't exist it throws an error ... just like an ordinary Python dictionary does.
The solution in your case is to wrap all of your data-processing code inside of a conditional:
if request.method == "POST":
# code accessing request.form here
So the general structure is:
#app.route('/add_place', methods=['GET', 'POST'])
def add_place():
if request.method == "POST":
username = session['username']
placename = request.form['place']
# ... snip ...
# Note that this is not under the `if`
# so we'll *always* return this template's HTML.
return render_template('placeindex.html')

How to get a new object after form submittig?

I'm trying flask nad there is a simple task to submit a form.
Page is showing a one picture and a form, if form was submitted correctly, picture should be changed, if not - be the same.
I can't understand the mechanism of how to show only one object on a page and get another after form submitting.
Tried to use iterator over the list of images is folder "static", but my implementation was not working correctly.
Please provide me a feedback how to do it in rigth way?
Now I have the simple view:
#app.route("/", methods=["GET", "POST"])
def start_view():
picture = None
form = InputForm(csrf_enabled=False)
if form.validate_on_submit():
picture = form.picture.data
form.picture.data = ""
return render_template('04-2.html', form=form, picture=picture)
class InputForm(Form):
picture = StringField('What is on a picture?', validators[DataRequired()])
submit = SubmitField('Submit')
And a simple template:
<body>
<form method="POST">
{{ form.picture.label }} {{ form.picture }}
{{ form.submit() }}
</form>
{% if form.errors %}
<span style="color: red">{{ form.error }}</span>
{% endif %}
</body>
Thank you!
Your form doesnt contain any pictures. It has a StringField and a SubmitField. If you want to see any image you need to have an <img> tag in your HTML pointing to the image location in your server
your view should look like:
from Flask import session
# in order to use sessions you have to use a secret key for your app
app.secret_key = 'some secret key'
#app.route("/", methods=["GET", "POST"])
def start_view():
img_list = ['filename1', 'filename2', 'filename3']
# if this is not the first form submission
if session.has_key('current'):
# if we reach the end of the list show the first image again
if int(session['current']) == len(img_list) - 1:
session['current'] = 0
# move to next image
else:
session['current'] = int(session['current']) + 1
else:
session['current'] = 0
picture = 'first_image_filename' # this should be the img on load
form = InputForm(csrf_enabled=False)
if form.validate_on_submit():
picture = img_list[int(session['current'])] # the filename of the next image
form.picture.data = ""
return render_template('04-2.html', form=form, picture=picture)
so template should look like:
<body>
<form method="POST">
{{ form.picture.label }} {{ form.picture }}
<img src="{{url_for('static', filename='img/' + picture)}}"
{{ form.submit() }}
</form>
{% if form.errors %}
<span style="color: red">{{ form.error }}</span>
{% endif %}
</body>

Flask render form values

I have a question about rendering form results. When i submit the form i want to show the term below the form. what did i wrong ?
Now wehen i submit the form i get a 200 Status Code and no error message. But the term dosent show up in the defined place.
# app.py
#app.route('/search')
def search():
return render_template('search/index.html')
#app.route('/search<q>')
def results(q):
return render_template('search/index.html', term=q)
# search/index.html
{% extends 'base.html' %}
{% block content %}
<div>
<form method="get" action="">
<input type="text" name="q" id="">
<input type="submit">
</form>
{{ term }}
</div>
{% endblock %}
You have confused path parameters (which Flask routes parse out and pass to the view) with query parameters (which are available in request.args). Remove your second route and update the first to access the query.
from flask import request
#app.route('/search')
def search():
term = request.args.get('q')
return render_template('search.html', term=term)

Django form for querying database. Is form.py needed and how to leave fields empty for query?

I would like to have an input form where a user inputs either an incident_id or a equipment_id or both. The problem I have now is for example, if I fill in incident_id and leave equipment_id blank, the query will return no hits even when incident_id finds a match, because my query uses blank equipment_id in the search. How can I set it up so that when I leave a field blank, it doesn't use it in the query? Do I need to validate this data? I'm not inserting any of it into the db.
I know Django forms uses POST, but in this instance I feel that GET is more appropriate, which means I don't have to use Django forms, but does that mean I also don't have to validate the data? Or should I just use POST anyway and validate that data with Django forms? I'm sorry this is so conceptual. I'm not finding many good answers online.
model.py
from django.db import models
class Incident(models.Model):
incident_id = models.CharField(max_length=1000, blank=True)
equipment_id = models.ForeignKey(Equipment, blank=True)
class Equipment(models.Model):
equipment_id = models.CharField(primary_key=True, max_length=100)
manufacturer = models.ForeignKey(Manufacturer)
equipment_category = models.ForeignKey(Equipment_Category)
validated= models.BooleanField(default=True)
in_service_date = models.DateTimeField('in service date', default=timezone.now)
view.py
#login_required
def search_incidents_query(request):
if request.method == 'GET':
incident_id_query = request.GET.get('incident_id')
equipment_id_query = request.GET.get('equipment_id')
try:
incident_id = str(incident_id_query)
except ValueError:
incident_id = None
try:
equipment_id = str(equipment_id_query)
except ValueError:
username = None
list = [incident_id,equipment_id]
if all(x is None for x in list): #check if `list` contains only None
incident_list = None #this in case the query comes back empty
else: #perform query
incident_list = Incident.objects.filter(incident_id=incident_id, equipment_id=equipment_id)
)
return render(request, 'search_incidents_query.html', {
'incident_list' : incident_list
})
search_incidents_query.html
{% extends "base.html" %}
{% load widget_tweaks %}
{% block content %}
<br>
<div class="container-fluid">
<!-----INPUT FORM------------------->
<form method='GET' action='/search_incidents/'>
<div class="row">
<div class="form-group col-md-3">
<label>Incident ID</label>
<input type="text" name="incident_id" value="{{ incident_id_query }}" class="form-control"/>
</div>
<div class="form-group col-md-3">
<label>Equipment ID</label>
<input type="text" name="equipment" value="{{ equipment_id_query }}" class="form-control"/>
</div>
</div>
</form>
</div>
{% endblock %}
The query
You should use a Q object for similar queries.
from django.db.models import Q
Incident.objects.filter(
Q(incident_id=incident_id) | Q(equipment_id=equipment_id)
)
More on Q objects.
Also, IMO this code needs to live in some Form class. If it was me, I would have put this code in some
The form
class IncidentSearchForm(forms.Form):
incident = forms.CharField(required=False)
# ModelChoiceField because we want django to do the validation for us
# TextInput because the default widget is a select tag
equipment = forms.ModelChoiceField(Equipment.objects.all(), required=False, widget=forms.TextInput) # TextInput because
def clean(self):
# I'd use the clean method to force the user to provide either an incident or equipment value
def search(self):
return Incident.objects.filter(
Q(incident_id=self.cleaned_data['incident']) |
Q(equipment_id=self.cleaned_data['equipment'])
)
The view
Why aren't you using Class Based Views already?
username = None. Wat?
You should use a form because never trust user input.
#login_required
def search_incidents_query(request):
form = IncidentSearchForm(request.GET or None)
incident_list = None
if 'equipment' in request.GET or 'incident' in request.GET:
incident_list = None # Or maybe Incident.objects.none()
if form.is_valid():
incident_list = form.search()
return render(request, 'search_incidents_query.html', {'form' : form})
The template
<form method='GET' action='/search_incidents/'>
<div class="row">
<div class="form-group col-md-3">
{{ form.incident }}
</div>
<div class="form-group col-md-3">
{{ form.equipment }}
</div>
</div>
<input type="submit" />
</form>
You can use a widget on the form to add form-control class to the fields.