I have a Django ModelForm as below:
class MeasurementForm(ModelForm):
class Meta:
model = Measurement
fields = ['weight', 'height', 'back_length', 'side_length', 'girth', 'food_consumption', 'measurement_type']
I use the form in a create_measurement view as below:
def create_measurement(request, pup_id):
pup = Pup.objects.get(id=pup_id)
if request.method == 'POST':
form = MeasurementForm(request.POST)
if form.is_valid():
measurement = form.save(commit=False)
measurement.measured_pup = pup
measurement.save()
return redirect('/pup/{{ pup.id }}')
else:
form = MeasurementForm()
return render(request, 'create_measurement.html', {'form': form, 'pup_id': pup.id})
This goes with the html:
<form action="/{{ pup_id }}/create-measurement/" method="POST">
{% csrf_token %}
{% load widget_tweaks %}
<small class="text-danger">{{ form.non_field_errors }}</small>
<div class="row">
<div class="form-group col-md-6">
<small class="text-danger">{{ form.weight.errors }}</small>
<label for="{{ form.weight.id_for_label }}">Weight:</label>
{{ form.weight|add_class:"form-control" }}
</div>
<div class="form-group col-md-6">
<small class="text-danger">{{ form.height.errors }}</small>
<label for="{{ form.height.id_for_label }}">Height:</label>
{{ form.height|add_class:"form-control" }}
</div>
</div>
<div class="row">
<div class="form-group col-md-6">
<small class="text-danger">{{ form.back_length.errors }}</small>
<label for="{{ form.back_length.id_for_label }}">Back Length:</label>
{{ form.back_length|add_class:"form-control" }}
</div>
<div class="form-group col-md-6">
<small class="text-danger">{{ form.side_length.errors }}</small>
<label for="{{ form.side_length.id_for_label }}">Side Length:</label>
{{ form.side_length|add_class:"form-control" }}
</div>
</div>
<div class="row">
<div class="form-group col-md-6">
<small class="text-danger">{{ form.girth.errors }}</small>
<label for="{{ form.girth.id_for_label }}">Girth:</label>
{{ form.girth|add_class:"form-control" }}
</div>
<div class="form-group col-md-6">
<small class="text-danger">{{ form.measurement_type.errors }}</small>
<label for="{{ form.measurement_type.id_for_label }}">Measurement Type:</label>
{{ form.measurement_type|add_class:"form-control" }}
</div>
</div>
<button type="submit" class="btn btn-primary">Add Measurement</button>
</form>
When submitting the form I receive a status 200 (OK) from the console, however the form does not save and I am not redirected to the pup details page as I should be. What am I doing wrong here?
{{ pup.id }} is Django template syntax and is supposed to use with template engines. If you need simple variable interpolation, you can use f-string instead
def create_measurement(request, pup_id):
pup = Pup.objects.get(id=pup_id)
if request.method == 'POST':
form = MeasurementForm(request.POST)
if form.is_valid():
...
return redirect(f'/pup/{pup.id}')
Related
I posted this question earlier but it was then linked to a similar question which don't provide the required solution and was then closed for answering.
So I have created a Flask Application that tracks the movement of products from one location to another while I make movements via the Flask App the form doesn't get validated I tried adding {{ form.hidden_tag() }} and {{ form.csrf_token }} to the html file that takes input from the user.
If I run this application from the terminal on my command line the form is validated and gets added to the database but if I run the flask app and submit the form in the browser it doesn't.
here is my code for the same
class MovementForm(FlaskForm):
to_location = SelectField('To Location', coerce=int)
from_location = SelectField('From Location', coerce=int)
product = SelectField('Product')
quantity = IntegerField('Quantity')
add_movement = SubmitField('Add Movement')
#app.route('/movements',methods=["GET","POST"])
def add_movements():
form = MovementForm()
form.to_location.choices = [(location.id, location.location_name) for location in Location.query.all()]
form.from_location.choices = [(location.id, location.location_name) for location in Location.query.all()]
form.product.choices = [(product.id, product.product_name) for product in Product.query.all()]
form.from_location.choices.insert(0, (0, 'None'))
if form.validate_on_submit():
new_movement = Movement(to_location_id=form.to_location.data, from_location_id=form.from_location.data, product_id=form.product.data, quantity=form.quantity.data)
db.session.add(new_movement)
db.session.commit()
flash('Product has been moved!', 'success')
return redirect(url_for('add_movements'))
return render_template('add_movements.html', form=form)
Here is my html file
<form action="/movements" method="post">
{{ form.hidden_tag() }}
{{ form.csrf_token }}
<div class="row">
<div class="form-group col">
{{ form.from_location.label(class="form-control-label") }}
{{ form.from_location(class="form-control form-control-lg") }}
</div>
<div class="form-group col">
{{ form.to_location.label(class="form-control-label") }}
{{ form.to_location(class="form-control form-control-lg") }}
</div>
</div>
<div class="row">
<div class="form-group col">
{{ form.product.label(class="form-control-label") }}
{{ form.product(class="form-control form-control-lg") }}
</div>
<div class="form-group col">
{{ form.quantity.label(class="form-control-label") }}
{{ form.quantity(class="form-control form-control-lg") }}
</div>
</div>
<div class="form-group">
{{ form.add_movement(class="btn btn-outline-info") }}
</div>
</form>
What's wrong here?
Try to remove to change in the HTML form the form's action.
<form action="" method="post">
{{ form.hidden_tag() }}
{{ form.csrf_token }}
<div class="row">
<div class="form-group col">
{{ form.from_location.label(class="form-control-label") }}
{{ form.from_location(class="form-control form-control-lg") }}
</div>
<div class="form-group col">
{{ form.to_location.label(class="form-control-label") }}
{{ form.to_location(class="form-control form-control-lg") }}
</div>
</div>
<div class="row">
<div class="form-group col">
{{ form.product.label(class="form-control-label") }}
{{ form.product(class="form-control form-control-lg") }}
</div>
<div class="form-group col">
{{ form.quantity.label(class="form-control-label") }}
{{ form.quantity(class="form-control form-control-lg") }}
</div>
</div>
<div class="form-group">
{{ form.add_movement(class="btn btn-outline-info") }}
</div>
</form>
Does this solve the issue?
Also What I suggest you is to add the Flash message into the HTML, because I see that once the Form is submitted it returns back to the 'add_movements' function. Therefore add this:
<div>
{% for msg in get_flashed_messages%}
<h1>{{msg}}</h1>
{% endfor %}
</div>
<form action="" method="post">
{{ form.hidden_tag() }}
{{ form.csrf_token }}
<div class="row">
<div class="form-group col">
{{ form.from_location.label(class="form-control-label") }}
{{ form.from_location(class="form-control form-control-lg") }}
</div>
<div class="form-group col">
{{ form.to_location.label(class="form-control-label") }}
{{ form.to_location(class="form-control form-control-lg") }}
</div>
</div>
<div class="row">
<div class="form-group col">
{{ form.product.label(class="form-control-label") }}
{{ form.product(class="form-control form-control-lg") }}
</div>
<div class="form-group col">
{{ form.quantity.label(class="form-control-label") }}
{{ form.quantity(class="form-control form-control-lg") }}
</div>
</div>
<div class="form-group">
{{ form.add_movement(class="btn btn-outline-info") }}
</div>
#EDIT
I noticed that something is missing in the product field once coerce in missing:
class MovementForm(FlaskForm):
to_location = SelectField('To Location', coerce=int)
from_location = SelectField('From Location', coerce=int)
product = SelectField('Product', coerce=int)
quantity = IntegerField('Quantity')
add_movement = SubmitField('Add Movement')
EDIT #2
In case you run in this kind of issues (which happens all the time) I suggest you to add a print statements and a If/Else clause as well. This will dramatically help you where the issue is ( The issue on your type of problem you posted is that you 'don't see it') and will give you 'eyes.'
For example this is what I would have done:
#app.route('/movements',methods=["GET","POST"])
def add_movements():
form = MovementForm()
form.to_location.choices = [(location.id, location.location_name) for
location in Location.query.all()]
form.from_location.choices = [(location.id, location.location_name)
for location in Location.query.all()]
form.product.choices = [(product.id, product.product_name) for product
in Product.query.all()]
form.from_location.choices.insert(0, (0, 'None'))
if form.validate_on_submit():
print('Form Ok') #if you see the 'Form ok' to see if is validated
new_movement = Movement(to_location_id=form.to_location.data,
from_location_id=form.from_location.data,
product_id=form.product.data, quantity=form.quantity.data)
db.session.add(new_movement)
db.session.commit()
flash('Product has been moved!', 'success')
return redirect(url_for('add_movements'))
else:
print('Form Not Ok') #If you see this printed then you see that
#is not validated
return render_template('add_movements.html', form=form)
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.
I have redefined form for contact us page, It's standard django-form stuff, but I'm struggling to understand how can I write description inside <inpout> field.
To be precise I want to write Name inside <input> field, so how can I do this. I define <input> field like {{ form.name }}, so how can I define it more like <input type="name" class="form-control" id="id_name" placeholder="Your Name">.
<div class="col-xs-12 col-sm-12 col-md-4 col-md-offset-2 col-lg-4">
{% if form.errors %}
<p style="color: red">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form class="form-horizontal" action="." method="POST">
{% csrf_token %}
<div class="field form-group">
{{ form.name.errors }}
<label for="id_name" class="control-label"></label>
<div class="col-sm-10">
{{form.name}}
</div>
</div>
<div class="field form-group">
{{ form.email.errors }}
<label for="id_email" class="control-label"></label>
<div class="col-sm-10">
{{ form.email }}
</div>
</div>
<div class="field form-group">
{{ form.phone_number.errors }}
<label for="id_phone_number" class="control-label"></label>
<div class="col-sm-10">
{{ form.phone_number }}
</div>
</div>
<div class="field form-group">
{{ form.message.errors }}
<label for="id_message" class="control-label"></label>
<div class="col-sm-10">
{{ form.message }}
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<input type="submit" class="btn btn-primary btn-block" value="Submit"></button>
</div>
</div>
</form>
</div><!--/end form colon -->
If you want to modify the placeholder text, or other values of the field Django creates, it can be done in the form code using the widget's attrs:
class MyForm(forms.Form):
name = forms.CharField(
widget=forms.TextInput(
attrs={
'class': 'my-class',
'placeholder': 'Name goes here',
}))
If your intention is to keep all of the code in the template you will have to manually create each input field instead of using the ones Django renders. You can still access the values of the generated field in the template to help you do that though.
<input name="{{ form.name.name }}" type="text" placeholder="Name field">
I am currently learning python and am trying to write an app. I have the basics done. I followed a tutorial which was helpful but have gotten stuck. My understanding is 100% up to scratch yet so any help and reasoning behind it would be great.
I am getting a Method Not Allowed Error when trying to submit a form. I will post the code below and hopefully someone can help.
new_action.py
{% extends "base.html" %}
{% block content %}
<h2>New Action Request</h2>
{% include 'flash.html' %}
<div class="well">
<form class="form-horizontal" action="" method="post" name="post">
{{ form.hidden_tag() }}
<div class="control-group{% if form.errors %} error{% endif %}">
<label class="pull-right" for="post">Date: {{
datetime.date(datetime.utcnow()) }}</label>
<div class="controls">
{{form.timestamp}}
</div>
<label class="control-label" for="post">Raised By:</label>
<div class="controls">
{{ form.raised_by }}
{% for error in form.errors.post %}
<span class="help-inline">[{{ error }}]</span><br>
{% endfor %}
</div>
<br/>
<label class="control-label" for="post">Source:</label>
<div class="controls">
{{ form.source }}
{% for error in form.errors.post %}
<span class="help-inline">[{{ error }}]</span><br>
{% endfor %}
</div>
<br/>
<label class="control-label" for="post">Category:</label>
<div id="radios1" class="controls" data-toggle="buttons-radio">
<button type="button" class="btn active" name="health_safety" value="health_safety">Health &
Safety</button>
<button type="button" class="btn" name="quality" value="quality">Quality</button>
<input type="hidden" name="category" value={{request.form['category']}} />
</div><br/>
<br/>
<label class="control-label" for="post">Sub-Category:</label>
<div class="controls">
{{ form.sub_category }}
{% for error in form.errors.post %}
<span class="help-inline">[{{ error }}]</span><br>
{% endfor %}
</div>
<br/>
<label class="control-label" for="post" width="80%" >Description:</label>
<div class="controls" >
{{ form.issue }}
{% for error in form.errors.post %}
<span class="help-inline">[{{ error }}]</span><br>
{% endfor %}
</div>
<br/>
<label class="control-label" for="post">Immediate Action:</label>
<div class="controls">
{{ form.immediate_action }}
{% for error in form.errors.post %}
<span class="help-inline">[{{ error }}]</span><br>
{% endfor %}
</div>
</div>
<div class="control-group">
<div class="controls">
<input class="btn btn-primary" type="submit" value="Submit Action Request">
</div>
</div>
</form>
</div>
{% endblock %}
Views.py
#app.route('/new_action', methods=['GET', 'SET'])
#login_required
def new_action():
form = ActionRequestForm()
if request.method == 'POST':
return redirect(url_for('index'))
#actionrequest = ActionRequest(id = form.id.data, category = form.category.data)
'''post = Post(body=form.post.data, timestamp=datetime.utcnow(),
author=g.user)
db.session.add(post)
db.session.commit()
flash('Your post is now live!')'''
return render_template('new_action.html',
user = user,
form = form,
datetime = datetime
)
Your form is trying to POST data to the server. This is a HTTP POST request. You define GET and SET methods in your view. You need to use POST there.
#app.route('/new_action', methods=['GET', 'POST']) # Changed SET to POST here
#login_required
def new_action():
# ... what ever...
You should go through this RFC for HTTP. There is no SET-method.
#app.route('/new_action', methods=['GET', 'SET'])
This line of code is only allowing "GET" and "SET" methods, while you are trying to "POST" to that route.
Have form.
class AddLogo(forms.Form):
title = forms.CharField(max_length=100)
date = forms.TimeField()
image = forms.ImageField()
And have standard Django preview form.
from django.contrib.formtools.preview import FormPreview
from django.http import HttpResponseRedirect
from company.models import Company
class add_logo_preview(FormPreview):
form_template = 'add_logo_preview.html'
def done(self, request, cleaned_data):
return HttpResponseRedirect('/company/hey/')
In template
{% extends "base.html" %}
{% block block_js %}
{% endblock block_js %}
{% block content %}
<h1>Preview your submission</h1>
{% with form as job %}
<div class="job_block">
<div class="job_content">
<div class="job_title">
<h1>{{ job.title.data }}</h1>
<span class="date">{{ job.date.date.data }}</span>
</div>
<div class="job_company">
<div class="company_logo">
{{ job.image.url }}
</div>
<div class="company_description">
<div class="name">{{ job.company_name.data }}</div>
<div class="location">Главный офис: {{ job.company_location.data }}</div>
<div class="website">{{ job.company_url.data }}</div>
</div>
</div>
<article>
{{ job.description.data|safe }}
</article>
</div>
<aside>
<h4>Поделиться вакансией</h4>
</aside>
</div>
<div class="job_feedback">
<h3>Откликнутся на вакансию</h3>
<p>{{ job.apply_terms.data|safe }}</p>
</div>
{% endwith %}
<p>Security hash: {{ hash_value }}</p>
<form action="" method="post">{% csrf_token %}
{% for field in form %}{{ field.as_hidden }}
{% endfor %}
<input type="hidden" name="{{ stage_field }}" value="2" />
<input type="hidden" name="{{ hash_field }}" value="{{ hash_value }}" />
<p><input type="submit" value="Submit" /></p>
</form>
<h1>Or edit it again</h1>
<h1>Шаг первый: создайте свое объявление</h1>
<form action="/job/preview/" method="POST" class="form">{% csrf_token %}
<h3>Опишите вакансию</h3>
<fieldset>
<div class="label_box">
<label for="">Назавние вакансии</label>
</div>
<div class="fields_box">
{{ form.title }}
</div>
</fieldset>
<fieldset>
<div class="label_box">
<label for="">Категория</label>
</div>
<div class="fields_box">
{% for cat in form.category %}
{% if cat.choice_value %}
{{ cat }}
{% endif %}
{% endfor %}
</div>
</fieldset>
<fieldset>
<div class="label_box">
<label for="">Головной офис</label>
</div>
<div class="fields_box">
{{ form.company_location }}
</div>
</fieldset>
<fieldset class="one_col">
<div class="label_box">
<label for="">
Описание вакансии
</label>
</div>
<div class="fields_box">
{{ form.description }}
</div>
</fieldset>
<fieldset>
<div class="label_box">
<label for="">
Apply this job.
</label>
</div>
<div class="fields_box">
{{ form.apply_terms }}
</div>
</fieldset>
<h3>О компании</h3>
<fieldset>
<div class="label_box">
<label for="">Название</label>
</div>
<div class="fields_box">
{{ form.company_name }}
</div>
</fieldset>
<fieldset>
<div class="label_box">
<label for="">Логотип</label>
</div>
<div class="fields_box">
{{ form.image }}
</div>
</fieldset>
<fieldset>
<div class="label_box">
<label for="">URL</label>
</div>
<div class="fields_box">
{{ form.company_url }}
</div>
</fieldset>
<fieldset>
<div class="label_box">
<label for="">Email</label>
</div>
<div class="fields_box">
{{ form.company_email }}
</div>
</fieldset>
<fieldset>
<div class="label_box">
<span>
Подсветить это объявление?
</span>
<label for="">{{ form.highlight }} Подсветить?</label>
</div>
</fieldset>
<input type="submit" value="Просмотреть">
</form>
{% endblock %}
I try: {{ form.image.url }} but does not work. I understand one: Django do not upload file, but how i cane change this? How i can make preview image in django FormPreview?
Convert your image to a base64 string, add a field to your form for that base 64 string. In the preview template, display the base64 string. And when finally saving the image, you will need to create a file, write the content of the base 64 string to it, and then save that file to your model.