Django: Save forms independently - html

I have two forms in two different tabs in the same template. The models of the forms are connected through a foreign key.
When I'm trying to save each form independently having a submit button for each form, but unfortunately the two forms are trying to save data again, even I push only one submit button.
Views.py
def input(request):
my_demographics = DemographicForm(request.POST or None)
my_diagnosis = DiagnosisForm(request.POST or None)
context = RequestContext(request)
if request.method == 'POST':
submitted = request.POST.get('form_id', '')
if submitted == 'demographics':
# Get the Form1 instance
my_demographics = DemographicForm(request.POST)
if my_demographics.is_valid():
my_demographics_object= my_demographics.save()
my_diagnosis=DiagnosisForm({'patient': my_demographics_object.patient_id})
elif submitted == 'diagnosis':
# Get the Form2 instance
my_diagnosis = DiagnosisForm(request.POST)
if my_diagnosis.is_valid():
my_diagnosis.save()
else:
raise ValueError('No form specified !')
return render_to_response('input.html', {'frm':my_demographics, 'frm_d': my_diagnosis}, context)
input.html
<div class="tab-content">
<!-- Tab panes -->
<form class="tab-pane fade in active" id="demographics" method="post" >
<input type="hidden" name="form_id" value="demographics">
{%crispy frm%}
</form>
<form class="tab-pane fade" id="diagnosis" method="post">
<input type="hidden" name="form_id" value="diagnosis">
{%crispy frm_d%}
</form>
</div>

First add an hidden input in each of your forms, which will specify which form is posted:
<div class="tab-content">
<!-- Tab panes -->
<form class="tab-pane fade in active" id="demographics" method="post" >
<input type="hidden" name="form_id" value="demographics">
{%crispy frm%}
</form>
<form class="tab-pane fade" id="diagnosis" method="post">
<input type="hidden" name="form_id" value="diagnosis">
{%crispy frm_d%}
</form>
</div>
Then in your view, check which form is posted and only save this form.
edit:
def input(request):
context = RequestContext(request)
if request.method == 'POST':
submitted = request.POST.get('form_id', '')
if submitted == 'demographics':
# Get the Form1 instance
my_demographics = DemographicForm(request.POST)
if my_demographics.is_valid():
my_demographics_object= my_demographics.save()
my_diagnosis=DiagnosisForm({'patient': my_demographics_object.patient_id})
else:
my_diagnosis=DiagnosisForm()
elif submitted == 'diagnosis':
# Get the Form2 instance
my_diagnosis = DiagnosisForm(request.POST)
if my_diagnosis.is_valid():
my_diagnosis.save()
# here you should redirect
my_demographics = DemographicForm()
else:
raise ValueError('No form specified !')
else:
my_demographics = DemographicForm()
my_diagnosis = DiagnosisForm()
return render_to_response(
'input.html',
{'frm':my_demographics, 'frm_d': my_diagnosis},
context
)

The view will have the input names that were inside the form submitted only, that is how you now, so you can add a hidden field and check for its value, if form1, or form2 then you know witch one have being submitted !
if request.POST:
# Get the form submitted
submitted = request.POST.get('form_name', '')
if submitted == 'form1'
# Get the Form1 instance
form = Form1Model(request.POST)
elif submitted == 'form2'
# Get the Form2 instance
form = Form2Model(request.POST)
else:
raise ValueError('No form specified !')
# Validate the form
if form.is_valid():
# If the form is valid save it
if form.save():
# correct data entry
messages.info(
request,
_(u"Fichier copié sur le DHS, mise à jour en cours ...")
)
else:
# Can't save the form
messages.warning(
request,
_(u"Un problème est survenu pendant l'enregistrement "
u"des données, merci de réessayer plus tard.")
)
else:
# Form is not valid, show feedback to the user
messages.error(
request,
_(u"Merci de corriger les erreurs suivantes.")
)
else:
# Empty forms this is the first call
form1 = Form1Model()
form2 = Form2Model()
# Disclaimer
messages.warning(
request,
_(u"L'interface web sera inaccessible durant la mise à jour.")
)

Related

Contact form not saving in the Database , is it the views or the HTML?

I have an issue in Django where the contact form after being filled out doesn't save in the database unless I just filled out the message text area :
My views :
def CV_page(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# Save form data to Django models
contact = Contact(name= form.cleaned_data['name'],
email= form.cleaned_data['email'],
phone= form.cleaned_data['phone'],
message= form.cleaned_data['message'])
contact.save()
# Send email to admin
send_mail('CV-Website-contact',
form.cleaned_data['message'],
form.cleaned_data['email'],
['xxxx#xxxx.com', form.cleaned_data['email']])
return HttpResponse('success') #HttpResponseRedirect('success/') # create a success page
else:
form = ContactForm()
else:
form = ContactForm()
context = {'Abouts': latest_description, 'form': form, 'categories': categories, 'portfolios': portfolios, 'pdf': final_pdf_link}
return render(request, 'cv_page.html', context)
models.py
class Contact(models.Model):
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
name = models.CharField(max_length=100, null=True, blank=True)
email = models.EmailField(max_length=254, null=False, blank=True)
phone = PhoneNumberField(null=True, blank=True, unique=False)
message = models.CharField(max_length=2500, null=True, blank=True)
created_on = models.DateTimeField(auto_now_add=datetime.datetime.now)
updated_on = models.DateTimeField(auto_now=datetime.datetime.now)
forms.py
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
fields = ['name', 'email', 'phone', 'message']
my HTML:
<!-- Contact Section-->
<section class="page-section" id="contact">
<div class="container">
<!-- Contact Section Heading-->
<h2 class="page-section-heading text-center text-uppercase text-secondary mb-0">Contact Me</h2>
<!-- Icon Divider-->
<!-- Contact Section Form-->
<div class="row justify-content-center">
<div class="col-lg-8 col-xl-7">
<form method="post">
{% csrf_token %}
{{form.as_p}}
<div class="form-actions">
<button type="submit">Send</button>
</div>
</form>
</div>
</div>
</div>
</section>
I don't understand why it would only save if there is only the message text area filled out ?
Thank you very much
As you've defined the model already in the forms.py you can simply save the form by:
form = ContactForm(request.POST)
if form.is_valid():
# Save form data to Django models
form.save()
# Send email to admin
# ... your additional code here
also add action="" in your HTML-form tag:
<form method="post" action="">
The action argument defines the url for the post request. An empty string will load the same page again. You can also define a custom url.
Everything else looks fine.
Edit 1: (comment 1)
The issue with the reload is because your form.is_valid() fails and then your page reloads:
if form.is_valid():
# ... your code
else:
form = ContactForm()
Remove the last two lines of the code above. If your form fails youre page gets reloaded like before but you'll see the errors in your form.
Here's the working snippet:
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# Save form data to Django models
form.save()
# Send email to admin
send_mail('CV-Website-contact',
form.cleaned_data['message'],
form.cleaned_data['email'],
['xxxx#xxxx.com', form.cleaned_data['email']])
return HttpResponse('success')
else:
form = ContactForm()

How Do I Properly Submit Two Forms Within One HTML Structure?

I am trying to submit a create view with two forms. The code below works fine if everything is filled out and the form submitted. However if fields are omitted in form2...the form submission fails and the field that was filled out for "form"..."name"....gets reset. I've read you can do multiple forms and I've largely got this working...I just need to figure out how to incorporate form2 into the if_valid().... Here's my view...
def tasklist_detail_view(request, id):
context = {}
context["tasklist"] = TaskList.objects.get(id=id)
context["tasks"] = Task.objects.filter(task_list=id).all()
obj = get_object_or_404(TaskList, id=id)
form = UpdateTaskListForm(request.POST or None, instance=obj)
form2 = TaskForm(request.POST or None)
context["task_list_id"] = id
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse("MyTaskLists:my_task_list_main_menu"))
context["form"] = form
context["form2"] = form2
return render(request, "my_task_list_tasklist_detail.html", context)
My HTML...
<form method="POST" enctype="multipart/form-data" id="forms">
{% csrf_token %}
{{ form.name }}
{% include "my_task_list_task_create_form1.html" with tasklist=tasklist %}
<button type="submit" class="button66" name="status" value="Submitted">Submit</button>
</form>
And then in my include HTML...
<div id="task-list-form" hx-target="this" hx-swap="outerHTML">
<button class="button35" hx-post="{% url 'MyTaskLists:task-create' id=task_list_id %}">Save</button>
{{ form2 }}
I did try to do something like....
if form.is_valid() and form2.is_valid():
form.save()
return HttpResponseRedirect(reverse("MyTaskLists:my_task_list_main_menu"))
But then nothing happens...the forms are not accepted at all even if the fields are filled out properly....From what I've read I understand the POST is being applied to both forms....if one is not filled out properly that is why the other errors out? I just can't quite figure out how to process them both properly.
Thanks in advance for any thoughts.
If you want the two forms to behave like one form, and save two objects only if both forms are valid, then the logic is
if form.is_valid() and form2.is_valid():
form.save()
form2.save()
return HttpResponseRedirect(reverse("MyTaskLists:my_task_list_main_menu"))
context["form"] = form
context["form2"] = form2
return render(request, "my_task_list_tasklist_detail.html", context)
If there is any field with the same name in form and form2 you need to use a prefix to remove the ambiguity.
form = UpdateTaskListForm(request.POST or None, instance=obj, prefix='form1')
form2 = TaskForm(request.POST or None, prefix='form2')

Using django Authentication form with the html form

I am trying to build a login module in django. I already have a nice HTML form for login which has username and password field.
But in my views.py I have imported default Django AuthenticationForm, but if integrate it with my nice-looking HTML form, there will be two forms. How can I import the Authentication form and use it with the my HTML form??
My code is here:
My view:
def login(request):
if request.method == 'POST':
form = AuthenticationForm(data=request.POST)
if form.is_valid():
user = form.get_user()
authlog(request, user)
return redirect('home')
else:
messages.error(request, 'Invalid username or password')
# back_page = request.META.get('HTTP_REFERER')
return redirect('login')
# return HttpResponse(back_page)
else:
content = {
'form': AuthenticationForm()
}
return render(request, 'sign-in.html', content)
If I use Django default form, the code will be following, but it won't look good as my other Html login page.
My sign-in html:
<hr>
<form action="" method="post">
{% csrf_token %}
{{form|crispy}}
<button type="submit" class=" btn btn-success ">Sign-Up</button>
</form>
I haven't posted my other HTML form though as it is very large. Hope it explains.

Is it possible to loop a custom model form in django?

Is it possible to create multiple objects for a model in django by looping the same form in a for loop. I am using a custom model form.
My template is:
{% for query in queryset %}
<form method="POST" action="{% url 'academics' %}" style=" padding: 5%">
{% csrf_token %}
<input type="text" name="Student" class="form-control" id="id_Student"
value="{{query}}">
<input type="text" name="Subject" class="form-control" required id="id_Subject">
<input type="checkbox" name="Presence" id="id_Presence">
<button type="Submit" id="submit">Submit</button>
{% endfor %}
<button type="Submit" id="submit">Submit</button>
</form>
My models.py is:
class Attendance(models.Model):
Student = models.CharField(max_length=100, blank=False)
Hour = models.CharField(max_length=1, blank=False)
Subject = models.CharField(max_length=8, blank=False)
Date = models.DateTimeField(default=timezone.now)
Presence = models.BooleanField(default=False, blank=False)
def __str__(self):
return f'{self.Student}'
My views.py is:
def academics(request):
if request.user.is_staff:
form = forms.AttendanceForm()
context = {
'form': form,
'queryset': User.objects.filter(profile__Year='SY',profile__Department='CSE')
}
if request.method == "POST" :
form = forms.AttendanceForm(request.POST)
if form.is_valid():
student = request.POST.get('Student')
hour = request.POST.get('Hour')
subject = request.POST.get('Subject')
boolean = request.POST.get('Presence')
def bool(boolean):
if boolean == 'on':
return 'True'
else:
return 'False'
form = Attendance(Student=student,Hour=hour,Subject=subject,Presence=bool(boolean))
form.save()
return render(request, 'console/academics.html',context)
Currently i can create multiple objects, but with the same values of the last form. ie, the object is created with the values of last form. Here i have looped the form so that n number of forms will be generated for n queries with the name filled automatically in the first field. I know explaining this is little complex. Anyone can help?
I'm not entirely clear what you mean by "looping a form", but if you want the user to be able to enter a list of arbitrary length of similar sets of data, then what you want is a Formset or a ModelFormset. When it comes back, you validate all the data that he has submitted, and if it's all good then you iterate through it, usually creating or modifying multiple objects.
Due to reputation I'm unable to comment but I believe this is how you achieve your desired result. by using WHILE LOOP.
I myself have not much knowledge of python & Django but I guess this is the logic. Please correct me if I am wrong instead of down voting.
var = 0
n = 5
if request.method == "POST":
form = forms.AttendanceForm(request.POST)
if form.is_valid():
while var < n:
student = request.POST.get('Student')
hour = request.POST.get('Hour')
subject = request.POST.get('Subject')
boolean = request.POST.get('Presence')
def bool(boolean):
if boolean == 'on':
return 'True'
else:
return 'False'
form = Attendance(Student=student, Hour=hour,Subject=subject,Presence=bool(boolean))
form.save()
var += 1
return render(request, 'console/academics.html', context)

Invalid form when uploading file in Django

I need to upload file on a Django page, however, after following the official tutorial, I was not able to upload it, it always gives the error "invalid form", and when I tried to print out the error msg of the form, it says "This field is required".
One thing notable is: I have 2 forms on one page, one is this upload form and the other one is for filling out information. Not sure if this is the root cause.
I have tried all solutions provided on the Internet.
Template file:
<form id="uploadForm" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="file" value="upload" name="sourcefile">
<button type="submit">Upload</button>
</form>
Forms.py:
from django import forms
from .models import SourceFile
class UploadFileForm(forms.ModelForm):
class Meta:
model = SourceFile
fields = ('file', 'title')
Models.py:
from django.db import models
# Create your models here.
class SourceFile(models.Model):
title = models.CharField(max_length=255, blank=True)
file = models.FileField(upload_to="media/")
Views.py
def model_form_upload(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
instance = SourceFile(file_field=request.FILES['file'])
instance.save()
return JsonResponse({'error': False, 'message': 'Uploaded Successfully!'})
else:
print("Invalid form")
# return JsonResponse({'error': True, 'errors': form.errors})
else:
form = UploadFileForm()
return render(request, 'source_validation.html', {'form': form})
Your template is wrong. Either use {{ form.as_p }} which should display a file input field because file is a field in your form. (so remove the <input type="file" ...>)
Or don't use it and manually add the <input> fields, but then you must use the correct names. Your form expects a "file" parameter, not a "sourcefile" parameter:
<input type="file" name="file">
Also, you're overcomplicating things in your view (even though your current code will work if you fix your template):
if form.is_valid():
form.save() # this will save your model
return redirect(...)