"Key 'itemsForRemove' not found in <QueryDict: {}>" - django

Temlate:
<form action="/remove_from_cart/" method="post">{% csrf_token %}
{% for item in request.session.cart %}
<div><input type="checkbox" name="itemsForRemove" value="{{ item.position }}"/>{{ item.product.name }}</div>
{% endfor %}
<p><input type="submit" value="Delete item"></p>
</form>
views.py
def RemoveProductFromCart(request):
removeThis = request.POST['itemsForRemove']
listOfItems = request.session['cart']
for i in removeThis:
del listOfItems[int(removeThis) - 1]
return redirect(request.path_info)
HTML in browser
<form action="/remove_from_cart/" method="post">
<div style="display:none">
<input type="hidden" name="csrfmiddlewaretoken" value="c49716c88a56e8e9884b31a233076b48"/>
</div>
<div>
<input type="checkbox" name="itemsForRemove" value="1"/>
Some text
</div>
<div>
<input type="checkbox" name="itemsForRemove" value="2"/>
Some text
</div>
<div>
<input type="checkbox" name="itemsForRemove" value="3"/>
Some text
</div>
<div>
<input type="checkbox" name="itemsForRemove" value="4"/>
Some text
</div>
<div>
<input type="checkbox" name="itemsForRemove" value="5"/>
Some text
</div>
<p>
<input type="submit" value="Delete item"/>
</p>
</form>
Raise exception: "Key 'itemsForRemove' not found in "
if I change "removeThis = request.POST['itemsForRemove']" to some think like: removeThis = request.POST['foo'], raise exception: "Key 'foo' not found in ". u'itemsForRemove': [u'6', u'7']} why?! And how i can this fix?

Your problem is that you are redirecting via request.path_info, which is just goint to redirect you back to your remove_cart view.
The reason your first error is "Key 'itemsForRemove' not found in " is because the first attempt worked and your view redirected to itself as GET, which clearly didn't have the itemsForRemove POST data.
When you changed your code to "foo", it's failing on your first POST stage (which is why you properly see "itemsForRemove").
Anyways, fix your redirect problem, then add a check to make sure your view is being called via POST.
def RemoveProductFromCart(request):
if not request.method == 'POST':
return http.HttpResponseForbidden()
removeThis = request.POST['itemsForRemove']
listOfItems = request.session['cart']
for i in removeThis:
del listOfItems[int(removeThis) - 1]
return redirect('somewhere_else')

If the request doesn't include the value for itemsForRemove it will raise an exception. Better way to do this is to use removeThis = request.POST.get('itemsForRemove', ''), it will give a default of '' and no exception is raised even if value doesn't exist.

Related

checkbox django return all false

My checkbox always return False value
my model
ho_so_giu=models.BooleanField(default=False)
my form
report_ho_so_giu = forms.BooleanField(widget=forms.CheckboxInput(attrs={'class':'form-check-input'}),required=False)
in my html template I add more code in my html template
<div class="col-md-8">
<form method="POST" id = "form_save_report" name ="form_save_report" value="form_save_report">
<div style="color:red;background-color:white">THÔNG TIN XỬ LÝ</div>
<div class="row">
{% csrf_token %}
<div class="form-group row">
<div class="col-md-4" id="labelsohd" name="labelsohd" style="display:none">Ngày hẹn</div>
<div class="col-md-6" id="so_hd" name="so_hd" type="number" style="display:none">{{form.so_hd}}</div>
<div class="form-group row">
<div name={{form.report_ho_so_giu.name}} id ="form.report_ho_so_giu.auto_id"> {{form.report_ho_so_giu}} </div>
<label class="form-check-label" for="{{form.report_ho_so_giu.auto_id}}">{{form.report_ho_so_giu.label}}</label>
</div>
</div>
</div>
<!-- Dòng 3 -->
<div class="row">
<div class="col-md-4">
<div class="form-group row">
<div class="card-footer" >
<button type="submit" class="fa fa-save" style="font-size:20px; color:blue" class="btn btn-primary btn-block" id="submit" name="submit">Lưu báo cáo</button>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
in my view, I add more code in my view
if request.method=='POST':
#print("request POST")
form=AddReportForm(request.POST)
if form.is_valid():
#print("if form")
so_hd=form.cleaned_data["report_so_hd"]
print(request.POST.get("report_ho_so_giu")) # return None
print(request.POST.get("id_report_ho_so_giu")) # return None
print(request.GET.get("report_ho_so_giu")) # return None
print(request.GET.get("id_ho_so_giu")) # return None
print(form.cleaned_data["id_report_ho_so_giu"]) # return False with checked or unchecked
print(form.cleaned_data["report_ho_so_giu"]) # return KeyError: 'report_ho_so_giu'
daily_report=report(so_hd=so_hd, ho_so_giu=ho_so_giu)
daily_report.save()
report_response_data={}
report_response_data["so_hd"]=so_hd
return JsonResponse({"so_hd":report_response_data["so_hd"],
})
I am using ajax to return my value from form but it still return only on whenever I check or uncheck box
ho_so_giu =$('#ho_so_giu_text').val() //return on
I try to print the result it just return "None" or "False" in my view, If I use console log in html file it retunr only "on". I read some question in stackoverflow and use some answer but it just return None or False
Is there any solution to replace checkbox in this case if I cannot find out the issue?
I think the problem might be with your form, try this:
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['ho_so_giu']
widgets = {
'ho_so_giu': forms.CheckboxInput(
'class': 'form-check-input',
'id': 'ho_so_giu_text',
'name': 'ho_so_giu_text'
)
}
Notes:
I dont know why you have given a name to the form. I have never seen that before. Could that be creating issues with the post request to the backend?
Have you tried building the form on the frontend by youserlf? Using just html? It would be a good way to debug the issue.
Consider writing a hybrid form, mostly in html, with dynamic elements. This will allow you to monitor exactly what's happening. Check out the example here below:
<input name="{{ wc_user_form.last_name.name }}" type="text" class="form-control" id="{{ wc_user_form.last_name.auto_id }}" placeholder="Votre Nom" oninput="customValidation(this);" required>
<label for="{{ wc_user_form.last_name.auto_id }}">{{ wc_user_form.last_name.label }}</label>
Pretty cool eh? Pay particular attention to the {{ form.field.auto_id }} template tag. That - as you can imagine - generates the id of the field that the backend expects in order to perform a form.save()

How to call a django function on click that doesn't involve changing page [duplicate]

My application currently flows through 3 pages:
User selects question in index page
User submits answer in answer page
User is presented with result in results page.
I want to compress that down to a single page where the user submits an answer to the question and result is shown on the same page.
The following django-template code separates questions with Bootstrap accordion. How do I post the form without refreshing the whole page? I want to be able to display the result on the page, update CSS styling with Javascript etc.
<h2>{{ category.title }}</h2>
<div class="accordion" id="accordion{{category.title}}">
{% for challenge in category.challenge_set.all %}
<div class="card">
<div class="card-header" id="heading{{challenge.id}}">
<h2 class="mb-0">
<button class="btn btn-link btn-block text-left" type="button" data-toggle="collapse" data-target="#collapse{{challenge.id}}" aria-expanded="true" aria-controls="collapse{{challenge.id}}">
{{ challenge.question_text }} - {{ challenge.point_value }} points
</button>
</h2>
</div>
<div id="collapse{{challenge.id}}" class="collapse in" aria-labelledby="heading{{challenge.id}}" data-parent="#accordion{{category.title}}">
<div class="card-body">
<p>{{ challenge.description }}</p>
<form action="{% url 'challenges:answer' challenge.id %}" method="post">
{% if challenge|is_answered:request %}
<label for="answered">Answer</label>
<input type="text" name="answered" id="answered" value="{{ challenge.answer_text }}" readonly>
{% else %}
{% csrf_token %}
<label for="answer">Answer</label>
<input type="text" name="answer" id="answer">
<input type="submit" value="Submit">
{% endif %}
</form>
</div>
</div>
{% endfor %}
</div>
Here is the view:
def index(request):
context = {'challenges_by_category_list': Category.objects.all()}
return render(request, 'challenges/index.html', context)
def detail(request, challenge_id):
challenge = get_object_or_404(Challenge, pk=challenge_id)
return render(request, 'challenges/detail.html', {'challenge': challenge})
def results(request, challenge_id, result):
challenge = get_object_or_404(Challenge, pk=challenge_id)
return render(request, 'challenges/results.html', {'challenge':challenge, 'result':result})
def answer(request, challenge_id):
challenge = get_object_or_404(Challenge, pk=challenge_id)
result = "Incorrect, try again!"
if challenge.answer_text.lower() == request.POST['answer'].lower():
current_user = request.user
session = User_Challenge(user=current_user, challenge=challenge, answered=True)
session.save()
points = Profile(user=current_user, points=challenge.point_value)
points.save()
result = "Correct!"
return HttpResponseRedirect(reverse('challenges:results', args=(challenge.id, result)))
You can try this:
Add the below script in your template:
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
write a script and a function inside it to submit the form data.
<script type="text/javascript">
function submitData( challenge_id ){
// Get answer from the input element
var answer = document.getElementById("answer").value;
// add the url over here where you want to submit form & challenge_id is also taken as a parameter.
var url = "<your_url>";
$.ajax({
url: url,
data: {
'answer': answer,
},
dataType: 'JSON',
success: function(data){
// show an alert message when form is submitted and it gets a response from the view where result is provided and if url is provided then redirect the user to that url.
alert(data.result);
if (data.url){
window.open(data.url, '_self');
}
}
});
}
</script>
Change type of the submit button and add an onclick event to call the submitData() function and pass the challenge id to it. And remove the action attr from the form.
see below:
<form method="post">
{% csrf_token %}
{% if challenge|is_answered:request %}
<label for="answered">Answer</label>
<input type="text" name="answered" id="answered" value="{{ challenge.answer_text }}" readonly>
{% else %}
<label for="answer">Answer</label>
<input type="text" name="answer" id="answer">
// over here
<button type="button" onclick="submitData({{ challenge.id }})">
Submit
</button>
{% endif %}
</form>
Return a JsonReponse to the ajax call from the views.
views.py
def answer(request, challenge_id):
answer = request.GET.get('answer', False)
url = False
if challenge.objects.filter(id=challenge_id).exists() and answer:
challenge = Challenge.objects.get(id=challenge_id)
if challenge.answer_text.lower() == answer.lower():
current_user = request.user
session = User_Challenge(user=current_user, challenge=challenge, answered=True)
session.save()
points = Profile(user=current_user, points=challenge.point_value)
points.save()
result = "Correct!"
# specify the url where you want to redirect the user after correct answer
url = ""
else:
result = "Incorrect, try again!"
data = {
'result': result,
'url': url
}
return JsonResponse(data)

Django why request.method=='GET' when refreshing the page

I want to have some search boxes on my page and my related codes are like below, my problem is why when i refresh the page the if clause: " if request.method=='GET':" executes without i click on any button ?
def allstocks_view(request):
if request.method=='GET':
question_set =Stocks.objects.all().filter(confirm=_('approved') )
name=request.GET.get('namesearch')
number=request.GET.get('numbersearch')
brand=request.GET.get('brandsearch')
if name is not None :
question_set = question_set.filter(name__icontains = name)
if number is not None :
question_set = question_set.filter(number__icontains = number)
if request.GET.get("brandsearch"):
question_set = question_set.filter(brand__icontains = brand)
print(">>>>>>>>>>>>>>>>>>>>")
print(question_set)
template :
<form method="get">
{% csrf_token %}
<div class="">
<label for="namesearch">Name</label>
<input type="text" name="namesearch" >
<label for="numbersearch"> Number</label>
<input type="text" name="numbersearch" >
<label for="brandsearch"> Brand</label>
<input type="text" name="brandsearch" >
<label for="brandsearch"> City</label>
<input type="text" name="citysearch" >
<input type="submit" name="search" value="Search">
</div>
</form>
A refresh of a page is a GET request unless your last action was a POST request so that is going to execute every time. What you could do is make the form a post and handle in a request.method == 'POST' block. Another option if you wanted to continute with GET would be have your view take an optional parameter such as search=None and set up your urls accordingly. Then in your view you could check for if search exists instead of request.method == 'GET'.

django authenticationform not showing all errors

My login works fine except for not showing all errors. When i type an invalid username or password, these errors don't show and the page just refreshes without putting any errors down.
However when i leave one field blank, it shows the correct error:
So the missing errors are(from source):
error_messages = {
'invalid_login': _("Please enter a correct %(username)s and password. "
"Note that both fields may be case-sensitive."),
'inactive': _("This account is inactive."),
}
my code:
def login_user(request):
"""Logs a user into the application."""
auth_form = AuthenticationForm(None, request.POST or None)
# The form itself handles authentication and checking to make sure password and such are supplied.
if auth_form.is_valid():
(request, auth_form.get_user())
return HttpResponseRedirect(reverse('index'))
return render(request, 'login.html', {'auth_form': auth_form})
My template:
<form action="{% url 'login_user' %}" method="post" class="login">{% csrf_token %}
<div>
<input name="username" placeholder="Username:" type="text" name="username" value="" id="username" class="login">
{{ auth_form.username.errors }}
</div>
<div>
<input name="password" placeholder="Password:" type="password" name="password" value="" id="password" class="login">
{{ auth_form.password.errors }}
</div>
<div>
<center>
<a href="{% url 'register_user' %}">
register
</a>
<button type="submit" class="link">
login
</button>
</center>
</div>
</form>
what do i do wrong?
You aren't including form.non_field_errors in your template. See the docs on customizing the form template for an example.
As an aside, the AuthenticationForm takes the request as its first argument. It looks slightly strange that you are passing None instead of request.

Django identifying non field validation error is associated with which form

Is there a way to identifying the validation error is associated with which form for a template contaning multiple forms?
Let me explain the scenario. I have login window popup script within my base.html
<div id="dialog1" class="window">
<form method="post" action="/accounts/login/?next=/IW/home" id='login-form' name=login-form>{% csrf_token %}
<div class="d-header">
{{ form.non_field_errors }}
<input type="text" name="username" id="id_username" value="" onclick="this.value=''"/><br/>
<input type="password" name="password" id="id_password" value="" onclick="this.value=''"/><br/>
<input type="hidden" name="login_form" value="1" />
<input type="submit" value="login" />
</div>
{% endif %}
</div>
</form>
</div>
<div id="mask"></div>
{% if form.non_field_errors %}
<script>
var maskHeight = $(document).height();
var maskWidth = $(window).width();
//Set heigth and width to mask to fill up the whole screen
$('#mask').css({'width':maskWidth,'height':maskHeight});
$('#mask').show();$('.window').show();
</script>
{% endif %}
As all other templates extends base,html whenever there is an error non_field error then login window pops up . I would like to show the login error only when login form is submit not on submit of someother form with a non field error.
For this I need to identify the name of the form.something like this {% ifequal form.form_name login_form %} - Display login error .Is this possible??
They isn't anything special about the name 'form' in the template. It's just a default context name, you can choose to name your forms anything you like.
Just name the forms differently in your context:
from django.http import Http404
def detail(request, poll_id):
# NOTE: This view code isn't really form processing code, just using it to show
# how you can pass different names into your template context.
login_form = MyLoginForm()
detail_form = MyDetailForm()
try:
p = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise Http404
return render_to_response('polls/detail.html', {'poll': p, 'login_form': login_form, 'detail_form': detail_form})
And then:
<div id="dialog1" class="window">
<form method="post" action="/accounts/login/?next=/IW/home" id='login-form' name=login-form>
{% csrf_token %}
<div class="d-header">
{{ login_form.non_field_errors }}
.
.
.
Also, if you want to do multiple instances of the same form type, have a look at formsets