I am trying to create a employee using a form. I want that after pressing the submit buttom data saves to employee list table and the page redirect to employee list table also. When I see the error log it shows Method Not Allowed (POST) . I think my code is fine but somehow it is not working.
employee_add_form.html:
{% extends 'base.html' %}
{% block content %}
{% load static %}
<link rel="stylesheet" href="{% static 'employee/css/master.css' %}">
{% load bootstrap4 %}
<div class="">
<form class="form" action="{% url 'employee:employee-list' %}" method="post" id="employee_add_form">
{% csrf_token %}
<!-- {% bootstrap_css %}-->
{% bootstrap_javascript jquery='full' %}
{{ form.media }}
{{ form.non_field_errors }}
<div class="container">
<label for=""><b>Personal Info</b></label>
<div class="border">
<div class="form-row">
<div class="col">
{{ form.first_name.errors }}
<label for="">First Name</label>
{{ form.first_name}}
</div>
<div class="col">
{{ form.last_name.errors }}
<label for="">Last Name</label>
{{ form.last_name}}
</div>
<div class="col">
{{ form.photo_id.errors }}
<label for="">Photo ID</label>
{{ form.photo_id }}
</div>
</div>
<div class="form-row inline">
<div class="col-4">
{{ form.gender.errors }}
<label for="">Gender</label>
{{ form.gender }}
</div>
<div class="col-4">
{{ form.blood_group.errors }}
<label for="">Blood Group</label>
{{ form.blood_group }}
</div>
<div class="col-4">
{{ form.religion.errors }}
<label for="">Religion</label>
{{ form.religion }}
</div>
</div>
<div class="form-row">
<div class="col">
{{ form.birth_date.errors }}
<label for="">Date of Birth</label>
{{ form.birth_date }}
</div>
</div>
</div>
</div>
<div class="container">
<label for=""><b>Contact Info</b></label>
<div class="border">
<div class="form-row">
<div class="col">
{{ form.email.errors }}
<label for="">Email</label>
{{ form.email }}
</div>
<div class="col">
{{ form.phone_number.errors }}
<label for="">Phone Number</label>
{{ form.phone_number }}
</div>
<div class="col">
{{ form.address.errors }}
<label for="">Address</label>
{{ form.address }}
</div>
</div>
</div>
</div>
<div class="container">
<label for=""><b>Work Info</b></label>
<div class="border">
<div class="form-row">
<div class="col">
{{ form.e_id.errors }}
<label for="">Employee ID</label>
{{ form.e_id }}
</div>
<div class="col">
{{ form.designation.errors }}
<label for="">Designation</label>
{{ form.designation }}
</div>
<div class="col">
{{ form.department.errors }}
<label for="">Department</label>
{{ form.department }}
</div>
</div>
<div class="form-row">
<div class="col">
{{ form.join_date.errors }}
<label for="">Joining Date</label>
{{ form.join_date }}
</div>
</div>
</div>
</div>
<div class="container">
<label for=""><b>Attachments</b></label>
<div class="border">
<div class="form-group">
<div class="col">
{{ form.cv.errors }}
<label for="">CV</label>
{{ form.cv }}
</div>
<div class="col">
{{ form.document.errors }}
<label for="">Documents</label>
{{ form.document }}
</div>
<div class="col">
{{ form.photo.errors }}
<label for="">Image</label>
{{ form.photo }}
</div>
</div>
</div>
</div>
<div class="container">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
{% endblock %}
views.py:
class EmployeeAddView(CreateView):
"""
Created new employee
"""
template_name = 'employee/employee_add_form.html'
form_class = EmployeeAddModelForm
# queryset = Employee.objects.all()
model = Employee
def form_valid(self, form):
print(form.cleaned_data)
return super().form_valid(form)
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('employee:employee-list')
return render(request, self.template_name, {'form': form})
urls.py:
from django.urls import path
from django.urls import reverse
from . views import (
EmployeeListView,
EmployeeAddView,
EmployeeDetailView,
EmployeeUpdateView,
EmployeeDeleteView,
)
app_name = 'employee'
urlpatterns = [
path('employee-list/', EmployeeListView.as_view(), name='employee-list'),
path('employee-add/', EmployeeAddView.as_view(), name='employee-add'),
path('employee-list/<int:id>/', EmployeeDetailView.as_view(), name='employee-detail'),
path('employee-list/<int:id>/update/', EmployeeUpdateView.as_view(), name='employee-update'),
path('employee-list/<int:id>/delete/', EmployeeDeleteView.as_view(), name='employee-delete'),
]
forms.py:
from django import forms
from core.models import Employee
from bootstrap_datepicker_plus import DatePickerInput
class EmployeeAddModelForm(forms.ModelForm):
use_required_attribute = False
class Meta:
model = Employee
fields = [
'e_id',
'first_name',
'last_name',
'gender',
'religion',
'blood_group',
'birth_date',
'photo_id',
'designation',
#'employee_type',
'join_date',
'address',
'phone_number',
'email',
#'supervisor',
'bank_account_no',
'department',
#'salary_type',
'cv',
'document',
'photo',
]
widgets = {
'birth_date': DatePickerInput(),
'join_date': DatePickerInput(),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Edit label:
self.fields['e_id'].label = 'Employee ID'
self.fields['cv'].label = 'CV'
# Remove help suggestion
for fieldname in ['e_id',
'first_name',
'last_name',
'gender',
'religion',
'blood_group',
'birth_date',
'photo_id',
'designation',
#'employee_type',
'join_date',
'address',
'phone_number',
'email',
#supervisor',
'bank_account_no',
'department',
#'salary_type',
'cv',
'document',
'photo']:
self.fields[fieldname].help_text = None
Your form is POST-ing to wrong URL
<form class="form" action="{% url 'employee:employee-list' %}" method="post" id="employee_add_form">
instead should be
<form class="form" action="{% url 'employee:employee-add' %}" method="post" id="employee_add_form">
If you are using class based view than you can do this.
class EmployeeAddView(CreateView):
template_name = 'employee/employee_add_form.html'
form_class = EmployeeAddModelForm
queryset = Employee.objects.all()
success_url = '/employee-list'
def form_valid(self, form):
print(form.cleaned_data)
return super().form_valid(form)
Change method="post" to method="POST" it should work. I had a similar problem with CBV. This worked for me.
So, here I have a piece of HTML code that is supposed to render a form using django form class. I have several forms on one page, they are rendered in 'for' cycle and should have different values as default (appointment.id). How can I set a value of a field here inside a template? Is in at least possible?
{% for appointment in appointments%}
{% load crispy_forms_tags %}
<form action="/register/" method="post" class="inline">
{% csrf_token %}
<div class="form-group w-25">
<div class="col-sm-10">
{{form.appointment_id|as_crispy_field}}
</div>
<input type="submit" class="btn btn-primary mt-1" value="Register">
</div>
</form>
</p>
{% endfor %}
You can do it in that way:
{% for appointment in appointments%}
{% load crispy_forms_tags %}
<form action="/register/" method="post" class="inline">
{% csrf_token %}
<div class="form-group w-25">
<div class="col-sm-10">
{{ form.appointment_id(value=appointment.id)|as_crispy_field }}
</div>
<input type="submit" class="btn btn-primary mt-1" value="Register">
</div>
</form>
</p>
{% endfor %}
I made a template tag and when I am using that in my template I get this error:
'str' object has no attribute 'as_widget'
This is the code of my template tag:
from django import template
register = template.Library()
#register.filter
def field_type(bound_field):
return bound_field.field.widget.__class__.__name__
#register.filter
def input_class(bound_field):
css_class = ''
if bound_field.form.is_bound:
if bound_field.errors:
css_class = 'is-invalid'
elif field_type(bound_field) != 'PasswordInput':
css_class = 'is-valid'
return 'form-control {}'.format(css_class)
and my template is here:
{% extends 'board/account.html' %}
{% load widget_tweaks %}
{% load form_tags %}
{% block title %}Sign up{% endblock title %}
{% block content %}
<div class="accountform">
<form method="POST">
<h4 class="display-6 text-white p-3">Create your account</h4>
{% csrf_token %}
<div class="alert alert-danger p-0" style="border:none;">
{% for field in form.visible_fields %}
{% for error in field.errors %}
<span class="err">{{ error }}</span><br>
{% endfor %}
{% endfor %}
</div>
<div class="form-group">
<label for="id_username">Username</label>
{% render_field form.username|input_class class='form-control' placeholder='John Doe' %}
</div>
<div class="form-group">
<label for="id_email">Email</label>
{% render_field form.email|input_class class='form-control' placeholder='johndoe#email.com' %}
</div>
<div class="row">
<div class="form-group col-md-6">
<label for="id_password1">Password</label>
{% render_field form.password1|input_class class='form-control' placeholder='****' %}
</div>
<div class="form-group col-md-6">
<label for="id_password2">Confirm Password</label>
{% render_field form.password2|input_class class='form-control' placeholder='****' %}
</div>
</div>
<input type="submit" value="Sign up" class="btn btn-primary btn-block">
<p class="display-6 bg-signup p-3">Have an account Sign In</p>
</form>
</div>
</div>
{% endblock content %}
I saw similar question and approved answer in SO which basically says that the solution for this issue is to add form in context, well that is already added, here is views
def signup_view(request):
if request.method == 'POST':
form = UserRegistrationForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
return redirect('board:home')
form = UserRegistrationForm(request.POST)
return render(request, 'accounts/signup.html', {'form': form})
Please help me solve this issue. Thank you for your help.
There doesn't seem to be any reason for either of these template tags. django-widget-tweaks already has the ability to add a custom error class with render_field, and you already know when you're rendering the password field so you can add that class when you need to.
(Also, django-widget-tweaks provides the field_type filter already).
So:
{% with WIDGET_ERROR_CLASS='my_error' %}
<div class="form-group">
<label for="id_username">Username</label>
{% render_field form.username class+='form-control' placeholder='John Doe' %}
</div>
<div class="form-group">
<label for="id_email">Email</label>
{% render_field form.email class+='form-control' placeholder='johndoe#email.com' %}
</div>
<div class="row">
<div class="form-group col-md-6">
<label for="id_password1">Password</label>
{% render_field form.password1| class+='form-control' placeholder='****' %}
</div>
...
{% endwith %}
You are doing it wrong way you have to add calss in class attribute not render class name as field. Do it like this.
{% render_field form.username class=form.username|input_class placeholder='John Doe' %}
Im tries to open in Django the user edit form in Bootstrap modal. But the form is empty, only the save button is shown. But I don't understand how I can make the connection. If I call the edit page directly, then I can edit the user
127.0.0.1:8000/account/edit/
index.html, includes the referral to the form
{% extends 'base.html' %}
{% block head %}
{% endblock %}
{% block body %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 col-md-6">
<div class="panel panel-default">
<div class="panel-body">
{% if error_message %}
<p><strong>{{ error_message }}</strong></p>
{% endif %}
<form action="{% url 'account:edit_profile' %}">
<input type="submit" value="Edit" />
</form>
<form action="{% url 'account:change_password' %}">
<input type="submit" value="Change Login" />
</form>
<br>
Open Modal
<br>
<div class="control-label col-sm-2">
First name:
</div>
<div class="col-sm-2">
{{ user.first_name }}
</div><br>
<div class="control-label col-sm-2">
Last name:
</div>
<div class="col-sm-2">
{{ user.last_name }}
</div><br>
<div class="control-label col-sm-2">
Email:
</div>
<div class="col-sm-2">
{{ user.email }}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="edit-profile-modal" >
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header" align="center">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
</div>
<div id="div-forms">
{% include "account/edit_profile.html" with form=form %}
</div>
</div>
</div>
</div>
{% endblock %}
edit_profile.html
{% block head %}
{% endblock %}
{% block body %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 col-md-6">
<div class="panel panel-default">
<div class="panel-body">
<h3>Profile</h3>
{% if error_message %}
<p><strong>{{ error_message }}</strong></p>
{% endif %}
<form method="post">
{% csrf_token %}
{{ user_form.as_p }}
<button type="submit">Save</button>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
views.py
def edit_profile(request):
if request.method == 'POST':
user_form = EditUserForm(request.POST, instance=request.user)
if all([user_form.is_valid(), profile_form.is_valid()]):
user_form.save()
return render(request, 'account/index.html')
else:
user_form = EditUserForm(instance=request.user)
args = {'user_form': user_form}
return render(request, 'account/edit_profile.html', args)
urls.py
urlpatterns = [
...
url(r'^edit/$', views.edit_profile, name='edit_profile'),
...
]
forms.py
class EditUserForm(forms.ModelForm):
class Meta:
model = User
fields = (
'email',
'first_name',
'last_name'
)
Im using:
Python 3.6.3
Django 2.0.7
Windows 8.1
Bootstrap 3.3.6
JQuery 1.12.0
I think that variable form doesn't exist and you use in template just user_form not form variable
{% include "account/edit_profile.html" with form=form %}
Try use it:
{% include "account/edit_profile.html" with user_form=user_form %}
Maybe you could try the code I wrote and you can find it at django-bootstrap-modal-forms. You will be able to bind your form to the modal and all of the validation stuff will work out of the box.
You will create a trigger element opening the modal
Your selected form will be appended to the opened modal
On submit the form will be POSTed via AJAX request to form's URL
Unsuccessful POST request will return errors, which will be shown under form fields in modal
Successful POST request will redirects to selected success URL
I'm currently coding a website using Django and Bootstrap.
I created the templates and models first, and now, I'm implementing the controllers. All is not implemented yet, but I needed some help on this. I was wondering how to render a Django authentication form with the Boostrap grid system. I'm using Boostrap 4 and Django 2.0.4. My older form was like this :
<div class="jumbotron">
<form class="form-horizontal" method="post" action="{% url 'login' %}">
{% csrf_token %}
<div class="form-group">
<div class="col-lg-4 offset-lg-4">
<label class="control-label" for="usernameInput">{{ form.username.label_tag }}</label>
<input id="usernameInput" type="text" name="{{ form.field.html_name }}" value="{{ form.username }}" class="form-control"
placeholder="Username">
</div>
</div>
<div class="form-group">
<div class="col-lg-4 offset-lg-4">
<label class="control-label" for="passwordInput">{{ form.password.label_tag }}</label>
<input id="passwordInput" type="password" name="{{ form.field.html_name }}" value="{{ form.field.value }}" class="form-control"
placeholder="Password">
</div>
</div>
<div class="container" id="btn_login">
<button type="submit" class="btn btn-primary btn-md" value="login" role="button">Log in</button>
<input type="hidden" name="next" value="{{ next }}"/>
</div>
</form>
<span class="container" id="forgotten_password">
Forgot your password ?
</span>
</div>
And here is the new one :
<div class="jumbotron">
{% load widget_tweaks %}
<form class="form-horizontal" method="post" action="{% url 'login' %}">
{% csrf_token %}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
{% for field in form.visible_fields %}
<div class="form-group">
{{ field.label_tag }}
{% if form.is_bound %}
{% if field.errors %}
{% render_field field class="form-control" %}
{% for error in field.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>
{% endfor %}
<div class="container" id="btn_login">
<button type="submit" class="btn btn-primary btn-md" role="button">Log in</button>
</div>
</form>
<span class="container" id="forgotten_password">
Forgot your password ?
</span>
</div>
But as you can obviously tell, this is not rendering the same way.
For example, I'd like to take back the width of the input.
For the rest, I use this line in my urls.py
re_path(r'^login/$', auth_views.login, {'template_name': 'main/login.html'}, name='login'),
And this one in my settings.py to get redirected to the right page :LOGIN_REDIRECT_URL = 'my_pls'
I googled a lot and finally used this link (in case you case notice something I didn't understand) : https://simpleisbetterthancomplex.com/article/2017/08/19/how-to-render-django-form-manually.html#understanding-the-rendering-process
You should use custom HTML attributes on your **forms.py**.
It's simple:
from django import forms
class your_form(forms.Form):
attrs_for_the_field = {
'class': 'form-control',
'placeholder': 'Write here!',
}
field = forms.CharField(widget=forms.CharField(attrs=attrs_for_the_field))
With this code you will render the following HTML:
<input type="text" name="field" class="form-control" placeholder="Write here!" id="id_field">
Take a look at https://docs.djangoproject.com/en/2.0/ref/forms/widgets/ in order to know how Django represents an HTML input element.
You also should read https://docs.djangoproject.com/en/2.0/ref/forms/fields/ so that you could understand how it works.
You can add all the HTML configuration for the fields in the form code in forms.py . Than the form can be displayed with just {{ form.as_p}}.
Width of input can be retrieved with jQuery or JavaScript .