Issues handling 2 forms in same django template - python

I'm trying to have 2 different forms in same template. Dropdown in one of the forms is not showing any data. I've looked at other posts here but all seem to be quite overwhelming and confusing.
forms.py
class BookOnlineForm(forms.ModelForm):
patient_name = forms.CharField(max_length=250, required= True,widget=forms.TextInput())
phone = forms.CharField(max_length=200, required= True,widget=forms.TextInput())
preference = forms.ChoiceField(required=True, choices = PREFER_CHOICES, widget = forms.Select)
class Meta:
model = Booking
fields = ("patient_name","phone")
class UserContentForm(forms.ModelForm):
time = forms.ChoiceField(required=True, choices = TIME_CHOICES, widget = forms.Select)
comment = forms.CharField(max_length=2000, required= False,widget=forms.TextInput())
class Meta:
model = UserContent
fields = ("time","comment")
views.py
def showDocProfile(request, id):
try:
doctor = Doctor.objects.get(id=id)
except Doctor.DoesNotExist:
raise Http404
clinic = Clinic.objects.get(id=doctor.clinic.id)
# User content comments and like begin here
params = {}
params.update(csrf(request))
if request.user.is_authenticated():
user = request.user
# User Content Form
if request.method == "POST":
form = UserContentForm(request.POST)
if form.is_valid():
time = form.cleaned_data['time']
comment = form.cleaned_data['comment']
if request.POST.get('Like') == 'Like':
con = UserContent(time=time, comment = comment, liked = True, disliked = False, doctor_id = doctor.id, user_id = request.user.id)
con.save()
elif request.POST.get('Like') == 'Dislike':
con = UserContent(time=time, comment = comment, liked = False, disliked = True, doctor_id = doctor.id, user_id = request.user.id)
con.save()
url = '/dp/%s' % str(doctor.id)
return HttpResponseRedirect(url)
else:
form = UserContentForm()
# BookingOnline Form
if request.method == "POST":
form = BookOnlineForm(request.POST)
if form.is_valid():
patient_name = form.cleaned_data['patient_name']
preference = form.cleaned_data['preference']
phone = form.cleaned_data['phone']
lead = Booking(doctor_id=doctor.id, preference = preference, patient_name=patient_name, phone=phone)
lead.save()
url = '/dp/%s' % str(doctor.id)
return HttpResponseRedirect(url)
else:
form = BookOnlineForm()
d.update({'doctor': doctor, 'clinic': clinic,'form': form, })
return render(request, 'm1/dp.html', d)
dp.html
The usercontent form is working fine. It's just the Booking form is not showing any preferences in the dropdown menu
<form action="" method="post" id="user_uploader" > {% csrf_token %}
<input type="hidden" name="doctor" value="{{ doctor.id }}" />
<input type="text" class="form-control" placeholder="Your Name" id="patient_name" name = "patient_name">
<input type="text" class="form-control" placeholder="Your Number" id="phone" name = "phone">
<select class="form-control" id="preference" name="preference">
<option><b>Time</b></option>
{% for value, text in form.preference.field.choices %}
<option value="{{ value }}">{{ text }}</option>
{% endfor %}
</select>
{% for field in form.visible_fields %}
{{ field.errors }}
{% endfor %}
<button class="btn btn-primary" type="submit" name="submit" id="ss-submit">Submit Booking Request</button>
</form>

You should use a different name for the UserContentForm and the BookForm, instead of calling them both form.
# User Content Form
if request.method == "POST":
user_content_form = UserContentForm(request.POST)
...
else:
user_content_form = UserContentForm()
# BookingOnline Form
if request.method == "POST":
book_online_form = BookOnlineForm(request.POST)
...
# watch this indentation. In your question above it is incorrect.
else:
book_online_form = BookOnlineForm()
d.update({'doctor': doctor, 'clinic': clinic,'book_online_form': book_online_form, 'user_content_form': user_content_form})
You will have to replace form with the correct variable in the rest of the view and your template.
Ideally, you should use a prefix when including multiple forms in the same template. However, doing that will require additional changes in your template, as you have hardcoded the form fields (e.g <input ...>), instead of letting Django render them (e.g. {{ form.patient_name }}).

Related

image in django won't upload via form

I already found many answers to that question but most of them refer to adding request.FILES wchich doesn't work for me. I can upload an image via admin page, but when it comes to form i am getting an error that image is not loaded (while it is)
Here is my model
class Player(models.Model):
name = models.CharField(max_length=30)
surname = models.CharField(max_length=30)
position = models.ForeignKey(Position,on_delete=models.CASCADE)
shirt_number = models.IntegerField()
team = models.ForeignKey(Team,null=True,on_delete=models.SET_NULL)
image = models.ImageField(upload_to='images/players/')
Here is my form
class PlayerForm(forms.ModelForm):
class Meta:
model = Player
exclude = ('team',)
Here is views.py
def team_detail(request,slug):
team = get_object_or_404(Team, slug=slug)
players = Player.objects.filter(team_id=team.id)
if request.method == "POST":
form = PlayerForm(request.POST,request.FILES)
if form.is_valid():
form.save()
return redirect('')
else:
form = PlayerForm()
return render(request,'team_detail.html',{'team':team,'players':players,'form':form})
And here is template file
<form method = "POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="SUBMIT">
</form>
Before submitting
After pressing submit button
You need to specify the enctype="…" attribute [mdn] to encode the file properly:
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="SUBMIT">
In the view you will also need to specify a value for the Team of the instance you create:
def team_detail(request,slug):
team = get_object_or_404(Team, slug=slug)
if request.method == 'POST':
form = PlayerForm(request.POST, request.FILES)
if form.is_valid():
form.instance.team = team
form.save()
return redirect('name-of-some-view')
else:
form = PlayerForm()
players = Player.objects.filter(team=team)
return render(request,'team_detail.html', {'team':team,'players':players,'form':form})

IntegrityError at /update_dept/1/ NOT NULL constraint failed: main_department.dept_name

I am creating a simple django models of doctors and department. there is not link between them and when I try to update the department then it is show me this error IntegrityError at /update_dept/1/ NOT NULL constraint failed: main_department.dept_name this error is new for me. I check other similar question also but didn't get much. so pls help me.
here is my view.py file
from django.shortcuts import render
from .forms import Doctorslist,Departmentform
from .models import Department, Doctor
from django.shortcuts import redirect
from django.views.generic import (CreateView, DetailView, UpdateView, ListView, TemplateView, DeleteView)
from django.contrib.messages import constants as messages
import os
# Create your views here.
def add_show(request):
form = Doctorslist()
if request.method == "POST":
form = Doctorslist(request.POST, request.FILES)
form.save()
return redirect('/')
else:
form = Doctorslist()
stud = Doctor.objects.all
context = {'form':form,
'stu':stud
}
return render(request, 'main/index.html', context)
def update_data(request, id):
prod = Doctor.objects.get(id=id)
if request.method == "POST":
prod.doc_image = request.FILES['doc_image']
prod.kycdocument = request.FILES['kycdocument']
prod.name = request.POST.get('name')
prod.phone_number = request.POST.get('phone_number')
prod.email = request.POST.get('email')
prod.city = request.POST.get('city')
prod.speciality = request.POST.get('email')
prod.save()
messages.success(request, "Product Updated Successfully")
return redirect('/')
context = {'prod':prod}
return render(request, 'main/update_doc.html', context)
def delete_data(request,id):
if request.method =='POST':
pi = Doctor.objects.get(pk = id)
pi.delete()
return redirect('/')
def add_show_dept(request):
form = Departmentform()
if request.method == "POST":
form = Departmentform(request.POST)
form.save()
return redirect('/')
else:
form = Departmentform()
dept = Department.objects.all
context = {'form':form,
'stu':dept
}
return render(request, 'main/pages-profile.html', context)
def update_dept_data(request, id):
prod = Department.objects.get(id=id)
if request.method == "POST":
prod.dept_name = request.POST.get('dept_name')
prod.dept_Email = request.POST.get('dept_Email')
prod.save()
messages.success(request, "Product Updated Successfully")
return redirect('/')
context = {'prod':prod}
return render(request, 'main/update_dept.html', context)
here is model.py
from django.db import models
from phonenumber_field.modelfields import PhoneNumberField
import os
# Create your models here.
import datetime
def get_file_path(request, filename):
filename_original = filename
nowTime = datetime.datetime.now().strftime('%Y%m%d%H:%M:%S')
filename = "%s%s" % (nowTime, filename_original)
return os.path.join('uploads/', filename)
class Doctor(models.Model):
name = models.CharField(max_length=20)
phone_number = PhoneNumberField(null=False, blank=False, unique=True)
email = models.EmailField(max_length = 100)
city = models.CharField(max_length=100)
speciality = models.CharField(max_length=50)
doc_image = models.ImageField(upload_to = get_file_path)
kycdocument = models.ImageField(upload_to = get_file_path, null = True, blank = True)
class Department(models.Model):
dept_name = models.CharField(max_length=20)
dept_Email = models.EmailField(max_length=100)
dept_password = models.CharField(max_length=200)
here is forms.py file
from django import forms
from phonenumber_field.modelfields import PhoneNumberField
from .models import Doctor,Department
class Doctorslist(forms.ModelForm):
class Meta:
model = Doctor
fields = ('name','phone_number','email', 'city', 'speciality', 'doc_image', 'kycdocument')
# widgets = {
# 'name': forms.TextInput(attrs = {'class': 'form-control'}),
# 'email': forms.EmailInput(attrs={'class': 'form-control'}),
# 'city': forms.CharField(attrs={'class': 'form-control'}),
# 'speciality': forms.CharField(attrs={'class': 'form-control'}),
# }
class Departmentform(forms.ModelForm):
class Meta:
model = Department
fields = ('dept_name','dept_Email','dept_password')
widgets = {'dept_password': forms.PasswordInput()}
here is update_dept.html file
{% extends 'base.html' %}
{% block content %}
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<h2 class="fw-bold">Edit Product</h2>
</div>
<div class="card-body">
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="mb-3">
<label for="" class="form-label">Name</label>
<input type="text" Required name="name" value="{{ prod.dept_name }}" class="form-control">
</div>
<div class="mb-3">
<label for="" class="form-label">Email</label>
<input type="text" Required name="price" value="{{ prod.dept_Email }}" class="form-control">
</div>
<button type="submit" class="btn btn-warning">Update</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
Your HTML form uses the wrong names, and therefore request.POST does not contain any entries like dept_name and dept_Email. You should specify name="dept_name" instead of name="name" and name="dept_Email" instead of name="price":
<div class="mb-3">
<label for="" class="form-label">Name</label>
<input type="text" Required name="dept_name" value="{{ prod.dept_name }}" class="form-control">
</div>
<div class="mb-3">
<label for="" class="form-label">Email</label>
<input type="text" Required name="dept_Email" value="{{ prod.dept_Email }}" class="form-control">
</div>
That being said, I would strongly advise that you use a ModelForm, you can make a second ModelForm for the department where you leave out the dept_password.
You can see the Rendering fields manually section of the documentation that shows how you can render you Django form with custom HTML.

Django Form Field not showing up

I just started learning Django and for this project I'm following the "Tango with Django" tutorial book. I have a problem with the input field of a form not showing up, while the button seems to be rendered fine.
Here's my code:
models.py
[...]
class Idea(models.Model):
keyword = models.ForeignKey(Keyword)
word = models.CharField(max_length=120)
count = models.IntegerField(default=1)
def __str__(self):
return self.word
forms.py
[...]
class Meta:
model = Keyword
fields = ('name',)
class IdeaForm(forms.ModelForm):
word = forms.CharField(max_length=120)
count = forms.IntegerField(widget=forms.HiddenInput(), initial=1)
class Meta:
model = Idea
fields = ('word',)
exclude = ('keyword',)
views.py
[...]
def keyword_detail(request, keyword_name_slug):
form = IdeaForm()
context_dict = {}
try:
keyword = Keyword.objects.get(slug=keyword_name_slug)
ideas = Idea.objects.filter(keyword=keyword)
context_dict['keyword'] = keyword
context_dict['ideas'] = ideas
except Keyword.DoesNotExist:
context_dict['keyword'] = None
context_dict['ideas'] = None
if request.method == 'POST':
form = IdeaForm(request.POST)
if form.is_valid():
idea = form.save(commit=False)
idea.keyword = keyword
idea.count = 1
idea.save()
return keyword_detail(request, keyword_name_slug)
else:
print(form.errors)
context_dict['form'] = form
return render(request, 'openminds/keyword.html', context_dict)
keyword.html
[...]
<h3>Add a new Idea</h3>
<div>
<form id="idea_form" method="post" action="">{% csrf_token %}
{% for hidden in forms.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in forms.visible_fields %}
{{ field.errors }}
{{ field }}
{% endfor %}
<input type="submit" name="submit" value="Add Idea" />
</form>
</div>
I think you're passing in form to the template, but attempting to use forms.

How do I prevent form submission if the form is invalid?

So when the form is invalid and I click submit, it just redirects to /home because of return redirect('/'). So what do I have to return here to prevent form submission and raise an error message? Here's my code:
views.py
class BoxesView(ListView, FormMixin):
template_name = 'polls.html' # extends base.html
form_class = UserRegistrationForm
def get_context_data(self, **kwargs):
context = super(BoxesView, self).get_context_data()
question_list = Question.objects.all().order_by('-date')
choice = Choice.objects.all()
context['question_list'] = question_list
context['choice'] = choice
q_list = []
returned_list = []
for i in question_list:
q_list.append(i)
for a, b in CATEGORY_CHOICES:
name = resolve(self.request.path_info).url_name
if b == name:
category = a
search = self.request.GET.get('search')
posts = Post.objects.all().filter(category=category).order_by('-date')
if search:
posts = posts.filter(
Q(title__icontains=search) |
Q(content__icontains=search)
)
else:
posts = Post.objects.all().filter(category=category).order_by('-date')
context['posts'] = posts
total = 0
for post in posts:
returned_list.append(post)
total += 1
if total == 4:
total = 0
for i in q_list:
returned_list.append(i)
q_list.remove(i)
break
paginator = Paginator(returned_list, 14)
page = self.request.GET.get('page')
try:
lst = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
lst = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
lst = paginator.page(paginator.num_pages)
context['lst'] = lst
return context
def get_queryset(self):
pass
def register(request):
form = UserRegistrationForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
email = form.cleaned_data['email']
user = User.objects.create_user(username=username, password=password, email=email)
user.save()
return redirect('/')
else:
print(form.errors)
form = UserRegistrationForm()
return redirect('/')
And in my forms.py it raises an exception error to the terminal but the form still submits.
forms.py
class UserRegistrationForm(forms.ModelForm):
email = forms.EmailField()
username = forms.CharField(max_length=25)
password = forms.CharField(widget=forms.PasswordInput)
confirm_password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = [
'username',
'email',
'password',
]
def clean(self):
email = self.cleaned_data.get('email')
current_emails = User.objects.filter(email=email)
if current_emails.exists():
raise forms.ValidationError("That email is taken")
base.html
<form method="post" enctype="multipart/form-data" action="{% url 'register' %}">{% csrf_token %}
<div class="registerBox">
<p><label for="id_username"></label> <input id="id_username" type="text" name="username" maxlength="30" placeholder="username"/></p>
<p><label for="id_email"></label> <input type="email" name="email" id="id_email" placeholder="email"/></p>
<p><label for="id_password"></label> <input type="password" name="password" id="id_password" placeholder="password"/></p>
<p><label for="id_confirm_password"></label> <input type="password" name="confirm_password" id="id_confirm_password" placeholder="confirm password"/></p>
<input type="submit" value="register" />
</div>
</form>
Any idea?
You shouldn't be trying to prevent submission when the form is invalid. What you should be doing is accepting the submission, checking the errors, then returning the errors and the filled-in form to the template.
But you are doing three things that prevent that: you are always re-instantiating the form when it is invalid, you always redirect, and you don't show errors or previous values in the template.
So you should do this:
def register(request):
form = UserRegistrationForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
email = form.cleaned_data['email']
user = User.objects.create_user(username=username, password=password, email=email)
user.save()
return redirect('/')
return render('mytemplate.html', {"form": form})
and in the template:
<div class="registerBox">
{{ form.non_field_errors }}
<p>{{ form.username.label_tag }} {{ form.username }} {{ form.username.errors }}</p>
<p>{{ form.email.label_tag }} {{ form.email }} {{ form.email.errors }}</p>
<p><label for="id_password"></label> <input type="password" name="password" id="id_password" placeholder="password"/></p>
<p><label for="id_confirm_password"></label> <input type="password" name="confirm_password" id="id_confirm_password" placeholder="confirm password"/></p>
<input type="submit" value="register" />
</div>
have you tried
if form.is_valid():
...
else:
return form_invalid(form)
You should use ajax validation if you do not want to submit invalid form.

django template form not saving data

I have a template form and trying to save some data. Upon clicking on the submit button the page just refreshes and nothing gets saved to the database. I don't get any errors on anything.
template
<form action="" method="post" id="salesform">
{% csrf_token %}
<input type="name" class="form-control" id="name" placeholder="Name">
<input type="clinic" class="form-control" id="clinic_name" placeholder="Clinic">
<input type="phone" class="form-control" id="phone" placeholder="Phone">
<input type="email" class="form-control" id="email" placeholder="Email">
<button id="sub" type="submit" class="btn btn-default">Submit</button>
</form>
forms.py
class LeadForm(forms.ModelForm):
name = forms.CharField(max_length=250, required= True,widget=forms.TextInput())
clinic_name = forms.CharField(max_length=250, required= True,widget=forms.TextInput())
phone = forms.CharField(max_length=8, required= True,widget=forms.TextInput(attrs={'type':'number'}))
email = forms.CharField(max_length=250, required= False, widget=forms.TextInput())
class Meta:
model = Lead
fields = ("clinic_name","phone")
views.py
def add_doc_info(request):
d = getVariables(request,dictionary={'page_name': "Doctors",
'meta_desc' : "Sign up "})
if request.method == "POST":
SalesForm = LeadForm(request.POST)
if SalesForm.is_valid():
name = SalesForm.cleaned_data['name']
clinic_name = SalesForm.cleaned_data['clinic_name']
phone = SalesForm.cleaned_data['phone']
email = SalesForm.cleaned_data['email']
#Saving to database
lead = Lead(name=name, clinic_name=clinic_name, phone=phone, email=email)
lead.save()
else:
SalesForm = LeadForm()
return render(request, 'm1/add_doc_info.html', d, context_instance=RequestContext(request))
models.py
class Lead(models.Model):
name = models.CharField(max_length=1300)
clinic_name = models.CharField(max_length=1300)
phone = models.IntegerField()
email = models.EmailField(blank = True)
submitted_on = models.DateField(auto_now_add=True)
def __unicode__(self):
return u"%s %s" % (self.clinic_name, self.phone)
Almost certainly the form is not valid, but you're not using it in your template so there is no way for it to display errors, or redisplay itself with partially-filled fields.
The Django documentation is fairly explicit on this, so I don't know why you have done something different. Pass the form into your context:
d['form'] = SalesForm
return render(request, 'm1/add_doc_info.html', d)
and use it in the template:
{{ form.errors }}
<form action="" method="post" id="salesform">
{% csrf_token %}
{{ form.name }}
{{ form.clinic_name }}
{{ form.phone }}
{{ form.email }}
<button id="sub" type="submit" class="btn btn-default">Submit</button>
</form>
(Note also you've unnecessarily defined all the fields explicitly in the form, but also stated you are only using two of them in the meta class; also your is_valid block is mostly unnecessary as you can just call form.save() directly. Again, all this is shown fully in the documentation.)

Categories