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

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.

Related

NoReverseMatch error from Python Tutorial

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!

How can I render search results using Symfony?

I've created a form for searching data in the DB.
This is the form:
<form role="search" method="post" action="{{ path('search') }}">
<div>
<input type="text" placeholder="Cerca" name ="search">
<span>
<button type="submit"></button>
</span>
</div>
</form>
And of course I also have the action in the controller:
public function searchAction(Request $request)
{
$request = $this->getRequest();
$data = $request->request->get('search');
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery('SELECT a FROM AppBundle:Article a WHERE a.titolo LIKE :data')
->setParameter('data', $data);
$result = $query->getResult();
return $this->render('default/search.html.twig', array('result' => $result));
}
In this way, I can write in the field what I want to search, and submit the form. The form is submitted, but it renders the form again without any message or results.
If I want to render the results, do I have to create a results template where I use a for loop to render all the results?
How can I render the results?
You're already passing $results to the render function. So with the required code in your template it should work without much hassle:
E.g.
{% for result in results %}
<div>
// use result, e.g. {{ result.title }} or whatever your data has to offer
</div>
{% else %}
<em>no results found</em>
{% endfor %}

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.

How to delete an entity from a template with a list of entities (CRUD)?

Explanation:
I have generated the CRUD of an entity, getting the following default actions:
indexAction(): lists all entities.
showAction($id): finds (by ID) and displays an entity.
deleteAction($id): deletes an entity.
another actions.
So, I have seen I can only delete an entity within the actions that use the param $id (e.g.: showAction($id) ) but I want to delete an entity inside the indexAction template because I save a step to users.
The deleteAction needs a request, an ID and use the POST method.
I was trying to code something like:
<a href="{{ path('entity_delete', { 'id': entity.id }) }}" class="btn">
<img src="{{ asset('bundles/acme/images/delete.png') }}" ... />
</a>
When I execute the action, I get the following error:
No route found for "GET /acme/something/4/delete": Method Not Allowed
(Allow: POST, DELETE)
This response is clear and it's what I expected, so I tried to do something similar but using a form. Something like this:
<form id="formDelete" action="{{ path('entity_delete', { 'id': entity.id }) }}" method="post">
<input type="hidden" name="_method" value="DELETE" />
{{ form_widget(delete_form) }}
<a href="{{ url('entity_delete') }}" class="btn" onclick="document.getElementById('formDelete').submit();">
<img src="{{ asset('bundles/acme/images/delete.png') }}" ... />
</a>
</form>
But the line {{ form_widget(delete_form) }} is a problem because the indexAction() hasn't got any parameter and it needs this code:
$deleteForm = $this->createDeleteForm($id);
return $this->render('AcmeBundle:Demo:index.html.twig', array(
'entities' => $entities,
'delete_form' => $deleteForm->createView(),
));
As you can see, the $id param is mandatory for the method createDeleteForm($id) but I can't get it from indexAction().
Question:
What is the best way to solve this issue?
if you only want to have as much delete buttons as items in your index here's how to easily do it.
In the indexAction, add the following loop and don't forget to pass the parameter to the view.
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('FooBundle:Link')->findAll();
$deleteForms = array();
foreach ($entities as $entity) {
$deleteForms[$entity->getId()] = $this->createDeleteForm($entity->getId())->createView();
}
return array(
'entities' => $entities,
'deleteForms' => $deleteForms,
);
}
Basicaly I just loop over all my entities and create the corresponding delete form using the built-in method generated by the crud, storing each form in an array and passing it to the view.
Then in the view, just add the form already available in the edit.html.twig generated view and edit the form_widget's parameter:
<form action="{{ path('foo_delete', { 'id': entity.id }) }}" method="post">
<input type="hidden" name="_method" value="DELETE" />
{{ form_widget(deleteForms[entity.id]) }}
<button type="submit" class="btn btn-small">
<i class="icon-trash"></i>
{{ 'links.admin.form.delete' | trans({}, 'FooBundle') }}
</button>
</form>