I have a view where I want to pass a variable to my template, however the value is always passed as None, as shown in numerals 1 , 2 and 3.
What am I doing wrong please your help, I know it's a newbie question, actually I'm very newbie.
views.py
def create_address(request, dni):
person = None
addresses = None
if request.method == 'POST':
form = CreateAddressForm(request.POST)
if form.is_valid():
try:
person = Persona.objects.get(numero_documento=dni)
addresses = Direccion.objects.filter(numero_documento=dni)
print(f'Persona: {person}') # this print person ID.
f = form.save(commit=False)
f.numero_documento = person
f.save()
messages.success(request,
'Dirección registrada con éxito.'
)
if 'save' in request.POST:
return HttpResponseRedirect(reverse('persons:list'))
if 'add_data' in request.POST:
return HttpResponseRedirect(reverse('persons:create_address', kwargs={'dni': dni}))
except Persona.DoesNotExist:
messages.error(
request,
'El número de DNI no existe en la base de datos.'
)
except Direccion.DoesNotExist:
addresses = None
messages.error(
request,
'No se ha registrado ninguna dirección.'
)
else:
messages.error(
request,
'No se pudo registrar la dirección.'
)
else:
form = CreateAddressForm()
template = 'persons/addresses/create_address.html'
context = {
'pre_title': 'Direcciones domiciliarias',
'person': person, # (2) The value of "person" is "None".
'form': form,
'addresses': addresses,
}
return render(request, template, context)
template.html
(3) Value of "person" is "None".
<div class="tab-pane active show" id="tabs-address-data">
Number of ID is: {{ person }}
</div>
A person is probably a user. You only get this user if:
the request.method == 'POST'
the form.is_valid() returns True
Same with addresses - this only gets returned in the context as something other than None if the above two conditions are True.
You define both at the beginning of the function as None, so if nothing changes the None values, they will stay None.
In the case of a GET request, person and addresses will stay None because they never change. This is why you are seeing None for person.
I have modified my code as shown below, thanks for your answers.
I would like to know if my algorithm is now correct.
def create_address(request, dni):
try:
person = Persona.objects.get(numero_documento=dni)
addresses = Direccion.objects.filter(numero_documento=dni)
except Persona.DoesNotExist:
person = None
messages.error(
request,
'El número de DNI no existe en la base de datos.'
)
except Direccion.DoesNotExist:
addresses = None
messages.error(
request,
'No se ha registrado ninguna dirección.'
)
if request.method == 'POST':
form = CreateAddressForm(request.POST)
if form.is_valid():
f = form.save(commit=False)
f.numero_documento = person
f.save()
messages.success(
request,
'Dirección registrada con éxito.'
)
if 'save' in request.POST:
return HttpResponseRedirect(reverse('persons:list_persons'))
if 'add_data' in request.POST:
return HttpResponseRedirect(reverse('persons:create_address', kwargs={'dni': dni}))
else:
messages.error(
request,
'No se pudo registrar la dirección.'
)
else:
form = CreateAddressForm()
template = 'persons/addresses/create_address.html'
context = {
'pre_title': 'Direcciones domiciliarias',
'title': f'{person.nombres} {person.apellido_paterno} {person.apellido_materno}',
'object': person,
'form': form,
'addresses': addresses,
}
return render(request, template, context)
Related
Here is my form
class TypeCompteForm(forms.Form):
LIBELLES = (("xxxxx","xxxxxxx"),("xxxxxxxx","xxxxxxxxxx"))
libelle = forms.ChoiceField(required=True,choices=LIBELLES,error_messages=err_msg,widget=forms.Select(attrs={"class":"form-control","placeholder": "Libellé du type"}))
code = forms.CharField(required=True, max_length=50,widget=forms.TextInput(attrs={"class":"form-control","placeholder": "Code de du type"}))
def clean_libelle(self):
data = self.cleaned_data["libelle"]
if TypeMagasin.objects.filter(libelle=data).exists():
raise ValidationError("Un type de magasin avec ce libellé existe déjà !")
return data
With this form I manage to insert the data in the data base. But when I try to modify one record the clean_libelle method executes.
Below is the view I use for updating
def updateView(request,id):
instance = MyModel.objects.get(pk=id)
form = ModelForm(instance=instance)
if request.method == "POST":
form = ModelForm(request.POST, instance=instance)
if form.is_valid():
form.save()
else:
print(form.errors)
return render(request,"template.html")
return render(request,"reconciliation/template.html",{"form":form})
In your update view, the form instance is created twice. The first time it is created with form = ModelForm(instance=instance) and the second time it is created with form = ModelForm(request.POST, instance=instance). The first time it is created, the clean_libelle method is not called. The second time it is created, the method is called, which raises the validation error. To fix this issue, you need to skip the validation of the libelle field if the instance already exists in the database. You can achieve this by manually setting the value of the libelle field in the form before calling the is_valid method. Here's the updated view code:
def updateView(request, id):
instance = MyModel.objects.get(pk=id)
form = ModelForm(instance=instance)
if request.method == "POST":
form = ModelForm(request.POST, instance=instance)
if instance.libelle == form.cleaned_data["libelle"]:
form.cleaned_data["libelle"] = instance.libelle
if form.is_valid():
form.save()
else:
print(form.errors)
return render(request, "template.html")
return render(request, "reconciliation/template.html", {"form": form})
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.
I have an error I do not understand because the logic I use in my view has not changed and works for my other project. And when I read the Django doc, my logic's view is conform: https://docs.djangoproject.com/fr/2.2/topics/forms/#the-view
We call the form’s is_valid() method; if it’s not True, we go back to the template with the form. This time the form is no longer empty (unbound) so the HTML form will be populated with the data previously submitted, where it can be edited and corrected as required.
In my form, I have validation control.
My clean method below have 3 validations controls and the control #2 raised
errors <ul class="errorlist"><li>__all__<ul class="errorlist nonfield"><li>Ce patient ne peut être randomisé dans ce site. Veuillez vérifier votre saisie.</li></ul></li></ul>
So in my understanding of the doc, it should be redirected to the completed form with errors message display (as it do usually in my project) even if there is no else condition for no valid form in my view(is_valid() == False).
What is wrong?
views.py
def randomization_edit(request):
if request.method == "POST":
print("request", request.POST.dict())
form = RandomizationEditForm(request, data=request.POST or None)
if form.is_valid():
# do stuff
return redirect('randomization:confirmation', pk=randomisation.pk)
else:
if request.session.get('user_can_randomize'):
form = RandomizationEditForm(request)
return render(request, 'randomization/edit.html', {'form': form})
else:
return redirect("home")
forms.py
def clean(self):
cleaned_data = super(RandomizationEditForm, self).clean()
# control #1
if Randomisation.objects.filter(pat=self.data.get('pat').upper()).exists():
bras = Randomisation.objects.get(pat=self.data.get('pat').upper()).bra_lib
raise forms.ValidationError("Ce patient a déjà été randomisé dans le bras " + bras + ". Veuillez vérifier votre saisie.")
# control #2
if Pays.objects.get(pay_abr=self.data.get('pat').upper()[0:2]).pay_ide != int(self.data.get('pay_ide')):
raise forms.ValidationError("Ce patient ne peut être randomisé dans ce site. Veuillez vérifier votre saisie.")
# control #3
if not patient_code_is_valid(self.data.get('pat').upper()):
raise forms.ValidationError("Il y a incohérence entre le site et le pays dans le numéro patient. Veuillez vérifier votre saisie.")
return cleaned_data
If you make a POST request, and the form is not valid, you do not return any result. In that casee, one normally rerenders the template with the form containing the errors:
def randomization_edit(request):
if request.method == 'POST':
form = RandomizationEditForm(request, data=request.POST)
if form.is_valid():
return redirect('randomization:confirmation', pk=randomisation.pk)
else:
if not request.session.get('user_can_randomize'):
return redirect("home")
else:
form = RandomizationEditForm(request)
return render(request, 'randomization/edit.html', {'form': form})
The return render(…) will thus return a HTTP response in case it is a GET requjest with a user_can_randomize value for the session, or in case you make a POST request, and the from is not valid.
EDIT
finally I use window.onpopstate event to prevent user go back
it works with Firefox but not with Chrome 79 (and other browsers?)
I have read many posts and official documentation that seems to say that this 'bug' was fixed after Chrome 34... but doesn't seems to be
to be honest, event reading the documentation, I do not really understand this event and the behavior so far...
How can I resolve this?
I know this topic has been already discuss but none of solutions resolve my problem.
I have 3 forms that update the same models.
I would like to manage/prevent user going back using back arrow.
I tried using window.location, window.onhashchange = function () {}, flag session variable but nothing works and I am lost
When user click on back arrow from 2nd form to go back to 1st form, I would like either the event is blocked (best), either user is redirected to home page
I notice that click on back arrow on the 2nd form do not call index view, reason why 'flag strategy' do not work
#login_required
#permission_required('unblind.can_unblind')
def index(request):
if request.method == "POST":
form = AveugleProcedureForm(request, data=request.POST or None)
if form.is_valid():
unblind = form.save()
# database treatment
return redirect('unblind:edit', pk = unblind.pk)
else:
form = AveugleProcedureForm(request)
return render(request, 'unblind/index.html', {'form': form})
#login_required
#permission_required('unblind.can_unblind')
def edit(request, pk):
if request.method == "POST":
form = AveugleForm(request, data=request.POST or None)
if form.is_valid():
# unblind = form.save()
# database treatment
unblind = Aveugle.objects.get(unb_ide = pk)
unblind.unb_pro = form.cleaned_data['unb_pro']
unblind.unb_nom_dem = form.cleaned_data['unb_nom_dem']
unblind.unb_nom_rea = form.cleaned_data['unb_nom_rea']
unblind.unb_dat = form.cleaned_data['unb_dat']
unblind.pat = form.cleaned_data['pat']
unblind.unb_num = form.cleaned_data['unb_num']
unblind.unb_mot = form.cleaned_data['unb_mot']
unblind.save()
# contrôler le couple numéro patient/boite de médicament
# récupération du traitement
treatment = Medicament.objects.get(med_num = unblind.unb_num).med_dru
# envoie d'un email de confirmation
if treatment == 1:
unblind_treatment = _('ASPIRIN')
else:
unblind_treatment = _('PLACEBO')
email(unblind.pat,unblind.unb_num,unblind_treatment,unblind.unb_mot)
return redirect('unblind:result', pk = unblind.pk)
else:
form = AveugleForm(request)
return render(request, 'unblind/edit.html', {'form': form,'pk': pk})
#login_required
#permission_required('unblind.can_unblind')
def result(request, pk):
# Récupération de l'enregistrement
unblind = Aveugle.objects.get(unb_ide = pk)
treatment = Medicament.objects.get(med_num = unblind.unb_num).med_dru
if request.method == "POST":
form = AveugleResultForm(request, data=request.POST or None)
if form.is_valid():
# database treatment
unblind.unb_rec = form.cleaned_data['unb_rec']
# unblind.unb_com = form.cleaned_data['unb_com']
unblind.unb_log_dat = datetime.now()
unblind.unb_log = request.user.username
unblind.unb_log_sit = request.session['selected_site']
unblind.save()
return redirect('home')
else:
form = AveugleResultForm(request)
return render(request, 'unblind/result.html', {'form': form,'unblind':unblind,'treatment':treatment})
I have a form with a single ChoiceField (widget radioselect) whose choices are dynamically generated and render perfectly. When the form is submitted the POST data shows the correct value (1-5) for the choice selected (in live debug and in the browser debug info) but for whatever reason the form is considered unbound and invalid. Here's the form:
class ReValidateStudentForm(forms.Form):
bs_answer = forms.ChoiceField(widget=RadioSelect, label='Answer', required=True)
def __init__(self, possible_answers, *args, **kwargs):
super(ReValidateStudentForm, self).__init__(*args, **kwargs)
self.fields['bs_answer'].choices = possible_answers
FYI, "possible_answers" is a list of tuples passed to the form that is presenting perfectly as radio select choices when the fresh form is rendered. request.method does equal POST.
Any advice?
EDIT
Here's the form view code:
#login_required(login_url='/login/')
def ask_identity_questions(request):
si = StudentInfo.objects.get(student=request.user)
qnum = si.bs_question_number
if request.method == 'POST':
revalidateform = ReValidateStudentForm(request.POST)
try:
va = VerificationAnswers.objects.get(student=request.user, question_num=qnum)
except VerificationAnswers.DoesNotExist:
return render(request, "informational.html", {'message': 'User--question does not exist.'})
if revalidateform.is_valid():
va.student = request.user
va.question_num = si.bs_question_number
va.answer_choice = revalidateform.cleaned_data['bs_answer']
va.question_answered_time = timezone.now()
si.bs_question_number += 1
si.save()
return render(request, "informational.html", {'message': 'Thank you! Please click here to continue working through the course material.'})
else:
return render(request, 'questions.html', {'form': revalidateform, 'question_num': qnum, 'question': va.question_text})
else:
if qnum == 6:
return render(request, "informational.html", {'message': 'You have already answered all validation questions.'})
elif si.bs_qset_id == '':
return render(request, "informational.html", {'message': 'There is a problem with your identity validation information. Please contact customer support.'})
else:
# initialize blockscore account
client = blockscore.Client({'api_key':'sk_live_149dthis3ddiseb2f5notbebforebreal'})
si = StudentInfo.objects.get(student=request.user)
# set question ask time
# retrieve the user's question set using question set id stored in StudentInfo
# retrieve specific question from set based on value in StudentInfo
qset = client.question_sets.retrieve(si.bs_qset_id)
qset = qset.body
question = qset["questions"][qnum - 1].get("question")
# add verification question and mark time asked
try:
va = VerificationAnswers.objects.get(student=request.user, question_num=qnum)
except VerificationAnswers.DoesNotExist:
va = VerificationAnswers()
va.student = request.user
va.question_num = qnum
va.question_text = question
va.question_asked_time = timezone.now()
va.save()
# create answer list
possible_answers = []
# fill answer list with tuples of answer ids + answers
for answer in qset["questions"][qnum - 1].get("answers"):
possible_answers.append((answer.get("id"), answer.get("answer")))
revalidateform = ReValidateStudentForm(possible_answers)
return render(request, 'questions.html', {'form': revalidateform, 'question_num': qnum, 'question': question})