My form is not saving to the database or at least i know the form is not valid i just dont know why? because it will always skip to the else in the if form.is_valid() (print("didnt work!"))
the view.py:
def index(request):
component = Component.objects.all()
form = ComponentModelForm()
if request.method == 'POST':
form = ComponentModelForm(request.POST)
if form.is_valid():
form.save()
return redirect('/maintenance')
else:
form = ComponentModelForm()
print("didnt work!")
context = {
'components': component,
'form': form,
}
return render(request, 'maintenance/index.html', context)
forms.py:
class ComponentModelForm(forms.ModelForm):
note = forms.CharField(widget=forms.Textarea)
image = forms.ImageField(error_messages = {'invalid':("Image files only")}, widget=forms.FileInput)
class Meta:
model = Component
fields = ("name",
"manufacturer",
"model",
"serial_number",
"price",
"note",
"image",
"parent",)
the template form:
{% load widget_tweaks %}
<form class="component-update-grid" enctype="multipart/form-data" method='POST' action=''>
{% csrf_token %}
<div class="component-form-data">
<span class="component-label-text">Name</span>
{% render_field form.name class="component-form-data-inputs" %}
<span class="component-label-text">Manufacturer</span>
{% render_field form.manufacturer class="component-form-data-inputs" %}
<span class="component-label-text">Model</span>
{% render_field form.model class="component-form-data-inputs" %}
<span class="component-label-text">Serial Number</span>
{% render_field form.serial_number class="component-form-data-inputs" %}
<span class="component-label-text">Price</span>
{% render_field form.price class="component-form-data-inputs" %}
<span class="component-label-text">Note</span>
{% render_field form.note class="component-form-data-inputs" %}
{% render_field form.parent class="component-form-data-inputs " %}
<input type="submit" class="button1" value='Create Component' />
</div>
<div class="component-form-img">
<img class="maintenance-component-img" src='{%static 'imgs/sidebar/logo.png'%} ' />
{% render_field form.image %}
</div>
</form>
You should not construct a new form when the form fails: a failed form will render the errors, such that the user knows what is going wrong, so:
def index(request):
component = Component.objects.all()
form = ComponentModelForm()
if request.method == 'POST':
form = ComponentModelForm(request.POST)
if form.is_valid():
form.save()
return redirect('/maintenance')
else:
# Don't create a new form!
print("didnt work!")
context = {
'components': component,
'form': form,
}
return render(request, 'maintenance/index.html', context)
Related
I'm trying to render this form set:
ProductFormSet = modelformset_factory(
model=Product,
fields='__all__',
extra=5,
)
class ProductFormSetHelper(FormHelper):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_tag = False
self.layout = Layout(
Row(
'productCategory',
'name',
'measurement_unit',
)
)
self.render_required_fields = True
with this view:
def product_create(request):
helper = ProductFormSetHelper()
context = {
'helper': helper,
'title': 'Nuovi Prodotti',
}
if request.method == 'GET':
formset = ProductFormSet(queryset=Product.objects.none())
context['formset'] = formset
elif request.method == 'POST':
formset = ProductFormSet(request.POST)
context['formset'] = formset
if formset.is_valid():
formset.save()
messages.success(request, 'Prodotti aggiunti correttamente', fail_silently=True)
return HttpResponseRedirect(reverse('warehouse:products_list'))
else:
return render(request, 'warehouse/product_create.html', context)
return render(request, 'warehouse/product_create.html', context)
and this template:
{% extends "masterpage.html" %}
{% load static %}
{% block headTitle %}
<title>Nuovo Prodotto</title>
{% endblock %}
{% block contentHead %}
{% endblock %}
{% block contentBody %}
{% load document_tags %}
{% load custom_tags %}
{% load crispy_forms_tags %}
<FORM method="POST" autocomplete="off">
<div class="alert alert-info">
{{ title }}
</div>
{{ formset.management_form }}
{% crispy formset helper %}
<input type="submit" class="btn btn-primary margin-left" value="SALVA">
</FORM>
{% endblock %}
Problem is that when I submit the form I get the: ValidationError: management form data are missing! First of all, using crispy forms the management data should be included, second even if I explicitly call with the tag, I still get the ValidationError.
in Every forum I searched online, everyone was missing the management form tag, so I have no clue on what could be wrong....
Any idea?
thank you very much
C
in your Post method you didnt include the "queryset"
formset = ProductFormSet(queryset=Product.objects.WHATEVER_YOU_CHOOSE, request.POST)
and for crispy forms
{% load crispy_forms_tags %}
<form method="post">
{% csrf_token %}
{{ formset|crispy }}
{{ formset.management_form }}
<input type="submit" class="btn btn-primary margin-left" value="SALVA">
</form>
and because you are not working in get_context_data fucntion, just keep it simple
context = {'formset':formset}
Exemple from the docs
from django.forms import modelformset_factory
from django.shortcuts import render
from myapp.models import Author
def manage_authors(request):
AuthorFormSet = modelformset_factory(Author, fields=('name', 'title'))
if request.method == "POST":
formset = AuthorFormSet(
request.POST, request.FILES,
queryset=Author.objects.filter(name__startswith='O'),
)
if formset.is_valid():
formset.save()
# Do something.
else:
formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))
return render(request, 'manage_authors.html', {'formset': formset})
Hope it can help others. Since I'm having troubles configuring the thousand separator, I tried to change the input.html widget in /templates/django/forms/widgets by adding the |intcomma filter.
This altered the management form data ( one field is set to 1000 by default ), thus corrupting the whole form.
I'm working on a single page site which is to have 3 different forms on the same page:
Tour form
flight form
bookform
I created the forms using model form, but how do I display the forms such that my site will know which form I'm submitting data to ?
you need pass your forms in your views.py
from your_app.forms import TourForm, FlightForm, BookForm
def your_view_name(request):
if request.method == 'POST':
tour_form = TourForm(request.POST or None)
flight_form = FlightForm(request.POST or None)
book_form = BookForm(request.POST or None)
# so you have 3 different forms
if tour_form.is_valid():
tour_form.save()
return redirect('some_url')
elif flight_form.is_valid():
flight_form.save()
return redirect('some_url')
elif book_form.is_valid():
book_form.is_save()
return redirect('some_url')
else:
return redirect('some_url')
else:
tour_form = TourForm()
flight_form = FlightForm()
book_form = BookForm()
context = {
'tour_form': tour_form,
'flight_form': flight_form,
'book_form': book_form
}
return render(request, 'your_template_name.html', context)
then simply in your template add your forms
<form method='post'>
{% csrf_token %}
{{ tour_form }}
<button class='btn btn-primary' type='submit'>submit</button>
</form>
<form method='post'>
{% csrf_token %}
{{ flight_form }}
<button class='btn btn-primary' type='submit'>submit</button>
</form>
<form method='post'>
{% csrf_token %}
{{ book_form }}
<button class='btn btn-primary' type='submit'>submit</button>
</form>
I'm new to Python Django and I'm trying to set up a bound form with three fields where one field (which will be read only) takes an initial value and displays it on the form; the other two fields will be populated by the user when they completes the form. But when I try to submit the form, the form.is_valid returns false, and I'm not sure what I did wrong. Can anyone please help?
Thanks
Here's the code:
views.py
class AddKeyAccompView(TemplateView):
template_name = 'AddKeyAccomp.html'
def get(self, request, Program):
username = request.user.username
form = AddKeyAccompForm(request, Program=Program)
return render(request, self.template_name, {'form': form
,'title':'Add New Key Accomplishment'
,'User': username
})
def post(self, request, Program):
username = request.user.username
form = AddKeyAccompForm(request.POST, Program=Program)
if form.is_valid():
Name = form.cleaned_data['Name']
Description = form.cleaned_data['Description']
form.save()
form = AddKeyAccompForm(request, Program=Program)
return HttpResponseRedirect(reverse('ModInit', args=[Program]))
else:
return HttpResponse('invalid form')
args = {'form': form
,'title':'Add New Key Accomplishment'
,'User': username
,'Name': Name
,'Desc': Description
,'Program': Program
}
return render(request, self.template_name, args)
forms.py
class AddKeyAccompForm(forms.ModelForm):
def __init__(self, request, *args, **kwargs):
self.program = kwargs.pop('Program')
super(AddKeyAccompForm, self).__init__(*args, **kwargs)
self.fields['Program'].initial = self.program
class Meta:
model = Key_Accomplishments
fields = ('Name', 'Description', 'Program',)
widgets = {
'Name': forms.TextInput(attrs={'required':True, 'class':'form-control'})
,'Description': forms.Textarea(attrs={'required': True, 'class':'form-control'})
,'Program': forms.TextInput(attrs={'readonly':'readonly', 'class':'form-control'})
}
html file
{% extends 'base.html' %}
<!DOCTYPE html>
<html>
<head>
{% block head %}
<title>New Key Accomplishment</title>
{% endblock %}
</head>
<body>
{% block body %}
<div class="container">
<ol class="breadcrumb my-4">
<li class="breadcrumb-item active">
<center>{{ title }}</center>
</li>
</ol>
</div>
<br>
<div class="offset-3 col-md-6">
<form method="post">
{% csrf_token %}
<div class="form-group" style="padding-left:10%;">
{% for field in form %}
<label>{{ field.label_tag }}</label>
{{ field }}
<br>
{% endfor %}
</div>
<div class="btn" style="padding-left: 10%;">
<button type="submit">Submit</button>
</div>
</form>
</div>
{% endblock %}
</body>
</html>
My file is being uploaded in the correct path but I have an issues with it:
Whenever I refresh my HTML page the file gets uploaded again and again. How do I solve this? Also
Please help me with the code or suggest me.
Thanks in advance:)
My views.py
def about_experiment(request, ex_link_name):
researcher = None
study = None
posts = None
exp = get_object_or_404(Experiment,link_name = ex_link_name)
high_scores = ScoreItem.objects.filter(experiment=exp,active=True)
context = {
'request': request,
'exp':exp,
'high_scores': high_scores,
'awards':AwardItem.objects.filter(experiment=exp,visible=True),
}
if exp.about_file:
context['about_file'] = settings.EXPERIMENT_DIRS+exp.about_file.get_include_path()
return render(request, 'about_experiment.html', context)
if request.method == 'POST':
form = AboutHelp(request.POST, request.FILES)
posts = Help.objects.filter().order_by('-date')[0]
documents = Help.objects.all()
if form.is_valid():
obj = form.save(commit = False)
obj.save()
researcher = form.cleaned_data['researcher']
study = form.cleaned_data['study']
document = form.cleaned_data['document']
else:
form = AboutHelp()
posts = Help.objects.filter().order_by('-date')[0]
documents = Help.objects.all()
return render(request, 'about_experiment.html', {'posts': posts})
return render(request, 'about_experiment.html', {'posts': posts})
Source page
<form action="{% url 'lazer.views.about_experiment' exp.link_name %}" method="POST" name="form" enctype="multipart/form-data">
{% csrf_token %}
<label>Researcher Name(s):
<input type="text" name="researcher"><br>
<lable>Study Summary
<textarea rows="10" cols="50" placeholder="Start typing..." maxlength="500" class="form-control" name="study"></textarea>
<br>
<label>Upload your IRB approval letter:
<input type ="file" id="irb-file" class="file_input" name="document"></label>
<br>
<input type = "submit" value="Submit" class="btn btn-primary" />
</form>
destination page
<div class="tab-pane" id="irb">
<h4> List of file(s) uploaded:</h4>
<!--File upload-->
{% if documents %}
<ul>
{% for file in documents %}
<li> {{ file.document.name }} </li>
{% endfor %}
</ul>
{% else %}
<p>No such documents available.</p>
{% endif %}
<!--File upload ends-->
</div>
{% if high_scores %}
{% for hs in high_scores %}
<div class="tab-pane" id="{{ hs.link_name }}">
{% high_score request exp.link_name hs.link_name %}
</div>
{% endfor %}
{% endif %}
As #almost a beginner pointed out, you should be redirecting to some other view, if your form is submitted successfully. If not, (in your case), when the page reloads, the code for POST request is executed again. ie, your form is submitted again. I could suggest some changes in your view,
def about_experiment(request, ex_link_name):
exp = get_object_or_404(Experiment,link_name = ex_link_name)
high_scores = ScoreItem.objects.filter(experiment=exp,active=True)
context = {
'request': request,
'exp':exp,
'high_scores': high_scores,
'awards':AwardItem.objects.filter(experiment=exp,visible=True),
'posts':Help.objects.filter().order_by('-date')[0],
'documents':Help.objects.all()
}
if exp.about_file:
context['about_file'] = settings.EXPERIMENT_DIRS+exp.about_file.get_include_path()
if request.method == 'POST':
form = AboutHelp(request.POST, request.FILES)
if form.is_valid():
obj = form.save(commit = False)
obj.save()
return redirect(reverse('lazer.views.about_experiment', kwargs={ 'ex_link_name':obj.link_name }))
else:
form = AboutHelp()
return render(request, 'about_experiment.html', context)
Here, I merely assumed your obj has a field link_name. You may need to change that according to your models.
When I submit this form, neither are saved in the database but the HttpResponseRedirect works successfully. Any ideas why?
views.py
#login_required
def entry(request):
fantasyTeamForm = FantasySeasonForm() #Form to store each player in the fantasy team
seasonUserTournForm = PartialSeasonEntryForm()
season_tournament_id = 1
tournament_classic = Tournament(pk=season_tournament_id)
user_instance = request.user
if request.method == 'POST':
fantasyTeamForm = FantasySeasonForm(request.POST or None)
fantasyTeamForm.fields
if fantasyTeamForm.is_valid():
fantasyTeamForm.save(commit=False)
seasonUserTourn = ClassicSeasonUserList(
tournament=tournament_classic,
fantasy_team=fantasyTeamForm['FANTASY_TEAM_ID'],
user=user_instance.id,
)
seasonUserTournForm = PartialSeasonEntryForm(request.POST or None, instance=seasonUserTourn)
seasonUserTournForm.fields
if seasonUserTournForm.is_valid():
seasonUserTournForm.save()
fantasyTeamForm.save()
return HttpResponseRedirect('/season/entrysuccess') #page on success
args = {}
args.update(csrf(request))
args['form'] = fantasyTeamForm
args['form2'] = seasonUserTournForm
return render_to_response('entry.html', args, context_instance=RequestContext(request))
entry.html
<h2><b>Choose your team:</b></h2><br>
{% for field in form %}
{{field.error}}
{% endfor %}
{% for field in form2 %}
{{field.error}}
{% endfor %}
<form action="/season/entrysuccess" method="post"> {% csrf_token %}
{{form2}}
<br><br>
{{form.as_ul}}
<br>
<input type="submit" value="Submit Team" />
</form>
form action in html should have been:
<form action="/season/entry" method="post">
instead of
<form action="/season/entrysuccess" method="post">