How to get a serie of request.POST values - python

In the following views.py:
def valores(request):
global peso_unitario, preco_unitario
peso_unitario=[]
preco_unitario=[]
N=a
print('N='+str(N))
for i in range(N):
peso_u=request.POST['peso_u']
preco_u=request.POST['preco_u']
if peso_u.isdigit() and preco_u.isdigit():
c = int(peso_u)
d = int(preco_u)
peso_unitario.append(c)
preco_unitario.append(d)
print(a)
print(preco_unitario)
if i<N-1:
return render(request, 'valores.html')
else:
return render(request, 'pacote.html',
{'peso_unitario': peso_unitario, 'preco_unitario': preco_unitario})
else:
res = 'Apenas numero.'
return render(request, 'pacote.html', {'res': res})
I have a function that receives a global value N=a, this value was received from the user, now I need to receive N times the both values in request.POST loop, but each time the user needs to enter the values. I don't know how to do this.

This is your python code, as per your problem you need to make a loop in your template to take input from user N times or maybe take values of peso_u and preco_u in a list whose length must be equal to N here.

Related

Future-proofing my application code for readability (Django, Beginner)

The aim of my website is to have a page, let's call it "Random Question!"
Each time the user enters the page, a set of numbers are randomly generated, and they have to correctly answer the question: numbera + number b .
IF they are correct, they go to a page that says "Correct" and then they are redirected back to the same page, again, with a different set of numbers.
Now, the issue is, on the first page "Random Question!", I want to add another question to it.
Views.py:
def form_handle(request):
if request.method == 'POST':
form = MyForm(request.POST) # if post method then form will be validated
if form.is_valid():
cd = form.cleaned_data
num1 = cd.get('num1')
a = request.session.get('a', 0)
b = request.session.get('b', 0)
if float(num1) == float(a + b):
# give HttpResponse only or render page you need to load on success
return render(request, 'sectipn1part1success', {})
else:
# if sum not equal... then redirect to custom url/page
return HttpResponseRedirect('rr/') # mention redirect url in argument
else:
a = random.randrange(5,10);
b = random.randrange(10,20);
request.session['a'] = a
request.session['b'] = b
question1 = ('What is ' + str(a) + ' + ' + str(b) + ' ?')
form = MyForm() # blank form object just to pass context if not post method
context = {
'form': form,
'a': a,
'b': b,
'question1': question1
}
return render(request, "section1part1.html", context)
As you can see, right now it only does one simple style of question, addition only (question 1).
I would like to add another question, such as question 2, which could be something like "What is a / 2".
Something like the above would be achieved using something like a Java SWITCH statement ( I am not sure if Django has it, though it should be possible to do it without it). A random number would be generated corresponding to another question. Then I'd have to use another IF statement after if request.method == 'POST' to calculate the correct answer as each new question would be calculated differently.
Now, the above would be a good strategy in the short term.
In the long term, I am not sure if it is ideal. Is there a better way of doing this sort of thing or is my way ok?
I was thinking of other ways including:
Using a view-dispatcher sort of function, for example, it would call another view instead of everything on one view but I am not sure of this is possible
** Are there any performance considerations I should be aware of ? **
Update #1
Ok, I've gone ahead and implemented what I suggested above. This is what happens:
Django view gets called --> Another view function is randomly called and does the processing and returns a context object
else: #add another 'if' randomiser to selection question function randomly
context = question1(request)
context = question2(request)
return render(request, "section1part1.html", context)
Is this good practice / style? Should I just continue doing it this way?
form_handle should only be responsible for handling forms. All the work of creating questions and answers should be done by something else. Once you do that, it's easy to to switch out question types, or generate endless loops of questions, or create a list of questions to loop through, or ...
Here's an example with a Question class. You could just as easily create functions that return a tuple of (question, answer) or any other variety of question/answer generators.
class Question(object):
def answer(self):
raise NotImplementedError
def question(self):
raise NotImplementedError
class AdditionQuestion(Question):
def __init__(self):
a_range = (5, 10)
b_range = (10, 20)
self.a = random.randrange(*a_range)
self.b = random.randrange(*b_range)
def answer(self):
return self.a + self.b
def question(self):
return 'What is {} + {}?'.format(self.a, self.b)
class MultiplicationQuestion(Question):
def __init__(self):
a_range = (100, 200)
b_range = (10, 20)
self.a = random.randrange(*a_range)
self.b = random.randrange(*b_range)
def answer(self):
return self.a * self.b
def question(self):
return 'What is {} * {}?'.format(self.a, self.b)
then, your code only relies on an object that has object.question() and object.answer(). If you want non-numeric answers, or answers that are close enough (ex: 3.3333 is close enough to 3.333333) you can change if float(num1) == float(answer): to if compare_answers(num1, answer): and then write a compare_answers function.
def form_handle(request):
if request.method == 'POST':
form = MyForm(request.POST) # if post method then form will be validated
if form.is_valid():
cd = form.cleaned_data
num1 = cd.get('num1')
answer = request.session.get('answer', 0)
if float(num1) == float(answer):
# give HttpResponse only or render page you need to load on success
return render(request, 'sectipn1part1success', {})
else:
# if sum not equal... then redirect to custom url/page
return HttpResponseRedirect('rr/') # mention redirect url in argument
else:
question = AdditionQuestion()
answer = question.answer()
request.session['answer'] = answer
form = MyForm() # blank form object just to pass context if not post method
context = {
'form': form,
'answer': answer,
'question': question.question()
}
return render(request, "section1part1.html", context)
If you want a random question-type generator, also make that its own function/object. Keep it separated from the form_handle so that it's easy to change:
def random_question():
class_ = random.choice([MultiplicationQuestion, AdditionQuestion])
return class_()
then change the line here from:
else:
question = AdditionQuestion()
to:
else:
question = random_question()

How can I simplify this Django view?

I have an app that shows some questions to the user. It has to reply in input text fields and then there's a view that checks all these results (the one below).
This view perfectly works but I know I made a mess with dictionaries and lists. I thought to create those just to prepare a results variable that then I'll print on the HTML page. How can I simplify it?
def check(request):
# Initialize results
results = []
i = 0
for input_name, input_value in request.POST.items():
# Remove cfsr from inputs
if input_name.isdigit():
# Get the question from the input name
question = Question.objects.get(pk=input_name)
# Get the related correct answer to that question
answer = question.answer
# Create results
results.append({'question_text': question.text, 'user_answer': input_value,
'correct_answer': answer.text})
# Check if user answer is correct
if input_value == answer.text:
results[i]['is_correct'] = True
else:
results[i]['is_correct'] = False
i += 1
context = {'results': results}
return render(request, 'quiz/results.html', context)
You could make these improvements for readability:
Create a list of the inputs that you want to access; the if check for the csrf_token field makes the code more difficult to read, and the assumption that csrf_token always contains letters may not be true.
Remove the counter variable (i); counters like this in for loops aren't pythonic, and often just complicate the code.
Replace the if/else test for the correct answer with a boolean expression; you can always to this with if/else blocks that simply assign True or False to a variable depending on the result of some test.
Build your results dictionary completely before appending to the list to avoid having to access via its index (results[i]...).
from django.http import HttpResponseNotAllowed, HttpResponseBadRequest
def check(request):
if not request.method == 'POST':
return HttpResponseNotAllowed(['POST'])
# guaranteed by CsrfViewMiddleware to exist
del request.POST['csrfmiddlewaretoken']
results = []
for question_id, user_answer in request.POST.items():
try:
question = Question.objects.get(pk=name)
except Question.DoesNotExist:
return HttpResponseBadRequest("Oops!")
results.append({
'question_text': question.text,
'user_answer': user_answer,
'correct_answer': question.answer.text,
'is_correct': value == question.answer.text,
})
return render(request, 'quiz/results.html', {
'results': results,
})
You can replace
if input_value == answer.text:
results[i]['is_correct'] = True
else:
results[i]['is_correct'] = False
with
results[-1]['is_correct'] = input_value == answer.text
and get rid of the i
or even better you could put that in the results.append
results.append({'question_text': question.text,
'user_answer': input_value,
'correct_answer': answer.text,
'is_correct': input_value == answer.text})

Django calling an another function inside from a view function

The views.py somthing like this
def getFormValues(request):
if ('mobile_a' in request.GET and request.GET['mobile_a']) and ('mobile_b' in request.GET and request.GET['mobile_b']):
mobile_a = request.GET['mobile_a']
mobile_b =request.GET['mobile_b']
# calling the mark calculation function
return calculateMark(mobile_a, mobile_b)
else:
message ='You submitted an empty form.'
return HttpResponse(message)
Here I am calling a function(calculateMark) which will calculate a marking. In the end of the calculateMark function I have something like this
if (tech_mark_a == 0 and tech_mark_b == 0):
mobile_a_infos = TechSpecificationAdd.objects.filter(tech_variables)
return render_to_response('degrees_result.html', {'mobile_a': tech_mark_a, 'mobile_b': mobile_b}, mobile_a_infos)
elif (tech_mark_a > 0 and tech_mark_b > 0):
return render_to_response('degrees_result.html', {'mobile_a': tech_mark_a, 'mobile_b': mobile_b})
The Problem is when I am submitting an empty form It's showing the message as getFormValues(). But when I submit something on the form it's showing an error The view MarkCalculation.views.getFormValues didn't return an HttpResponse object.
How can I solve the problem? Thanks in advance.
Fix your calculateMark() function so that it doesn't have any code paths that don't return a response. Also, consider converting the arguments to numbers first.

How to get django form wizard extra_context to show on template?

EDIT: FWIW, I am running django 1.3
I have...
class CreateProductWizard(FormWizard):
def get_template(self, step):
if step == 1:
return 'product/form_wizard/editor.html'
else:
return 'product/form_wizard/wizard_%s.html' % step
def process_step(self, request, form, step):
if step == 1:
self.extra_context = {'ptype': form.cleaned_data}
return
else:
return
def done(self, request, form_list):
# now that it's all together, store it.
return render_to_response('product/form_wizard/done.html',
{'form_data': [form.cleaned_data for form in form_list]},
context_instance=RequestContext(request))
and I'd like to get the self.extra_context to the template.
How do I get that on the template?
I've tried on the template:
{{extra_context}}
{{form.extra_context}}
{{form.extra_context.ptype}}
etc..
Looking at the docs i'd say that get_context_data is what you are after:
Returns the template context for a step. You can overwrite this method
to add more data for all or some steps. This method returns a
dictionary containing the rendered form step.
So what I ended up using on the template was:
{{ptype}}
which I had already tried.
The problem, and I'm still not sure why was that I had:
def process_step(self, request, form, step):
if step == 1:
self.extra_context = {'ptype': form.cleaned_data}
return
else:
return
and what worked was:
def process_step(self, request, form, step):
self.extra_context = {'ptype': 'hello!!',}
For some reason, the 'step' that is being passed to 'process_step()' is always == 0 which made my 'if step ==1:' logic fail...
After reviewing the source (django.contrib.formtools.wizard.FormWizard), one thing that looks like it could be failing on is my form is not valid. It must be valid for the step number to increment and call the process_step function. HOWEVER, the {{step}} variable is getting the right value. And I'm not doing anything crazy with the form...
So weird. But my main question is solved.

django 1.3 forms validation using clean method to retrieve getlist

I have a form with checkboxes, the form functioning well, in my view i can use request.POST.getlist('list') to retrieve the list of values.
At the moment am trying to do some form validation inside the clean method and when i try to use self.cleaned_data['list'] I get the last value. I cannot retrieve the list of items.
Any idea how i could do that?
forms.py
class SelectList_Form(forms.Form):
list = forms.CharField(required=False)
def clean(self):
super(SelectList_Form, self).clean()
cleaned_data = self.cleaned_data
try:
# TODO: list validation
if cleaned_data['list'].__len__() is 0:
raise forms.ValidationError(_('Must select at least one of the lists below'),)
if cleaned_data['list'].__len__() > 1:
try:
# In here when i print list it only shows me the last value. It doesn't show me the list of values when the box is checked
print cleaned_data['list']
except Main.DoesNotExist:
raise Http404
except forms.ValidationError:
raise
class Posting_Wizard(FormWizard):
def render_template(self, request, form, previous_fields, step, context=None):
if step == 0:
obj = MainI18n.objects.filter(main__is_active=True, language=request.LANGUAGE_CODE).\
exclude(main__parent=None).order_by('main__parent').select_related(depth=1)
category_choices=dict(['%s,%s' % (i.main.slug, i.main.parent.slug), '%s - %s' % (i.main.parent,i.label)] for i in obj)
form.fields['categories'] = forms.CharField(widget=forms.RadioSelect(choices=category_choices.items()))
if step == 1:
category = request.POST.get('0-categories')
pobj = Main.objects.filter(slug=category.split(',')[1], parent=None).get()
cobj = Main.objects.filter(slug=category.split(',')[0], parent=pobj.id).get()
lobj = ListI18n.objects.filter(list__is_active=True, language=request.LANGUAGE_CODE, list__main__slug=category.split(',')[0], list__main__parent=pobj.id).select_related()
list_choices = dict([i.id, i.title] for i in lobj)
if cobj.mainproperties.relation == 'M':
# Here i generate the checkboxes
form.fields['list']=forms.CharField(widget=forms.CheckboxSelectMultiple(choices=list_choices.items()),label="Pick the list",)
else:
form.fields['list']=forms.CharField(widget=forms.RadioSelect(choices=list_choices.items()),label="Pick the list",)
return super(Posting_Wizard, self).render_template(request, form, previous_fields, step, context)
def done(self, request, form_list):
return HttpResponseRedirect(reverse('accounts-registration-wizard-done'))
def get_template(self, step):
return 'listing/post/wizard/wizard_%s.html' % step
First, there are a number of basic Python errors here. There is almost never a need to access the double-underscore functions - they are internal implementation details. Always use the normal len() function instead. And, never use is for comparisons: it's for identity, so should only be used with things you know have the same identity, which basically just means None. So your code should read:
if len(cleaned_data['list']) == 0:
etc.
Now, secondly, I don't understand why you think there could ever be more than one 'element' in list. You've defined it as a CharField, which is a single field containing many characters. Your len is testing the number of characters entered into that field, not the number of fields, however you think you've defined them.

Categories

Resources