Django form not showing up in template - python

My problem is not showing up form in the Django template.
I'm using python 3.7.6
Django 3.2
Here is my code
....................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
forms.py
from django import forms
from tasks.models import Task, TaskType
class TaskForm(forms.ModelForm):
name = forms.CharField(max_length=100,
required=True, widget=forms.TextInput(attrs={'class': 'form-control'}))
input_image = forms.ImageField(widget=forms.FileInput(
attrs={'class': 'form-control-file'}))
task_type = forms.ModelChoiceField(queryset=TaskType.objects.name.all(), widget=forms.Select(
attrs={'class': 'form-control'}))
class Meta:
model = Task
fields = ['name', 'input_image', 'task_type']
view.py
from django.shortcuts import render, redirect
from tasks.forms import TaskForm
def create_task(request):
if request.method == 'POST' and 'submit-task' in request.POST:
task_form = TaskForm(request.POST, request.FILES, instance=request.user)
if task_form.is_valid():
task_form.save()
return redirect(to='dashboard')
return render(request, 'users/dashboard.html', {'task_form': task_form})
dashboard.html
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="modal fade" id="myModal">
<div class="modal-dialog modal-fullscreen-lg-down">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h4 class="modal-title">Upload your image</h4>
<button
type="button"
class="btn-close"
data-dismiss="modal"
></button>
</div>
<!-- Modal body -->
<div class="modal-body">
<div class="form-group">
<label class="">Task name</label>
{{task_form.name}}
<div class="input-group">
<select class="custom-select" id="inputGroupSelect04">
<option selected>Choose your model</option>
{{task_form.task_type}}
</select>
<span class="input-group-btn">
<span class="btn btn-outline-dark btn-file">
Browse… {{task_form.image_input}}
</span>
</span>
<input type="text" class="form-control" readonly />
</div>
<img id="img-upload" />
</div>
</div>
<!-- Modal footer -->
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
data-dismiss="modal"
>
Close
</button>
<button type="button" class="btn btn-primary" name="submit-task">
Save changes
</button>
</div>
</div>
</div>
</div>
</form>
So, in the template, the form is not showing up. Please help me to fix it. Thank you so much

def create_task(request):
if request.method == 'POST' and 'submit-task' in request.POST:
task_form = TaskForm(request.POST, request.FILES, instance=request.user)
...
return render(request, 'users/dashboard.html', {'task_form': task_form})
I pretty sure that you want to return dashboard.html on GET method,
however task_form is creating only when POST method. In other words task_form does not exists.
You should define it before using:
def create_task(request):
if request.method == 'POST' and 'submit-task' in request.POST:
task_form = TaskForm(...)
...
else:
task_form = TaskForm(...) # task form defined for non POST methods
# or place it here
# task_form = TaskForm(...) # task form defined for non POST methods
return render(request, 'users/dashboard.html', {'task_form': task_form})

the first thing in your code is you are passing an instance for a create method but the instance does not exist when you didn't create the record yet, the other problem is you are not supporting the get method.
there is an example :
from django.shortcuts import render, redirect
from tasks.forms import TaskForm
from .models import Task
def create_task(request):
instance = Task.objects.filter(user=request.user)
if request.method == 'POST':
if instance:
task_form = TaskForm(request.POST, request.FILES, instance=request.user)
else:
task_form = TaskForm(request.POST, request.FILES)
if task_form.is_valid():
task_form.save()
return redirect(to='dashboard')
return render(request, 'users/dashboard.html', {'task_form': task_form})
else:
if instance:
task_form = TaskForm(instance=request.user)
else:
task_form = TaskForm()
return render(request, 'users/dashboard.html', {'task_form': task_form})

Related

How to properly render form fields with django?

I am currently working on a login page for a django webapp. I am trying to include the login form within the index.html file. However, the form fields are not being rendered. My urls are correct I believe but I'm not sure where I am going wrong. Here is my views.py, forms.py and a snippet of the index.html. (I do not want to create a new page for the login I'd like to keep it on the index page)
# Home view
def index(request):
form = LoginForm()
if form.is_valid():
user = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password'],
)
if user is not None:
login(request, user)
messages.success(request, f' welcome {user} !!')
return redirect('loggedIn')
else:
messages.info(request, f'Password or Username is wrong. Please try again.')
return render(request, "index_logged_out.html")
class LoginForm(forms.Form):
username = forms.CharField(max_length=63)
password = forms.CharField(max_length=63, widget=forms.PasswordInput)
<!-- Login -->
<section class="page-section" id="login">
<div class="container">
<div class="text-center">
<h2 class="section-heading text-uppercase">Login</h2>
</div>
<form>
{% csrf_token %}
{{form}}
<center><button class="btn btn-primary btn-block fa-lg gradient-custom-2 mb-3" type="submit" style="width: 300px;">Login</button></center>
</form>
<div class="text-center pt-1 mb-5 pb-1">
<center><a class="text-muted" href="#!">Forgot password?</a></center>
</div>
<div class="d-flex align-items-center justify-content-center pb-4">
<p class="mb-0 me-2">Don't have an account?</p>
<button type="button" class="btn btn-outline-primary">Create New</button>
</div>
</form>
</div>
</section>
To add to A.S's answer, you should initialize a context variable at the start of the view.
def index(request):
context = {}
form = LoginForm()
context['form'] = form
if form.is_valid():
# ...
return render(request, "index_logged_out.html", context)
It makes it easier to work with when you start to pass in more variables to the context later on, otherwise it'll complicate your view.

Django Form, form is not being submitted

I am pretty new to django and I am having some issues with my form. It is not submitting anything. I don´t have any idea why, no issue appears in the terminal. It displays the form correctly, but when filling it out and submitting, it just redirects me to the same form but blank. I check the database and nothing´s been added. My code below:
#views.py
def ContractView(request):
form=contractsform(request.POST)
if form.is_valid():
con =form.save()
return redirect("{% url 'contracts' %}", con.id)
else:
form = contractsform()
return render(request, 'contform.html', {'form': form})
#contform.html
<div class="card-body">
<form action="" method="POST" class="row g-3">
{% csrf_token %}
<label for="{{ form.subject.id_for_label }}">Name:</label>
{{form.name}}
<div class="col-md-6">
<label for="{{ form.subject.id_for_label }}">Contractor:</label>
<div class="input-group input-group-sm mb-3">
{{form.contractor}}
<button id="new-vendor" class="btn btn-outline-secondary" type="button">+</button>
</div>
</div>
<div class="col-md-6">
<label for="{{ form.subject.id_for_label }}">Contractee:</label>
{{form.contractee}}
</div>
...
<div class="col-md-6">
<button type="button" onclick="javascript:history.back()">Cancel</button>
</div>
<div class="col-md-6">
<input type="submit" value="Submit" class="btn btn-primary" style="float: right;">
</div>
</form>
#forms.py
class contractsform(forms.ModelForm):
class Meta:
model = Contratos
fields = '__all__'
widgets = {
'name': forms.TextInput(attrs ={'class': 'form-control'}),
'contractee': forms.TextInput(attrs={'class': 'form-control'}),
'contractor': forms.Select(attrs={'class': 'form-control', 'id': 'contractor_view' }),}
#urls.py
urlpatterns = [
path('contracts/', views.contratostabla, name='contracts'),
path('contracts/add/', ContractView, name='new-contract'),
]
You are currently redefining the form as an empty form when it is not valid, you need to change you logic to use a form filled with POST data when the request method is POST and an empty form when the method is GET. You still need to use the filled form for POST when it's invalid so that you get the errors and the previous data
def ContractView(request):
if request.method == 'POST':
form = contractsform(request.POST)
if form.is_valid():
con = form.save()
return redirect("{% url 'contracts' %}", con.id)
else:
form = contractsform()
return render(request, 'contform.html', {'form': form})
FYI on readability, the convention is to use CamelCase for classes so your form would be named ContractsForm and lowercase-with-underscores for functions so your view would be contract_view
You can update your view like this
def ContractView(request):
form = contractsform(request.POST or None)
if form.is_valid():
con = form.save()
con.save()
return redirect("{% url 'contracts' %}", con.id)
else:
form = contractsform()
return render(request, 'contform.html', {'form': form})
I think this will solve your problem

Redirect problems with django form in a modal

I am trying to implement a form in a modal which is focused on modifying a comment in a post, the way i did it everything works, the problem is when I click on the submit button it sends me to the html in which I have the modal and there I edit the comment. when I try to delete the url in the action form that takes me to the second page of my form it throws the error "local variable 'form' referenced before assign", also if I put for example in form action the url of the login sends me towards There but the comment is not updated or edited.
My idea is simply that when I submitting the form, the modal closes, and the page where the modal was opened from the beginning, reload or simply the comment already edited appears.
if you need more information I can add it.
views.py
#need_analyst_role
def comment_modify(request, comment_id):
if 'comment_edit' in request.POST:
form_comment = FormComment(request.POST)
if form_comment.is_valid():
comment_text = form_comment.cleaned_data['text']
comment = ModelRiskTracking.objects.get(id=comment_id)
comment.comment = comment_text
print(comment.comment)
comment.save()
else:
messages.error(request, 'Error!', extra_tags="danger")
context = {}
context['comment'] = ModelRiskTracking.objects.get(id=comment_id)
return render(request, 'analyst_pages/comment_edit.html', context = context)
modal.html
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title">Editar comentario</h2>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<form action="{% url 'soc_irisk_modify' comment_id=comment.id %}" method="POST">
{% csrf_token %}
<textarea type="text" name="text" class="form-control" rows="15">{{ comment.comment|safe }}</textarea>
<div class="modal-footer">
<input type="submit" value="Actualizar" name="comment_edit" onsubmit="setFormSubmitting()" class="btn btn-info btn-sm pull-right" />
</div>
</form>
</div>
</div>
I open the modal with a button calling a jQuery function:
<script type="text/javascript">
function openModal(url){
$('#commentModal').load(url, function(){
$(this).modal('show');
});
}
</script>
<button type="button" class="btn btn-primary btn-sm pull-right" data-toggle="modal" data-target="#commentModal" onclick="openModal('{% url 'soc_comment_modify' comment_id=comment.id %}')">
when you saving the model, you need to redirect the user
#need_analyst_role
def comment_modify(request, comment_id):
if 'comment_edit' in request.POST:
form_comment = FormComment(request.POST)
if form_comment.is_valid():
comment_text = form_comment.cleaned_data['text']
comment = ModelRiskTracking.objects.get(id=comment_id)
comment.comment = comment_text
print(comment.comment)
comment.save()
return redirect("some_url")
else:
messages.error(request, 'Error!', extra_tags="danger")
return redirect("some_url")
context = {}
context['comment'] = ModelRiskTracking.objects.get(id=comment_id)
return render(request, 'analyst_pages/comment_edit.html', context = context)

Why is my django form sending as a GET and then giving a 405 error at POST

I am trying to create a 'change email' form in Django. The form is showing in the template but when I submit the form this happens in the terminal
[09/Feb/2016 09:19:55] "GET /change_email/ HTTP/1.1" 200 3775
[09/Feb/2016 09:19:55] "GET /static/css/styles.css HTTP/1.1" 304 0
[09/Feb/2016 09:20:09] "POST /account/ HTTP/1.1" 405 0
And it sends to a blank page. I've also looked in the view and noticed, with some print statements, that it's going to the last else statement rather than going through if request.POST:
Here's my code:
View:
def change_email(request):
if request.POST:
print "POST"
form = ChangeEmailForm(request.POST)
if form.is_valid():
email = request.POST['current_email']
email_new = request.POST['new_email']
email_confirmed = request.POST['confirm_email']
form.save()
if email_new == email_confirmed:
User.objects.get(email=email).update(email=request.POST['new_email'])
else:
return HttpResponse("These emails don't match")
else:
return render(request, 'registration/email_change_form.html', {'form': form})
else:
print "GET"
form = ChangeEmailForm()
return render(request, 'registration/email_change_form.html', {'form': form})
Form:
class ChangeEmailForm(forms.ModelForm):
current_email = forms.EmailField()
new_email = forms.EmailField()
confirm_email = forms.EmailField()
class Meta:
model = User
fields = ('current_email', 'new_email', 'confirm_email')
Template:
<form action="{% url 'account' %}" method="post">
{% csrf_token %}
<div class="form-group">
<label for="Current Email">Current Email:</label>
<div class="col-sm-10">
{% render_field form.current_email type="email" class+="form-control" placeholder="Current Email" %}
</div>
</div>
<div class="form-group">
<label for="New Email">New Email:</label>
<div class="col-sm-10">
{% render_field form.new_email type="email" class+="form-control" placeholder="New Email" %}
</div>
</div>
<div class="form-group">
<label for="Confirm New Email">Confirm New Email:</label>
<div class="col-sm-10">
{% render_field form.confirm_email type="email" class+="form-control" placeholder="Confirm New Email" %}
</div>
</div>
<div class="form-group" style="padding-top: 40px; text-align:right">
<button type="submit" class="btn btn-primary">Save changes</button>
</div>
</form>
URLs:
urlpatterns = [
url(r'^change_email/$', views.change_email, name="change_email"),
url(r'^account/$', TemplateView.as_view(template_name='account_details.html'), name="account"),
]
form action=""
This will send the form back to the change_email and go through the POST method part (currently it sends to another url). Also, use
if request.method == 'POST':
TemplateView will not have post method defined. It is a basic class which makes template rendering easy.
Django will throw 405 METHOD NOT ALLOWED on class based views if appropriated method is not defined for corresponding HTTP verb.
You should implement your own class:
class AccountView(TemplateView):
template_name='account_details.html'
def post(self):
# your code to handle HTTP post
# return response
def get(self):
# your code to handle HTTP get
# return response
and in urlpatterns:
url(r'^account/$', AccountView.as_view()),
More information at : https://docs.djangoproject.com/es/1.9/topics/class-based-views/

405 error with AJAX for submission

I am trying to perform ajax for my form in my Django project. I am pretty new to webdev in general so what I think I am supposed to do is have an ajax call POST in a specific url which I chose as /message/. When a POST request is sent, my view should respond to this request and update my database and also render some text within /message/. However I am getting 405 error.
urls.py:
from home.views import HomeView, contact_request_view
urlpatterns = patterns('',
url(r'^$', HomeView.as_view(), name="home"),
url(r'^message/', contact_request_view)
)
views.py:
class HomeView(generic.TemplateView):
template_name = "home/home.html"
def contact_request_view(request):
if request.method == 'POST':
form = ContactForm()
if form.is_valid():
obj, created = User.objects.get_or_create(email=form.cleaned_data['email'],
first_name=form.cleaned_data['first_name'],
last_name=form.cleaned_data['last_name'])
ContactRequest.objects.create(user=obj,
message=form.cleaned_data['message'])
return render(request, "message", "testing")
return render(request, "message", "FAIL")
form.py:
class ContactForm(forms.Form):
first_name = forms.CharField(required=True, widget=forms.TextInput(attrs={'class': 'form-control'}))
last_name = forms.CharField(required=True, widget=forms.TextInput(attrs={'class': 'form-control'}))
email = forms.EmailField(required=True, widget=forms.EmailField())
message = forms.CharField(required=True, widget=forms.Textarea(attrs={'class': 'form-control contact-margin', 'rows': '8', 'placeholder': 'Message...'}))
JS:
var contactForm = document.getElementById("contact-form");
var firstName = contactForm.getElementById("firstname");
var lastName = contactForm.getElementById("lastname");
var email = contactForm.getElementById("email");
var message = contactForm.getElementById("message");
contactForm.submit(function() {
var contactInfo = {
first_name: firstName.val(),
last_name: lastName.val(),
email: email.val(),
message: message.val()
};
$.ajax({
type: 'POST',
url: "/message/",
data: contactInfo,
success: function() {
console.log("posted");
},
error: function() {
console.log("failed")
}
});
return false;
});
form:
<section id="contact">
<div class="container">
<div class="title-container">Contact Us</div>
<div class="title-caption">Reach us at (415)-911-9999</div>
<form class="contact-input" id="contact-form" method="post">
{% csrf_token %}
<div class="col-md-12">
<div class="col-md-6">
<div class="contact-input-margin form-group">
<input id="firstname" class="form-control" placeholder="First name">
</div>
<div class="contact-input-margin form-group">
<input id="lastname" class="form-control" placeholder="Last name">
</div>
<div class="contact-input-margin form-group">
<input id="email" class="form-control" placeholder="Email">
</div>
<div class="contact-input-margin form-group">
<input class="form-control" placeholder="Phone number">
</div>
</div>
<div class="contact-input-margin col-md-6">
<div class="form-group">
<textarea id="message" rows="8" class="form-control contact-margin" placeholder="Message...">
</textarea>
</div>
</div>
</div>
<input type="submit" value="Submit" class="btn btn-xl">
</form>
</div>
</section>
Method Not Allowed because you have not defined the POST in your view, the error make sence. Your view needs the POST method to be declared:
class HomeView(generic.TemplateView):
def post(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
You should send the csrf token with the post request in your JS code or you have to turn off the csrf protection on your message view with csrf_exempt() method like this url(r'^message/', csrf_exempt(contact_request_view)).
You would need to create a form instance and populate it with data from the request:
def contact_request_view(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# if form is valid, you can process the data in form.cleaned_data
...
return render(request, "message", "testing")
else:
do_some_stuff() # if you `print(form.errors)` you can see what cause the errors
return render(request, "message", "FAIL")
Also, you might want to take a look at ModelForm
, so you can redeclare your ContactForm like this:
class ContactForm(ModelForm):
class meta:
model = User
def __init__(self, *args, **kwargs):
super(ContactForm, self).__init__(*args, **kwargs)
After that, if form is valid, you can call form.save(), and django will create the User instance automatically for you.

Categories