Auto Fill ModelForm with data already stored in database - django

I got a form as shown below and I want it to be filled with information from the database when its HTML is rendered. I am passing the id of the Coworker as a parameter for the view.
See code below:
view.py
def EditCoworker(request, id):
form = FormEditCoworker(Coworkers.objects.get(id=id))
if request.method == "POST":
form = FormEditCoworker(request.POST)
if form.is_valid():
form.save()
confirmation_message = "Coworker information updated successfully!"
return render(request, "coworkers/coworkers.html", locals())
else:
return render(request, "coworkers/edit_coworker.html", locals())
return render(request, 'coworkers/edit_coworker.html', locals())
forms.py
class FormEditCoworker(ModelForm):
class Meta:
model = Coworkers
urls.py
url(r'^edit_coworker/(?P<id>[\d]+)$', views.EditCoworker),
Of course the code in my views.py is not right.
Can someone help me on this?
Thanks in advance!

This line
form = FormEditCoworker(Coworkers.objects.get(id=id))
Should be
form = FormEditCoworker(instance=Coworkers.objects.get(id=id))
Although you should really handle the case where the Coworker doesn't exist
form = FormEditCoworker(instance=get_object_or_404(Coworkers, id=id))
EDIT: As Alisdair said, you should also pass the instance keyword arg to the bound form also
instance = get_object_or_404(Coworkers, id=id)
form = FormEditCoworker(instance=instance)
if request.method == "POST":
form = FormEditCoworker(request.POST, instance=instance)

Related

How to initialize value of foreign key in Django form

Im trying to initialize a model form where both fields are foreign key.
Model:
class Subcohort(models.Model):
cohort_id=models.ForeignKey(Cohort,on_delete=models.PROTECT,default=0,db_constraint=False,related_name='subcohortid')
parent_id=models.ForeignKey(Cohort,on_delete=models.PROTECT,default=0,db_constraint=False,related_name='subparentid')
Form:
class SubcohortForm(forms.ModelForm):
class Meta:
model = Subcohort
fields = [
"cohort_id","parent_id",
]
Views:
initialvalue2={
'cohort_id':int(cohortidnew),
'parent_id':id,
}
form2 = SubcohortForm(initialvalue2)
if form2.is_valid():
return redirect('/dashboard')
It is saying my form is not valid. Can someone explain what is the reason behind this and how to fix this?
Thanks.
Because, you have not saved that form after validation.
let's save it:
if form2.is_valid():
form2.save()
return redirect('/dashboard')
And now your problem will be solved..
If you need the form intialize with these values, then please pass the values using initial parameter when initiaiting form object:
initialvalue2={
'cohort_id':int(cohortidnew),
'parent_id':id,
}
form2 = SubcohortForm(initial = initialvalue2)
You can send this form2 instance to the template directly without validating it. But you should check if the form is valid on post request. For example:
if request.method == 'GET':
form2 = SubcohortForm(initial = initialvalue2)
return render(request, template_name, context={'form2':form2})
else:
form = SubcohortForm(request.POST)
if form.is_valid():
form.save()
return redirect('dashboard')
else:
return render(request, template_name, context={'form2':form})

Django: form.is_valid() error, but only after "if request.method == 'POST'"?

When I print(formexam) BEFORE the if request.method == 'POST', it shows the appropriately filled out form items (the exam was created earlier, now I'm just updating it to make changes as desired).
However, when I print(formexam) AFTER if request.method == 'POST', it shows the form fields (at least several of them, I didn't look at every single one) to be empty. What makes that happen?
(In my example code below, I am printing the errors instead of the form.)
Also, a very very similar views.py function (changeExam, bottom of this post) works just fine.
Thank you!
views.py
def updateExam(request, pk):
exam = Exam.objects.get(id=pk)
formod = form_od.ODForm(instance=exam.od)
formos = form_os.OSForm(instance=exam.os)
formexam = ExamForm(instance=exam)
print(f'The errors are: {formexam.errors}')
if request.method == 'POST':
formexam = ExamForm(request.POST, instance=exam)
print(f'The errors are: {formexam.errors}')
formod = form_od.ODForm(request.POST, instance=exam.od)
formos = form_os.OSForm(request.POST, instance=exam.os)
if formod.is_valid() and formos.is_valid():
print("these are valid")
if formexam.is_valid():
print("so is this one.")
#save exam
instance = formexam.save(commit=False)
instance.save()
#save OD
instance = formod.save(commit=False)
instance.save()
#save OS
instance = formos.save(commit=False)
instance.save()
else:
print("Exam form not valid.")
#save OD
instance = formod.save(commit=False)
instance.save()
#save OS
instance = formos.save(commit=False)
instance.save()
else:
print("No forms are valid.")
context = {
'formod': formod,
'formos': formos,
'formexam': formexam,
'exam': exam,
}
return render(request, 'accounts/form_exam_update.html', context)
Results of hitting submit button:
The errors are:
The errors are: <ul class="errorlist"><li>doctor<ul class="errorlist">.<li>This field is required.</li></ul></li><li>examtype<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
these are valid
Exam form not valid.
However, this very similar one works:
views.py
def changeExam(request, pk):
exam = Exam.objects.get(id=pk)
form = ExamForm(instance=exam)
if request.method == 'POST':
form = ExamForm(request.POST, instance=exam)
if form.is_valid():
print(form)
form.save()
next = request.POST.get('next', '/')
return HttpResponseRedirect(next)
context = {
'form': form,
}
return render(request, 'accounts/form_exam.html', context)def
Figured it out!
On changeExam, the resultant HTML page (form_exam.html) has <form> tags with all of the fields within the <form> tags. Therefore, no error.
On updateExam, it's a larger page (form_exam_update.html) using Django template tags to include things in different sections, and I realized a few of the fields (e.g. doctor, examtype) were outside of the <form> tags.
I updated the HTML code so that all corresponding fields were within the <form> tags, and it now works as desired!

Delete record without accessing it directly

I am creating a data visualisation site in django and using the rest api for my data. Is there any way of deleting a record without accessing its url directly, as in this case it is impossible.
Something like
def employee_delete(request):
instance = Employee.objects.get(social_security=request.POST)
instance.delete()
return render(request, "dashboard.html")
This only works if you have access to the console as I learned, so I tried to access the data from a form like so
def employee_delete(request):
if request.method == "POST":
form = delete_EmployeeForm(request.POST, request.FILES)
if form.is_valid():
instance = Employee.objects.get(social_security=request.POST)
instance.delete()
return render(request, "dashboard.html")
else:
form = delete_EmployeeForm()
return render(request, "deleteemployee.html",{'form': form})
Would this work if I was able to be more specific about which piece of data I was accessing from the form? I got a typeError trying to use request.Post in that manner. That form contained a single field in 'social_security' from the Employee model.
Thanks
def employee_delete(request):
if request.method == "POST":
form = delete_EmployeeForm(request.POST, request.FILES)
if form.is_valid():
instance = Employee.objects.get(social_security=request.POST['social_security'])
instance.delete()
return render(request, "dashboard.html")
else:
form = delete_EmployeeForm()
return render(request, "deleteemployee.html",{'form': form})
use this in your view

Create, get and edit user information in same form and template

I'm trying to retrieve data from user. The form where i want to show the user information is also the same that i use to update this information.
Update3
After some updates I make this work and this is my code. If somenone have a better way to do this can share it :)
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class informacionFacturacion(models.Model):
usuario = models.ForeignKey(User, on_delete=models.CASCADE)
apellidos = models.CharField(max_length=100)
nombres = models.CharField(max_length=100)
[More fields...]
def __str__(self):
self.apellidos
forms.py
from .models import informacionFacturacion
#Create your forms here.
class informacionFacturacionForm(ModelForm):
class Meta:
model = informacionFacturacion
fields = [
"usuario",
"apellidos",
"nombres",
[More fields...]
]
views.py
#login_required
def datosPersonales(request):
#Filter query by user ID
query = informacionFacturacion.objects.filter(usuario=request.user)
form = informacionFacturacionForm()
#If query has content, edit record, else, create a new record
if query:
if request.method == "POST":
form = informacionFacturacionForm(request.POST or None, instance=query[0])
if form.is_valid():
edit_content = form.save()
edit_content.save()
else:
if request.method == "POST":
form = informacionFacturacionForm(request.POST)
if form.is_valid():
create_content = form.save(commit=False)
create_content.save()
return HttpResponseRedirect(reverse('datosPersonales'))
context = {
"titulo": "Datos personales | Co.",
"body_class": "class= sidebar_main_open sidebar_main_swipe",
"form": form,
"infoFacturacion": query,
}
template = "micuenta/datosPersonales.html"
return render(request, template, context)
Thanks for the support.
At first glance, it seems that the informacionFacturacion table is not being populated. Have you checked that the instance.save() is reached? (in other words, that the form is valid)
Second, in the template you want to use the informacionFacturacion object as the form elements, and you are handling them separately. Do:
if request.POST:
form = informacionFacturacionForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
else:
# handle here the form error's, maybe report it in the template
else:
query = informacionFacturacion.objects.filter(usuario=request.user)
form = informacionFacturacionForm(instance=query[0])
and render the form parameter insead of infoFacturacion:
{{ form.as_p }}
finally, make sure that your template form id's matches the form element names, otherwise the form won't be filled.
UPDATE
Based on your edit, now the error is in this line:
form = informacionFacturacionForm(request.POST, instance=query_id)
query_id is an int, and it is expecting a model. Change the following line:
query_id = informacionFacturacion.objects.get(usuario=request.user).id
to
query = informacionFacturacion.objects.get(usuario=request.user)
and the faulty line to:
form = informacionFacturacionForm(request.POST, instance=query)
that should work for now, although code can be simplified a lot.
EDIT 2
Here is what I assume you want:
#login_required
def datosPersonales(request):
query = informacionFacturacion.objects.filter(usuario=request.user)
if request.method == "POST": # This will handle the template form's POST
form = informacionFacturacionForm(request.POST)
if form.is_valid():
asd = form.save(commit=False)
asd.save()
# Here you may want to redirect to somewhere else
# Im not sure here, I guess that you want to handle the GET method if
# there is no form in the request. Post your template form to see what
# is happening.
else:
form = informacionFacturacionForm(instance=query)
# you dont need to save it, it is already in DB
context = {
"titulo": "Datos personales | Co.",
"body_class": "class= sidebar_main_open sidebar_main_swipe",
# I think here is your main issue, you are handling a form object
# AND a infoFacturacion object. You need to use just the
# form object in the template and render it accordingly.
"form": form,
"infoFacturacion": query,
}
template = "micuenta/datosPersonales.html"
return render(request, template, context)
Well, I was with the same problem on my sytem, so I made this solution, maybe it works to you! =D
I'm changing the value of the submit button and using the same form:
<button type="submit" id="submitButton" name="button" value="">Save</button>
If is a new task, I change the value of the button with JQuery:
$('#submitButton').val('new');
And if is an edition, I change the value again:
$('#submitButton').val('edit');
On my views.py, I check if is an edit or a new save by the value of the button:
def index(request):
tasks = Task.object.filter()
context = {
'tasks': tasks
}
if request.method == 'POST':
form = NewTask(request.POST or None)
if request.POST['button'] == 'new':
if form.is_valid():
context['is_valid'] = True
form.save()
form = NewTask()
else:
context['is_valid'] = False
if request.POST['button'] == 'edit':
instance = Task.object.filter(pk=request.POST['id']).first()
form = NewTask(request.POST, instance=instance)
if form.is_valid():
context['is_valid'] = True
form.save()
else:
context['is_valid'] = False
else:
form = NewTask()
context['form'] = form
return render(request, 'index.html', context)

Insert or update data with Django formsets

it's not clear to me how to manage formsets in Django. This is my views.py:
def newAd(request):
newAdFormSet = modelformset_factory(Ad)
if request.method == 'POST':
formset = newAdFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
return render_to_response('conf.html',
{'state':'Your ad has been successfull created.'},
context_instance = RequestContext(request),)
else:
formset = newAdFormSet()
return render_to_response('ad_form.html',
{'form':formset},
context_instance=RequestContext(request),)
It works but it always returns one prefilled form for each existing tuple plus, at the end, a blank form.
Now, i can't get how to say where it must return a blank form (to perform a new insert), and where it must instead return a single prefilled form (possibly passing the Ad's id) to perform an update.
modelformset_factory and formset helps to solve a lot, take your code for example
def newAd(request):
newAdFormSet = modelformset_factory(Ad, extra=1)
if request.method == 'POST':
formset = newAdFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
return render_to_response('conf.html',
{'state':'Your ad has been successfull created.'},
context_instance = RequestContext(request),)
else:
formset = newAdFormSet(queryset=Ad.objects.all())
return render_to_response('ad_form.html',
{'form':formset},
context_instance=RequestContext(request),)
Note the extra=1 in modelformset_factory line, it ensures there is only one extra blank form. And queryset=Ad.objects.all() in the second newAdFormSet inside else statement, it pre-fills forms for Ad objects from DB and correctly set PK in, mostly hidden, field for backend code to recognize submitted objects.
update
if you want to set Ad().codU to point to an User() instance, request.user for example, you could simply just set it by
instances = formset.save(commit=False)
for obj in instances:
obj.codU = request.user
obj.save()
I'm still not 100% clear what your question is, but it sounds like you don't want a formset at all. If you're only interested in adding or updating a single record at a time, you want a simple ModelForm, not a formset. So:
class AdForm(forms.ModelForm):
class Meta:
model = Ad
def add_update_ad(request, pk=None):
if pk is not None:
instance = Ad.objects.get(pk=pk)
else:
instance = Ad()
if request.POST:
form = AdForm(request.POST, instance=instance)
if form.is_valid():
new_instance = form.save()
return HttpResponseRedirect('my_confirmation_view')
else:
form = AdForm(instance=instance)
return render(request, 'ad_form.html', {'form': form})