Render html form in django with forms.py - html

I have django web application with authentication system in it. I have user registration view, customer model and
UserCreationForm in forms.py:
class CustomerSignUpForm(UserCreationForm):
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
# phone_number = forms.CharField(required=True)
# location = forms.CharField(required=True)
class Meta(UserCreationForm.Meta):
model = User
#transaction.atomic
def save(self):
user = super().save(commit=False)
user.is_customer = True
user.first_name = self.cleaned_data.get('first_name')
user.last_name = self.cleaned_data.get('last_name')
print(user.last_name)
user.save()
customer = Customer.objects.create(user=user)
# customer.phone_number=self.cleaned_data.get('phone_number')
# customer.location=self.cleaned_data.get('location')
customer.save()
return user
My model looks like this:
...
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
phone_number = models.CharField(max_length=20)
location = models.CharField(max_length=20)
I render form in my customer_register.html:
...
<section>
<div class="container">
<div class="row">
<div class="col-md-6 mx-auto">
<div class="card">
<div class="card-header text-black">
<h2>Register</h2>
</div>
<div class="card-body">
<form action="{% url 'customer_register' %}" method="POST" novalidate>
{% csrf_token %}
{% for field in form.visible_fields %}
<div class="form-group">
{{ field.label_tag }}
{% render_field field class="form-control" %}
{% for error in field.errors %}
<span style="color:red">{{ error }}</span>
{% endfor %}
{% endfor %}
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
...
It doesn't look very pretty though.
What I want to do is to replace my form in customer_register.html with new form in which I wouldn't use widget_tweaks but just html.

I'm moderately confused with what you mean by "wouldn't use widget_tweaks but just html"
but if the form isn't pretty you can always render/place the form fields yourself doing something like:
<form action="{% url 'customer_register' %}" method="POST" novalidate>
<div class="row justify-content-md-center">
<div class="col-md-3 col-md-auto text-center">
<b>First Name:<b>
{{ form.first_name }}
{% if 'first_name' in error %}
<div style='color:red'>{{error.first_name.0.message}}</div>
{% endif %}
</div>
<div class="col-md-3 col-md-auto text-center">
<b>Last Name:<b>
{{ form.last_name }}
{% if 'last_name' in error %}
<div style='color:red'>{{error.last_name.0.message}}</div>
{% endif %}
</div>
</div>
</form>
You could also add classes in the Forms.py __init__ functions, and then add some CSS to make it look pretty (I assume this is the Widget Tweaking, but i don't see it in your original form
class CustomerSignUpForm(UserCreationForm):
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
# phone_number = forms.CharField(required=True)
# location = forms.CharField(required=True)
def __init__(self, *args, **kwargs):
super(CustomerSignUpForm, self).__init__(*args, **kwargs)
self.fields['first_name'].widget.attrs={'class': 'form-control'}
self.fields['last_name'].widget.attrs={'class': 'form-control'}
or you could just straight up create the HTML fields yourself.. All the form and the backend care about is the 'name' attribute- but! You lose all the dynamic validation that Django does.. sooooo I recommend doing the 1st one
<form action="{% url 'customer_register' %}" method="POST" novalidate>
<div class="row justify-content-md-center">
<div class="col-md-3 col-md-auto text-center">
<b>First Name:<b>
<input type="text" name="first_name" max_length="100" required class="form-control"></input>
{% if 'first_name' in error %}
<div style='color:red'>{{error.first_name.0.message}}</div>
{% endif %}
</div>
<div class="col-md-3 col-md-auto text-center">
<b>Last Name:<b>
<input type="text" name="last_name" max_length="100" required class="form-control"></input>
{% if 'last_name' in error %}
<div style='color:red'>{{error.last_name.0.message}}</div>
{% endif %}
</div>
</div>
</form>

Related

sending data from a "form action" to a views function in django

How are you community, I'm a little confused between my newbies and lack of knowledge, I'm working on a small project in Django and I'm also trying to send data from a form action in the html to another view function but I'm not understanding it well How does this work and on top of that I have to send several data not just one and it confuses me even more, I have the following HTML:
{% extends "base.html" %}
{% block content %}
<main class="container">
<div class="row">
<div class="col-md-10 offset-md-1 mt-5">
<form action="/interface/" method="POST" class="card card-body">
<h1>Interface</h1>
<h4>{{ error }}</h4>
<select name="dv">
<option selected disabled="True">Select Device</option>
{% for device in devicess %}
<option>{{ device.id }} - {{ device.name }}</option>
{% endfor %}
</select>
<br>
{% csrf_token %}
<br>
<button type="submit" class="btn btn-primary">Send</button>
</form>
<br>
{% for interface in interfaces %}
<section class="card card-body">
<h2>{{interface.Interface}}</h2>
{% if interface.Description == "" %}
<p class="text-secondary">none description</p>
{% else %}
<P class="text-secondary">{{interface.Description}}</P>
{% endif %}
<form action= "{% url 'send_description' %}"method="POST">
{% csrf_token %}
<input type="text" name="command" class="form-control" placeholder="Change description">
<br>
<button type="submit" class="btn btn-primary align-content-lg-center">Send change</button>
</form>
<br>
{% if interface.Status == "up" %}
<p class="text-secondary">Interface State: 🟢 Free</p>
{% else %}
<p class="text-secondary">Interface State: 🔴 Used</p>
{% endif %}
</section>
<br>
{% endfor %}
</div>
</div>
</main>
{% endblock %}
and aesthetically to better understand the first POST executed like this:
So far everything is perfect, if I press the "Send change" button it redirects me perfectly, the problem is that I need to send various data such as device.id, interface to that function that I am executing in the action= "{% url 'send_description' %} .Interface and also the content of the input that is inside the same form. Could you give me a hand or a guide on where to find the best way?
regards!
Let me start by saying that this would work way better with JS and AJAX. But, to answer your question, data is passed via Django http request object, in your case, since you have several different forms, it is possible to pass this data by adding a hidden field inside each form with the desired value:
<input type="hidden" name="interface" value="{{ interface.id }}">
And fetch this value form the request object in the view:
interface = request.POST.get('interface')
A full example:
models.py
class Device(models.Model):
name = models.CharField(max_length=100)
class Interface(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=100, default='interface description field')
status = models.BooleanField(default=False)
device = models.ForeignKey(Device, on_delete=models.CASCADE, related_name='interfaces')
views.py
from django.core.exceptions import ObjectDoesNotExist
def list_interfaces(request):
devices = Device.objects.all()
interfaces = None
try:
selected_device = Device.objects.get(id=request.POST.get('dv'))
interfaces = selected_device.interfaces.all()
except ObjectDoesNotExist:
selected_device = Device.objects.all().first()
if selected_device:
interfaces = selected_device.interfaces.all()
else:
selected_device = None
context = {
'devices': devices,
'selected_device': selected_device,
'interfaces': interfaces
}
return render(request, 'list_device_interfaces.html', context)
def send_description(request):
command = request.POST.get('command')
device = request.POST.get('seleted_device')
interface = request.POST.get('interface')
print(f'command: {command}')
print(f'device_id: {device}')
print(f'device_id: {interface}')
return redirect('core:list-device-interfaces')
urls.py
from core import views
from django.urls import path
app_name = 'core'
urlpatterns = [
path("list/device/interfaces/" , views.list_interfaces, name="list-device-interfaces"),
path("send/description/" , views.send_description, name="send-description"),
]
list_device_interfaces.html
{% extends "base.html" %}
{% block content %}
<main class="container">
<div class="row">
<div class="col-md-10 offset-md-1 mt-5">
<form action="{% url 'core:list-device-interfaces' %}" method="POST" class="card card-body">
{% csrf_token %}
<h1>Device</h1>
<h4>{{ error }}</h4>
<select name="dv">
<option selected disabled="True">Select Device</option>
{% for device in devices %}
<option value="{{ device.id }}" {% if device.id == selected_device.id %} selected {% endif %}>{{ device.id }} - {{ device.name }}</option>
{% endfor %}
</select>
<br>
<br>
<button type="submit" class="btn btn-primary">Send</button>
</form>
<br>
<hr>
<h2>Interfaces</h2>
{% for interface in interfaces %}
<section class="card card-body">
<h2>{{interface.name}}</h2>
{% if interface.description == "" %}
<p class="text-secondary">none description</p>
{% else %}
<P class="text-secondary">{{interface.description}}</P>
{% endif %}
<form action= "{% url 'core:send-description' %}"method="POST">
{% csrf_token %}
<input type="text" name="command" class="form-control" placeholder="Change description">
<input type="hidden" name="seleted_device" value="{{ selected_device.id }}">
<input type="hidden" name="interface" value="{{ interface.id }}">
<br>
<button type="submit" class="btn btn-primary align-content-lg-center">Send change</button>
</form>
<br>
{% if interface.status %}
<p class="text-secondary">Interface State: 🟢 Free</p>
{% else %}
<p class="text-secondary">Interface State: 🔴 Used</p>
{% endif %}
</section>
<br>
{% endfor %}
</div>
</div>
</main>
{% endblock %}

Django: div class alert alert-danger does not work properly

My forms.py:
class SignUpForm(forms.ModelForm):
name = forms.CharField(label="name", required=True, widget=forms.TextInput())
email = forms.CharField(label="email", required=True, widget=forms.TextInput())
password = forms.CharField(label="password", widget=forms.PasswordInput(), required=True)
confirm_password = forms.CharField(label="password", widget=forms.PasswordInput(), required=True)
def clean(self):
cleaned_data = super(SignUpForm, self).clean()
password = cleaned_data.get("password")
confirm_password = cleaned_data.get("confirm_password")
if password != confirm_password:
self.add_error('confirm_password', "Password and confirm password do not match")
return cleaned_data
class Meta:
model = get_user_model()
fields = ('name', 'email', 'password')
My html file:
{% block content %}
<form method="post">
<div class="sign-card">
<h3>Signup</h3>
{% csrf_token %}
<div class="input-div">
<label for="{{ form.name.id_for_label }}">Username:</label>
{{ form.name }}
</div>
<div class="input-div">
<label for="{{ form.email.id_for_label }}">Email:</label>
{{ form.email }}
</div>
<div class="input-div">
<label for="{{ form.password.id_for_label }}">Password:</label>
{{ form.password }}
</div>
<div class="input-div">
<label for="{{ form.password.id_for_label }}">Confirm Password:</label>
{{ form.confirm_password }}
</div>
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% endif %}
<button type="submit" class="btn">Sign up</button>
<p>Already have account? Log In</p>
</div>
</form>
{% endblock %}
My views.py:
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('name')
password = form.cleaned_data.get('password')
email = form.cleaned_data.get('email')
user = authenticate(username=username, password=password, email=email)
login(request, user)
return redirect('index')
else:
form = SignUpForm()
return render(request, 'registration/signup.html', {'form': form})
The problem I'm facing is that <div class="alert alert-danger"> doesn't work properly. It prints the text and makes it bold, but I have no CSS styling for it (like here, for example: https://www.csestack.org/display-messages-form-submit-django/). I don't want to use Django messages, neither change my code in views.py. How can I fix it? If there is no way to fix it without this changes, so, how can I fix the problem fixing my views.py?
Thanks a lot for your answers.
Actually, you are missing the css file to interpret the alert-danger class.
You can either manually write css for it or include some css library like bootstrap.
You can do something like below in your code: In <head> tag
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
</head>
It should work fine then.

i get an error. django.urls.exceptions.NoReverseMatch

l am started to learn Django few days ago, and I get this error:
django.urls.exceptions.NoReverseMatch: Reverse for 'create_order' with no arguments not found. 1 pattern(s) tried: ['create_order/(?P[^/]+)/$']*
urls.py
path('create_order/<str:pk>/', views.createOrder, name='create_order'),
views.py
def createOrder(request, pk):
customer = Customer.objects.get(id=pk)
form = OrderForm(initial={'customer': customer})
if request.method == 'POST':
# print('Printing:', request.POST)
form = OrderForm(request.POST)
if form.is_valid():
form.save()
return redirect('/')
context = {
'form': form
}
return render(request, 'accounts/order_form.html', context)
order_form.html
{% extends 'accounts/main.html' %}
{% load static %}
{% block content %}
<br>
<div class="row">
<div class="col-12 col-md-6">
<div class="card card-body">
<form action="" method="post">
{% csrf_token %}
{{form}}
<input class="btn btn-sm btn-danger" type="submit" value="Conform">
</form>
</div>
</div>
</div>
{% endblock %}
customer.html
<div class="row">
<div class="col-md">
<div class="card card-body">
<h5>Customer:</h5>
<hr>
<a class="btn btn-outline-info btn-sm btn-block" href="">Update Customer</a>
<a class="btn btn-outline-info btn-sm btn-block" href="{% url 'create_order' customer.id %}">Place Order</a>
</div>
</div>
As the error said, it tried with empty argument, means there was no customer value available in context. So you need to send the customer value through context, like this:
context = {
'customer' : customer,
'form': form
}
I was also following this tutorial from youtube(dennis ivy) and got the same error,
don't know what is the problem but just replace the file urls.py from github with the same context and it's not showing that error,.
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name="home"),
path('products/', views.products, name='products'),
path('customer/<str:pk_test>/', views.customer, name="customer"),
path('create_order/<str:pk>/', views.createOrder, name="create_order"),
path('update_order/<str:pk>/', views.updateOrder, name="update_order"),
path('delete_order/<str:pk>/', views.deleteOrder, name="delete_order"),
]
views.py
from django.forms import inlineformset_factory
def createOrder(request, pk):
OrderFormSet = inlineformset_factory(Customer, Order, fields=('product', 'status'), extra=10 )
customer = Customer.objects.get(id=pk)
formset = OrderFormSet(queryset=Order.objects.none(),instance=customer)
#form = OrderForm(initial={'customer':customer})
if request.method == 'POST':
#print('Printing POST:', request.POST)
#form = OrderForm(request.POST)
formset = OrderFormSet(request.POST, instance=customer)
if formset.is_valid():
formset.save()
return redirect('/')
context = {'form':formset}
return render(request, 'accounts/order_form.html', context)
order_form.html
{% extends 'accounts/main.html' %}
{% load static %}
{% block content %}
<div class="row">
<div class="col-md-6">
<div class="card card-body">
<form action="" method="POST">
{% csrf_token %}
{{ form.management_form }}
{% for field in form %}
{{field}}
<hr>
{% endfor %}
<input type="submit" name="Submit">
</form>
</div>
</div>
</div>
{% endblock %}
again I don't know why it was showing this error and where was the problem but just relapced it with the same code from github and it worked..if someone know how it worked , that will be really helpful in near future. thanks to all regards Haris Ahmad

multiple html form from a single form model in django

i need your assistance
im building a school president vote tallying system
the vote results are saved in the polls table as
candidate id | pollingstationid | result |
when capturing the results the html page will render the form for each candidate. for example if there are 3 candidates the html form will have 3 forms:
candidate 1:
result _______
candidate id 1001
pollingstationid 301
candidate 2:
result _______
candidate id 1002
pollingstationid 301
candidate 3:
result _______
candidate id 1003
pollingstationid 301
[submit button]
the problem:
when i click submit, its only saving the last form(i.e candidate 3)
how do i get all three entries into the database each as a new row.
views.py
class candidatesview(AjaxFormMixin, View):
form_class = pollsForm
model = Polls
template_name = 'app/candidates.html'
def get(self, request):
form = self.form_class()
candidatesls = Candidates.objects.all()
context = {'title':'polls','form' : form, 'candidates': candidatesls }
#print(context)
return render(request, self.template_name, context )
def post(self, request):
form = pollsForm(request.POST)
candidatesls = Candidates.objects.all()
if form.is_valid():
print(form.cleaned_data['Result'])
print(form.cleaned_data['Candidateid'])
print(form.cleaned_data['PollingstationID'])
form.save()
messages.success(request,('Form submitted successfuly'))
else:
messages.warning(request,('nah!'))
print(messages)
context = {'title':'polls','form' : form, 'candidates': candidatesls, 'message':messages}
return render(request, self.template_name, context)
forms.py
class pollsForm(forms.ModelForm):
class Meta:
model = Polls
fields = ['Result', 'Candidateid','PollingstationID']
html (candidates.html)
{% extends "app/base.html" %}
{% load widget_tweaks %}
{% block content %}
<div class="bg-white">
<div class="row">
<div class="col-lg-4 col-md-4 col-sm-8">
{% if messages %}
{% for message in messages %}
<div class="alert alert-warning alert-dismissible show" role="alert">
{{ message }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="false">×</span>
</button>
</div>
{% endfor %}
{% endif%}
<div id="alertbox">
</div>
<div class="form-group">
<form class="my-ajax-form" method="POST" action="{% url 'polls' %}">
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{#{% for field in form.visible_fields %}#}
<table class="table">
{% for candidates in candidates %}
<tr>
<td>
{% render_field form.Result class="form-control" placeholder=candidates.CandidateName id=forloop.counter %}
<input type="number" class="form-control" id={{ forloop.counter }} value={{ candidates.CandidateID }}>
{% render_field form.PollingstationID type="hidden" class="form-control" id="C1_Pollingstation" %}
{% for error in field.errors %}
<span class="help-block">{{ error }}</span>
{% endfor %}
</td>
<td>
<div class="circle" style="background:{{ candidates.CandidateColor }}">2</div>
</td>
</tr>
{% endfor %}
</table>
<div class="pull-right">
<input type='submit' class='btn btn-next btn-fill btn-success btn-wd' name='Post' value='Post' />
</div>
</form>
</div>
</div>
</div>
</div>
<br />
{% endblock content %}
{% block javascript %}
<script>
$(document).ready(function(){
var $myForm = $(".my-ajax-form")
var $myMessage = $("#alertbox")
$myForm.submit(function(event){
event.preventDefault()
var $formData = $(this).serialize()
var $endpoint = $myForm.attr("data-url") || window.location.href
console.log($formData)
console.log($endpoint)
$.ajax({
method: "POST",
url: $endpoint,
data: $formData,
success: handleFormSuccess,
error: handleFormError,
})
function handleFormSuccess(data, textStatus, jqXHR){
console.log(data)
console.log(textStatus)
console.log(jqXHR)
$myForm[0].reset();
$myMessage.replaceWith('<div class="alert alert-success show" role="alert" id="alertbox"> post succcess</div> ');
}
function handleFormError(jqXHR, textStatus, errorThrown){
console.log(jqXHR)
console.log(textStatus)
console.log(errorThrown)
$myMessage.replaceWith('<div class="alert alert-warning show" role="alert" id="alertbox"> post failure</div> ');
}
})
})
</script>
{% endblock %}

Using html input tag while iterating over Django fields

I want to iterate over fields list in Django so as to create a generalized template for major of my forms.
The problem I face is that my form is not considered as valid when I'm using the input fields.
I want to stick to input fields as I'm using materialize css .
Below is my
form_template.html
<div class="row ">
{% for field in form %}
<div class="form-group">
{% ifequal field.name "password" %}
<div class="row">
<div class="input-field col s3 xl12">
<input id="{{ field.name }}" type="password" class="{{
field.name }}">
<label for="{{ field.name }}">{{ field.label }}</label>
</div>
</div>
{% endifequal %}
{% ifnotequal field.name "password" %}
{% ifequal field.name "email" %}
<div class="row">
<div class="input-field col s3 xl12">
<input id="{{ field.name }}" type="{{ field.name }}" class="validate">{{ form.field }}
<label for="{{ field.name }}" data-error="Not a valid email"
data-success="Valid Email">{{ field.label }}</label>
</div>
</div>
{% endifequal %}
<br>
{% ifnotequal field.name "email" %}
{% ifequal field.name "album_logo" %}
<div class="file-field input-field col s3 xl12">
<div class="btn">
<span>File</span>
<input type="file" multiple>
</div>
<div class="file-path-wrapper">
<input class="file-path validate" type="text" placeholder="Upload an album cover">
</div>
{% endifequal %}
{% ifnotequal field.name "album_logo" %}
{% ifequal field.name "date_joined" %}
<div class="row">
<div class="input-field col s3 xl12">
<input id="{{ field.name }}" type="date" class="datepicker">{{ form.field }}
<label for="{{ field.name }}">{{ field.label }}</label>
</div>
</div>
{% endifequal %}
{% ifnotequal field.name "date_joined" %}
<div class="row">
<div class="input-field col s3 xl12">
<input id="{{ field.name }}" type="text">
<label for="{{ field.name }}">{{ field.label }}
</label>
</div>
</div>
{% endifnotequal %}
{% endifnotequal %}
{% endifnotequal %}
{% endifnotequal %}
</div>
{% endfor %}
</div>
and UserFormView Class in views.py
class UserFormView(View):
form_class = UserForm
template_name = "music/registration_form.html"
# Display a blank form for a new user
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
# Process form Data here
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
# Cleaned (Normalized or Formatted) Data
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user.set_password(password)
user.save()
# Returns User Objects if credentials are correct
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request,user)
return HttpResponseRedirect('music:index')
else:
return render(request, self.template_name, {'form': form})
Would really appreciate some help, thanks.
When you want to style your form I would suggest to use Widget Tweaks. When you install it correctly you can use it in your template like:
Css:
.inputStyle{
width: 500px;
border: 1px solid black;
border-radius: 5px;
}
.slide{
...
}
HTML:
<form method='POST' action="/" enctype='multipart/form-data'>
{% load widget_tweaks %}
{% csrf_token %}
<span class="">Post the Image via Url: {{form.image_url|add_class:"inputStyle" }}</span>
<span class="" >Please select an option {{ form.Options|add_class:"slide" }}</span>
</form>
Another way to style your forms is to install Widgets in the forms.py
You can install things like Django Select and add it into the form like:
class PostForm(forms.ModelForm):
language = forms.MultipleChoiceField(widget=Select2MultipleWidget(attrs={'data-placeholder': 'Language'}),choices=settings.LANGUAGES)
class Meta:
model = Post
fields=[
'title',
'content',
'image_url',
'language',
.....
]
don't forget to use {{ form.media.js }}in the form.
I hope you get that going. The way you do it now is not the best way ;)
p.s. forgot to mention Django Crispy Form. They are fast to install and easy to handle but I would suggest using widget tweaks since you can style everything with CSS. Crispy can be tricky sometimes and you have to read into the docs...