Randomizing again in Django - django

When I generate a quiz in django, the question value before if request.method == 'POST': is one and then changed. Follow the screenshots.
views.py
questao = Questao.objects.annotate(resp_count=models.Count(models.Case(models.When(resposta__usuario=request.user, then=1),output_field=models.IntegerField()))).filter(resp_count=0,tipoQuestao=1).order_by("?").first()
print (questao)
if request.method == 'POST':
print (questao)
respostaform = RespostaForm(request.POST or None)
if respostaform.is_valid():
resp = respostaform.save(commit=False)
resp.idQuestao = questao
resp.save()
return HttpResponseRedirect(request.path_info)

Your view should look something like this, where you only fetch a random question when the request IS NOT POST:
if request.method == 'POST':
respostaform = RespostaForm(request.POST or None)
if respostaform.is_valid():
resp = respostaform.save()
return redirect(...)
else:
questao = Questao.objects\
.annotate(
resp_count=models.Count(
models.Case(
models.When(resposta__usuario=request.user, then=1),
output_field=models.IntegerField())))\
.filter(resp_count=0,tipoQuestao=1)\
.order_by("?")\
.first()
print(questao)
return render(request, 'some template', {'questao': questao})
Your RespostaForm should include a field named idQuestao (You did not show the code of the form, but I assume it is a ModelForm).
Does that help?

Related

Get Kwargs through an intermediate page

I have a model (grade) inside another model (homework) which is inside another model (activity) and when I submit the grade of a homework and try to get back to activty I loose the id of the activity. How do I get the right kwargs to get back to activity after submiting a grade? Or any other solution you may think about. Thanks in advance.
Views.py
def grade_homework(request, id):
if not request.user.is_authenticated:
return render(request, "auctions/login.html")
try:
activity = Activity.objects.get(id=id)
except Activity.DoesNotExist:
activity = None
try:
hw_upload = Hw_upload.objects.get(id=id)
except Hw_upload.DoesNotExist:
hw_upload = None
if request.method == 'POST':
form = Hw_gradeForm(request.POST, request.FILES or None)
if form.is_valid():
hw_grade = form.save(commit=False)
hw_grade.grader = request.user
hw_grade.hw_upload = Hw_upload.objects.get(id=id)
hw_grade.save()
url = reverse('activity', kwargs={'id': id})
return HttpResponseRedirect(url)
Urls.py
path("auction/course/module/activity/<str:id>", views.activity, name="activity"),
path("grade_hw/<int:id>", views.grade_homework, name="grade_hw"),

Django post-form cannot validate when using Form with additional inputs

I have a form containing af MultipleChoiceField where the choices are created dynamic based on the given user
class UpdateForm(forms.Form):
def __init__(self,names,*args,**kwargs):
super(UpdateForm,self).__init__(*args,**kwargs)
self.fields["list_names"] = forms.MultipleChoiceField(choices = zip(names,names),widget=forms.CheckboxSelectMultiple,label="Pick some names")
add_new = forms.BooleanField(initial=True, label="Add new names?",required=False)
delete_missing = forms.BooleanField(label = "Delete names?",required=False)
and it works fine as GET-request, the issues arrives with the post-request:
My view is the following:
def update(request):
user = request.user
list_names = MyModel.objects.filter(user=user).all().values_list("nick_name",flat=True).distinct()
form = UpdateWishlistForm(names =list_names)
if request.method == "POST":
post_form = UpdateForm(request.POST)
if post_form.is_valid():
list_names = post_form.cleaned_data["list_names"]
add_new = post_form.cleaned_data["add_new"]
delete_missing = post_form.cleaned_data["delete_missing"]
messages.success(request, "Success")
context = {
"form":form,
}
redirect("home")
else:
#invalid post_form
messages.error(request, "Error")
context = {
"form":form,
}
return render(request, "discounttracker/update.html")
else: #Get request
context = {
"form":form,
}
return render(request, "myapp/update.html",context=context)
The post_form = UpdateForm(request.POST) does not validate and the post_form.errors is empty.
It does contain data though (before calling post_form.is_valid())
print(post_form)
# UpdateForm: <UpdateForm bound=False, valid=Unknown, fields=(add_new;delete_missing;list_names)>
print(request.POST.dict())
#<QueryDict: {'csrfmiddlewaretoken': ['...'], 'add_new': ['on'], 'list_names': ['test_name_1']}>
but I notice it is not bound, thus not validating. But I cannot understand why it's not "binding" when parsing request.POST?
In the POST request, you need to pass the names as well, so:
list_names = MyModel.objects.filter(user=user).values_list("nick_name",flat=True).distinct()
form = UpdateWishlistForm(names=list_names)
if request.method == 'POST':
post_form = UpdateForm(names=list_names, data=request.POST)
# …
# …
But I would advise to work with a ModelMultipleChoiceField [Django-doc] and thus pass a queryset. Since the nick names apparently can contain duplicates, it might be better to make a Nickname model, and use ForeignKeys to that model.

Save and Continue in Django Forms

I have created a django form which at the moment I can only save the POST. Would like to add Save and Add another button in my templates and views function. Has anyone found a solutions.
if request.method == "POST":
form = StktxnsForm(request.POST )
if form.is_valid():
new_txns = form.save(commit=False)
new_txns.created_by = request.user
new_txns.save()
return redirect('pending_transactions')
else:
form = StktxnsForm()
return render(request,'new_transaction.html', {'form': form})
You may think use AJAX function to save and continue without reload. Send 'POST' request to save data in Ajax. It will help you.
I used like this in class-based view (vanilla method)
class PackageCreateView(View):
def get(self,request,*args,**kwargs):
return render(request,'package/create_package.html')
def post(self,request,*args,**kwargs):
if request.user.is_authenticated:
if request.method == 'POST':
data = request.POST
name = data.get('name')
detail = data.get('des')
price = data.get('price')
fname = Package.objects.all().filter(name=name)
if fname:
messages.info (request,'sorry name already exits')
return redirect ('create_package')
elif request.POST.get ('continue') :
pac = Package(name=name, detail=detail, price=price)
pac.save()
return redirect('create_package')
else:
pac = Package(name=name, detail=detail, price=price)
pac.save()
return redirect('packagelist')
else:
return redirect ('create_package')
else:
return redirect('login')
Here's one way to do it.
On your template:
<button type="submit" name="save_add" value="True">Save & Add another</button>
In your view:
if form.is_valid():
new_txns = form.save(commit=False)
new_txns.created_by = request.user
new_txns.save()
if request.POST.get('save_add'):
return redirect('create_transaction')
return redirect('pending_transactions')

Django forms "pattern" for this situation?

I'm pretty new to Python so that may be a stupid question but I'll ask it anyway. Is there a Django forms "design pattern" for this common view situation? When I run the view, I want it to act on one of two different types of forms depending on the type of user who's filling out the form. It seems ugly to have two if/then blocks inside the if request.method block to determine which type of form I'm acting on. What I'd like is to be able to refer to a "CreateProfileForm" that will refer to either a CreateManProfileForm or CreateWomanProfileForm depending on what's in the session variable.
Thanks!
def create_profile(request, template):
if request.session['user_type_cd'] == 'man':
is_man = True
else:
is_man = False
if request.method == "POST":
if is_man:
form = CreateManProfileForm(request.POST)
else:
form = CreateWomanProfileForm(request.POST)
if form.is_valid():
# Do stuff
return HttpResponseRedirect(reverse('do-next-thing'))
else:
if is_man:
form = CreateManProfileForm()
else:
form = CreateWomanProfileForm()
return render_to_response(template, locals(), context_instance=RequestContext(request))
You can do something like this:
Create a dictionary of the forms,
FORMS = {
0: CreateWomanProfileForm,
1: CreateManProfileForm
}
And in the views:
def create_profile(request, template):
is_man = 1 if request.session.get('user_type_cd') == 'man' else 0
if request.method == "POST":
form = FORMS.get(is_man)(request.POST)
if form.is_valid():
# Do stuff
return HttpResponseRedirect(reverse('do-next-thing'))
else:
form = FORMS.get(is_man)()
return render_to_response(template, locals(), context_instance=RequestContext(request))
Or even this should work
def create_profile(request, template):
is_man = 1 if request.session['user_type_cd'] == 'man' else 0
form = FORMS.get(is_man)(request.POST or None)
if request.method == "POST":
if form.is_valid():
# Do stuff
return HttpResponseRedirect(reverse('do-next-thing'))
return render_to_response(template, locals(), context_instance=RequestContext(request))

django - how to check if model is empty

I have settings form page. If user filled the form once; it must display those values. But if there is no data [first time] I get query error. I need that query, because the form data must be written as related with current user [logged in].
here is my view part :
#login_required(login_url='/login/')
def profile_page(request,username):
query = Profile.objects.get(owner__username = username) ##error!
if request.method == 'POST':
form = profile_form(request.POST,instance=query)
form.save()
return HttpResponseRedirect('/admin/')
else:
form = profile_form(instance=query)
return render_to_response('profile_save.html',{'form':form},context_instance = RequestContext(request))
I think I need to check the model and if it is empty I should do something different.
I am stuck.
Thank you
You want to make use of the .exists() queryset option
#login_required(login_url='/login/')
def profile_page(request,username):
form = profile_form()
if Profile.objects.get(owner__username = username).exists():
query = Profile.objects.get(owner__username = username)
if request.method == 'POST':
form = profile_form(request.POST,instance=query)
form.save()
return HttpResponseRedirect('/admin/')
else:
form = profile_form(instance=query)
return render_to_response('profile_save.html',{'form':form},context_instance = RequestContext(request))
see QuerytSet API reference for more information
You just need to wrap that get query in try ... except and set instance to none, like this.
from django.core.exceptions import ObjectDoesNotExist
#login_required(login_url='/login/')
def profile_page(request,username):
try:
query = Profile.objects.get(owner__username = username)
#to be more specific you can except ProfileObjectDoesNotExist
except ObjectDoesNotExist:
query = None #Doesn't exist, set to None
if request.method == 'POST':
form = profile_form(request.POST,instance=query)
form.save()
return HttpResponseRedirect('/admin/')
else:
form = profile_form(instance=query)
return render_to_response('profile_save.html',{'form':form},
context_instance = RequestContext(request))
I think i may have use get_or_create for this purpose.
Profile.objects.get_or_create(owner__username = username)