I'm trying to add some data to the DB from a modal form in django. After filling all the fields and click on submit it doesn't save on the DB. Here are the models, views and forms and the template. I think the problem it's on the views.py
models.py
class Buyer(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=255)
phone_numbers = ArrayField(PhoneNumberField())
industry = models.IntegerField(null=True)
credit_limit = MoneyField(max_digits=20, decimal_places=2,
default_currency='MMK', null=True)
is_active = models.BooleanField(default=True)
datetime_created = models.DateTimeField(auto_now_add=True)
datetime_updated = models.DateTimeField(auto_now=True)
views.py
class BuyerCreateView(AtomicMixin, View):
template_name = 'add_buyer_modal.html'
def get(self, request):
form = BuyerForm()
return render(request, self.template_name, {'form': form})
def post(self, request):
form = BuyerForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Buyer created!', extra_tags='alert alert-success')
return HttpResponseRedirect(self.request.META.get('HTTP_REFERER'))
messages.error(request, 'Unable create buyer. {}'.format(form.errors), extra_tags='alert alert-danger')
return HttpResponseRedirect(self.request.META.get('HTTP_REFERER'))
forms.py
class BuyerForm(forms.ModelForm):
class Meta:
model = Buyer
fields = ['name', 'phone_numbers', 'industry', 'credit_limit']
template
<div class="modal fade" id="add-buyer-modal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">New Buyer</h5>
<button type="button" data-dismiss="modal" aria-label="Close" class="close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="col-md-12 modal-body">
<form id="buyer-form" method="post" class="submit-form" action="{% url 'buyers:add_buyer' %}">
{% csrf_token %}
<div class="col-md-12">
<div class="form-group label-floating">
<label class="control-label">Name</label>
<input autocomplete="false" type="text" name="name" class="form-control" required>
</div>
</div>
<div class="col-md-12">
<div class="form-group label-floating">
<label class="control-label">Industry</label>
<div class="input-group">
<input autocomplete="false" type="number" name="industry" class="form-control" required>
</div>
</div>
</div>
<input id="payment-submit" type="submit" class="btn btn-primary pull-right submit-button" />
</form>
</div>
</div>
</div>
urls.py
urlpatterns = [
url(r'^$', buyers_views.BuyerListView.as_view(), name='buyers_list'),
url(r'^(?P<id>[0-9a-f-]+)/$',
buyers_views.BuyerDetailView.as_view(), name='buyers_detail'),
url(r'^/buyer/add/', buyers_views.BuyerCreateView.as_view(), name='add_buyer'),
]
Check to see if your form is invalid. You only fill out 2 of the 3 fields in the HTML form and send it back to the server. Therefore, when you check to see if the form.is_valid(), it's probably returning False and therefore, not actually saving the form.
To check, you can put a print statement inside the if statement printing out 'success' and one after the if statement printing out 'failure'. If you don't see the 'success' print out, it means your form is invalid.
If this truly is the issue, add form fields in the HTML for all fields in your form. Any field you include in the fields attribute of a form by default is required. This means that if the field isn't filled out when calling is_valid on the form, a validation error for that field will be thrown.
Related
I have created one html form for my web application. Now I want to fetch data for further validation on submit the form in DJANGO. So how can I do this. I have attached my html form code below. Actually, I can get the data by the request.POST.get('field_name') method but I want to get data in the single object. Also I want to create seprate python file for validation. So how can I redirect on that file.
<form action="/contact_form_data_insert" name = "contact_us_form" id = "contact_us_form" method="POST">
<div class="bg-transperent container mt-6">
<div class="bg-transperent container">
<div class="row bg-transperent">
<div class="col-lg-6 bg-transperent contact_field">
<div class="form-outline my-2 px-2" >
<input type="text" id="contact_name" name="contact_name" class="form-control form-control-lg-border-0" placeholder = "Your Name"/>
</div>
</div>
<div class="col-lg-6 bg-transperent contact_field">
<div class="form-outline my-2 px-2" >
<input type="text" id="contact_company" name="contact_company" class="form-control form-control-lg-border-0" placeholder = "Your Company" />
</div>
</div>
</div>
<div class="row bg-transperent">
<div class="col-lg-6 bg-transperent contact_field">
<div class="form-outline my-2 px-2" >
<input type="tel" id="contact_phone_number" name="contact_phone_number" class = "form-control form-control-lg-border-0" placeholder = "Phone Number">
</div>
</div>
<div class="col-lg-6 bg-transperent contact_field">
<div class="form-outline my-2 px-2" >
<input type="email" id="contact_email" name="contact_email" class="form-control form-control-lg-border-0" placeholder = "Email"/>
</div>
</div>
</div>
</div>
<div class="bg-transperent container">
<div class="row">
<div class="col-12 bg-transperent contact_field ">
<div class="form-outline my-2 px-2" >
<input type="text" id="contact_subject" name = "contact_subject" class="form-control form-control-lg-border-0" placeholder = "Subject" />
</div>
</div>
</div>
</div>
<div class="bg-transperent container">
<div class="row">
<div class="col-12 bg-transperent contact_field">
<div class="form-outline my-2 px-2" >
<textarea class="form-control form-control-lg-border-0" id="contact_question" name="contact_question" placeholder = "Your Question" rows="5"></textarea>
</div>
</div>
</div>
</div>
<div class="container bg-transperent">
<div class="row">
<div class="col-lg-2 px-4">
<input type="submit" class = "btn btn-info btn-lg btn-block"style="color: white;font-family: serif; font-weight: bolder; " value="SEND">
</div>
</div>
</div>
</div>
</form>
Make Django form in the backend for example login form has username and password fields
Don't use it in the front
Just make your own form in the front end with fields named username and password
Django of course can't tell if the data sent from Django form or custom form
So it'll treat it normally
For example
class LoginForm(Form):
username = ...
password = ...
class Meta:
fields = ('username', 'password')
Now in the backend
form = LoginForm (request.POST)
if form.is_valid():
The form only needs data named username and password from the front side
About using Django forms, here's a quick demo... You can create a file within your app folder called forms.py and place the following inside of it.
from django import forms
class ContactForm(forms.Form):
# You can also modify the field attributes from here if you wish to
contact_name = forms.CharField(widget=forms.TextInput(attrs={'id':'contact_name', 'name': 'contact_name', 'class': 'form-control form-control-lg-border-0', 'placeholder': 'Your Name'}))
# You can take the same approach for the other text & email input fields below
contact_company = forms.CharField(widget=forms.TextInput(attrs={...}))
contact_phone_number = forms.CharField(widget=forms.TextInput(attrs={...}))
contact_subject = forms.CharField(widget=forms.TextInput(attrs={...}))
contact_email = forms.EmailField(widget=forms.EmailInput(attrs={...}))
# Textarea field
contact_question = forms.CharField(widget=forms.Textarea(attrs={'id':'contact_question', 'name': 'contact_question', 'class': 'form-control form-control-lg-border-0','placeholder': 'Your Question', 'rows': '5'}))
# Can create any method in here to handle a specific process if the form is valid
def save(self):
pass
From your views.py file within the same app folder:
from .forms import ContactForm # Importing the custom form you created
# Now let's say I want to pass it to a specific view to allow a user to submit his/her information...
def contact_form_view(request):
if request.method == 'POST':
form = ContactForm(data=request.POST)
if form.is_valid():
# Do something here to process and save the form data
form.save()
else:
print(form.errors)
else:
form = ContactForm()
return render(request, 'contact_form.html', {'form': form})
Now, within your html template, you could just replace the respective input fields with the form object fields. For example:
<form method="POST" ...>
# Where you have these fields
<input type="text" id="contact_name" name="contact_name" class="form-control form-control-lg-border-0" placeholder = "Your Name"/>
# Just replace with... (i.e.: contact_name as above)
{{ form.contact_name }}
# Apply the above with the other respective fields.
</form>
I trust you already know how to set up your url for the view. In a nutshell, that's an approach you could take.
I do recommend that you read the doc for more information on the Django forms though.
I have a form which registers a new user, I used Bootstrap 5 to make it look nice. However, when I press the submit button the form does not validate. The error it shows when I write print(form.errors) says that every field is required, which means it didn't recieve anything. Why does this happen? This is my code:
HTML
<div class="card" id='signup_card'>
<div class='card-header'>
<h2 class='card-title'>Sign Up</h2>
</div>
<div class='card-body'>
<form method='POST' action="" id='create_user_form' style="color: #fff;">
{% csrf_token %}
<label for='usernameInput' class="form-label">{{form.username.label}}:</label>
<input type="text" id='usernameInput' style="margin-bottom: 20px;">
<label for='phoneNumberInput' class="form-label">{{form.phone_number.label}}:</label>
<input type="text" id='phoneNumberInput' style="margin-bottom: 20px;">
<label for='emailInput' class="form-label">{{form.email.label}}:</label>
<input type="text" id='emailInput' style="margin-bottom: 20px;">
<label for='password1Input' class="form-label">{{form.password1.label}}:</label>
<input type="text" id='password1Input' style="margin-bottom: 20px;">
<label for='password2Input' class="form-label">{{form.password2.label}}:</label>
<input type="text" id='password2Input' style="margin-bottom: 20px;">
<button class="btn btn-primary" type='submit'>Submit</button>
</form>
</div>
models.py
class Account(User):
phone_number = BigIntegerField()
forms.py
class CreateAccountForm(UserCreationForm):
class Meta:
model = Account
fields = ['username', 'email', 'phone_number', 'password1', 'password2']
views.py
def signup(request):
if request.method == 'GET':
form = CreateAccountForm()
ctx = {
'form':form
}
return render(request, 'signup.html', ctx)
if request.method == 'POST':
form = CreateAccountForm(request.POST)
if form.is_valid():
form.save()
else:
print(form.errors)
return render(request, 'index.html')
Your input elements need to specify a name="…" attribute to specify for which name they will associate a value:
<form method='POST' action="" id='create_user_form' style="color: #fff;">
<label for='usernameInput' class="form-label">{{form.username.label}}:</label>
<input type="text"name="username" id='usernameInput' style="margin-bottom: 20px;">
<label for='phoneNumberInput' class="form-label">{{form.phone_number.label}}:</label>
<input type="text" name="phone_number" id='phoneNumberInput' style="margin-bottom: 20px;">
<label for='emailInput' class="form-label">{{form.email.label}}:</label>
<input type="text" name="email" id='emailInput' style="margin-bottom: 20px;">
<label for='password1Input' class="form-label">{{form.password1.label}}:</label>
<input type="text" name="password1" id='password1Input' style="margin-bottom: 20px;">
<label for='password2Input' class="form-label">{{form.password2.label}}:</label>
<input type="text" name="password2" id='password2Input' style="margin-bottom: 20px;">
<button class="btn btn-primary" type='submit'>Submit</button>
</form>
Your error is normal because you need add a name attribute to input field :
<label for='usernameInput' class="form-label">{{form.username.label}}:</label>
<input type="text" id='usernameInput' name='username' style="margin-bottom: 20px;">
You can also use full Django form like this :
<label for='usernameInput' class="form-label">{{form.username.label}}:</label>
{{ form.username }}
Now, if you want add some boostrap class name to have nice look, you can override the Form class __init__ method like this :
class CreateAccountForm(UserCreationForm):
class Meta:
model = Account
fields = ['username', 'email', 'phone_number', 'password1', 'password2']
# Here we override the form elements attributes to add boostrap class
def __init__(self, *args, **kwargs):
super(RegistrationForm, self).__init__(*args, **kwargs)
# Add some placeholder to username input field
self.fields['username'].widget.attrs['placeholder'] = 'Your username'
# add an id to username input field
self.fields['username'].widget.attrs['id'] = 'usernameInput'
# add the same class to all the fields (commom attribute value for all)
for field in self.fields:
self.fields[field].widget.attrs['class'] = 'form-control'
More about Django model form here
I am unable to save my form responses to the database as an object in Django.
Everytime I click on submit to submit my form, I am just logged out of my website and the object isnt saved in the database either.
Can anyone tell me where I am going wrong?
This is my models in models.py.
class Chain(models.Model):
name = models.CharField(max_length=255)
user = models.ForeignKey(User, on_delete=models.CASCADE)
year = models.CharField(max_length=10, default="20XX")
sem = models.CharField(max_length=30, default="Default Semester")
code = models.CharField(max_length=10, default="SUB-CODE")
slot = models.CharField(max_length=10, default="EX+EX")
last_updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
This is my view in views.py file.
#login_required(login_url='/')
def create_course(request):
if request.method == 'GET':
return render(request, 'create_course.html', {})
elif request.method == 'POST':
name=request.POST['name']
year=request.POST['year']
sem=request.POST['sem']
code=request.POST['code']
slot=request.POST['slot']
newchain = Chain(
name=name,
year=year,
sem=sem,
code=code,
slot=slot,
)
newchain.user = request.user
newchain.save()
return redirect('success')
This is my HTML code for the form.
{% extends 'authmain.html' %}
{% block content %}
<h3> <p class="text-center"> Create a new Course Blockchain: </p> </h3>
<div class="card border-dark mb-3 mx-auto" align="center" style="width: 40rem;">
<div class="card-body">
<h5 class="card-title">
<form method='POST'>
{% csrf_token %}
<label for="year">Year: </label>
<input type="text" id="year" name="year" value=""><br>
<label for="code">Course Code: </label>
<input type="text" id="code" name="code" value=""><br>
<label for="name">Course Name: </label>
<input type="text" id="name" name="name" value=""><br>
<label for="slot">Slot: </label>
<input type="text" id="slot" name="slot" value=""><br>
<label for="sem">Semester: </label>
<input type="text" id="sem" name="sem" value=""><br>
<button class="btn btn-outline-primary" type="Submit"> Create </button>
</form>
</h5>
</div>
</div>
{% endblock %}
This is my urls.py.
from django.urls import path, include
from . import views
urlpatterns = [
path('', views.home, name="home"),
path('register/', views.register, name="register"),
path('logout/', views.logoutuser, name="logoutuser"),
path('dashboard/', views.dashboard, name="dashboard"),
path('create_course/', views.create_course, name="create_course"),
path('success', views.success, name="success"),
]
This is the view function for success.
#login_required(login_url='/')
def success(request):
return render(request, 'success.html', {})
The issue is that you are not closing form tag in the authmain.html.
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<form action="{% url 'logoutuser' %}" method='POST'>
{% csrf_token %}
<button class="btn btn-outline-info mb-auto" type="submit">Logout</button>
----- CLOSING FORM TAG MISSING HERE ---
</li>
</ul>
and when you submit the form at Create Course, you actually trigger this form, which logs out the user. Add closing tag to the logout form and you'll fix your problem.
Sometimes debugging can be a bit tricky.
To save directly in the database in Django use Model.objects.create()
Chain.objects.create(user=request.user, name=name, year=year, sem=sem,
code=code, slot = slot)
You need to use a model form to achieve this
class MyForm(ModelForm):
class Meta:
model = MyModel
fields = []
And then you can do something like this:
form = MyForm(request.POST)
if form.is_valid():
new_item = form.save()
...
And it will save directly to the database.
I noticed that when I upload a profile picture the picture is not being saved in my media directory.
I have manually created the folder and referenced it in settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
urls.py:
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)
models.py:
class User(AbstractUser):
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
...
class Mentor(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,primary_key=True)
linkedin = models.URLField(max_length=200,null=True,blank=True)
photo = models.ImageField(null=True, blank=True, upload_to='media')
forms.py
#basic form
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('first_name','last_name','email')
# edit mentor profile
class MentorProfileForm(forms.ModelForm):
class Meta:
model = Mentor
fields = ('photo',)
and views.py:
def edit_user(request):
user = request.user
# form = MentorProfileForm(instance=user)
if request.method == 'POST':
form = UserForm(request.POST, request.FILES, instance=user)
mentorform = MentorProfileForm(request.POST, request.FILES, instance=user)
if form.is_valid() and mentorform.is_valid():
form.save()
mentorform.save()
messages.success(request, ('Your profile was successfully updated!'))
return HttpResponseRedirect('%s' % (reverse('teachers:edit_user')))
else:
messages.error(request, ('Please correct the error below.'))
else:
form = UserForm(request.POST, instance=user)
mentorform = MentorProfileForm(request.POST, request.FILES, instance=user)
return render(request, 'classroom/teachers/app-instructor-profile.html', {'form': form,
'mentor_form': mentorform})
EDIT
As requested here is the html template I am using to upload the picture and other profile info. I am convinced that the problem is with my html. I'm not sure what else I could be doing wrong
<form id="edit-mentor-profile" class="form-horizontal" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
<label for="photo" class="col-sm-2 control-label">Avatar</label>
<div class="col-md-6">
<div class="media v-middle">
<div class="media-left">
<div class="icon-block width-100 bg-grey-100">
<img id="image" style="width:99%;height:99%;">
</div>
</div>
<div class="media-body">
<input type="file" id="files" class="btn btn-white btn-sm paper-shadow relative" data-z="0.5" data-hover-z="1" data-animated/>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="inputEmail3" class="col-md-2 control-label">Full Name</label>
<div class="col-md-8">
<div class="row">
<div class="col-md-6">
<div class="form-control-material">
{{ form.first_name }}
<label for="edit-mentor-profile-first_name"></label>
</div>
</div>
<div class="col-md-6">
<div class="form-control-material">
{{ form.last_name }}
<label for="edit-mentor-profile-last_name"></label>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="email" class="col-md-2 control-label">Email</label>
<div class="col-md-6">
<div class="form-control-material">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-envelope"></i></span>
{{ form.email }}
<label for="edit-mentor-profile-email"></label>
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-6">
<div class="checkbox checkbox-success">
<input id="checkbox3" type="checkbox" checked="">
<label for="checkbox3">Subscribe to our Newsletter</label>
</div>
</div>
</div>
<div class="form-group margin-none">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-primary paper-shadow relative" data-z="0.5" data-hover-z="1" data-animated>Save Changes</button>
</div>
</div>
</form>
As #schwobaseggl said, file should be stored in /media/media folder. But there is another problem in your code, here:
mentorform = MentorProfileForm(request.POST, request.FILES, instance=user) # <-- Here
Here it should be:
mentorform = MentorProfileForm(request.POST, request.FILES, instance=user.mentor)
Because MentorProfileForm is using Mentor model, not User model. Also you need to fix the code for handling GET request:
def edit_user(request):
user = request.user
# form = MentorProfileForm(instance=user)
if request.method == 'POST':
form = UserForm(request.POST, request.FILES, instance=user)
mentorform = MentorProfileForm(request.POST, request.FILES, instance=user.mentor)
if form.is_valid() and mentorform.is_valid():
form.save()
mentorform.save()
messages.success(request, ('Your profile was successfully updated!'))
return HttpResponseRedirect('%s' % (reverse('teachers:edit_user')))
else:
messages.error(request, ('Please correct the error below.'))
else:
form = UserForm(instance=user) # <-- Here
mentorform = MentorProfileForm(instance=user.mentor) # <-- Here
return render(request, 'classroom/teachers/app-instructor-profile.html', {'form': form,
Please use below code in your html template. Where you are using form tag.
<form enctype="multipart/form-data" method="post">
--------- --------
---------Your code-------
</form>
Hi i just have a small doubt can we create a HTML template which will have the Django form and normal HTML form together.
I created a HTML template which has both normal HTML input tag and Django forms.
I am getting the following error when i do a form.save(commit=False)
could not be created because the data didn't validate.
My view.py
if request.method == 'POST':
form_value = request.POST.copy()
print form_value
form = InfoForm(data=request.POST)
post_val = form.save(commit=False)
my HTML
<div class="form-row">
<div class="form-group col-md-4">
{{form.name}}
</div>
<div class="form-group col-md-4">
{{form.number}}
</div>
<div class="form-group col-md-4">
{{form.location}}
</div>
</div>
<div class="form-group">
<label for="Feedback">Feedback</label>
<div id="Feedback" class="optionBox1">
<div class="input-group my-add-div">
<input type="text" class="form-control" name="feedback" required>
<input type="text" class="form-control" name="feedback" required>
<input type="text" class="form-control" name="feedback" required>
</div>
</div>
</div>
my form.py
class InfoForm(forms.ModelForm):
name = forms.CharField(label='Project Name',max_length=100,widget=forms.TextInput(attrs={'class':'form-control','placeholder':'Click to enter text',}))
number = forms.DecimalField(label='Project #',widget=forms.NumberInput(attrs={'class':'form-control','placeholder':'Enter the ID',}))
location = forms.CharField(label='Location',max_length=100,widget=forms.TextInput(attrs={'class':'form-control','placeholder':'Enter the Location',}))
class Meta:
model = Info
field = ('name','number','location',)
My Model.py
name = models.CharField(max_length=200,blank=True , null=True)
number = models.IntegerField(blank=True , null=True)
location = models.CharField(max_length=200,blank=True , null=True)
feedback = ArrayField(ArrayField(models.CharField(max_length=200,blank=True,null=True)))
Thanks in advance
You need to first call form.is_valid() to use save method on the form.
All what you need to create any form in template you want, example:
``
<form action="." method="post">
{% csrf_token %}
<input type="text" name="first_name">
<p><input type='submit' value="Change"></p>
</form> ``
then, in your view call
first_name = request.POST['first_name']
and it will be works fine.