None returned in processing POST form - django

I am working on a web page that takes a set of song titles and artist names, and finds the lyrics for the songs.
I have a minimal search page with a POST form and a submit button.
def search(request):
formset = modelformset_factory(Song, fields=('title', 'artist', 'song_pk'))
return render(request, 'lyricfind/search.html', {'formset': formset})
for the view, and
<form method="post" action="/results/">
{% csrf_token %}
{{ formset }}
<input type="submit" value="Submit">
</form>
for the template.
However, when I enter data in the text input fields and click the submit button, an error
The view lyricfind.views.results didn't return an HttpResponse object. It returned None instead.
is thrown.
I do not see what causes this error.
I wasn't sure about how I should write my view, so the view could be the cause.
def results(request):
SongFormSet = modelformset_factory(Song)
if request.method == 'POST':
formset = SongFormSet(request.POST)
if formset.is_valid():
return HttpResponseRedirect(reverse('lyricfind/results.html', {'formset': formset}))
return render(request, 'lyricfind/search.html', {'formset': formset})
The template, results.html, just contains some plain text.
I believe urls are properly configured
url(r'^', include('lyricfind.urls', namespace='lyricfind')),
and then in lyricfind.urls,
url(r'^$', views.search, name='search'),
url(r'^results/$', views.results, name='results'),

try changing code to this:
def results(request):
SongFormSet = modelformset_factory(Song)
if request.method == 'POST':
formset = SongFormSet(request.POST)
if formset.is_valid():
# SAVE or Process Data Then:
return redirect('/some-save-confirmation-result-page')
# or if your doing just a search, should use GET and can return a rendered template.
return render(request, 'lyricfind/search.html', {'formset': formset})

Related

File uploaded in my form is not showing up in my edit/update form

When I fill out my form with its file, it apparently submits, but when checking it out when editing/uploading, all data in the form shows up except my file. So, I cannot access it at all. I guess it probably has something to do with my views.py (the function is for both, save a form for the first time and visualizing them), so here it goes
#views.py
def contract_form(request, id=0):
if request.method == "GET":
if id == 0:
form = ContractsForm(request.FILES)
else:
contratos = Contratos.objects.get(pk=id)
form = ContractsForm( instance=contratos)
return render(request,"contracts_form.html", {'form':form})
else:
if id == 0:
form = ContractsForm(request.POST, request.FILES)
else:
contratos = Contratos.objects.get(pk=id)
form = ContractsForm(request.POST, request.FILES, instance= contratos, )
if form.is_valid():
form.save()
messages.success(request, "Form submission successful")
else:
messages.error(request, "Error, contract not submitted")
return redirect('/contracts')
Just in case, every other instance that has something to do with the upload file:
#models.py
attached_file=models.FileField(upload_to="media", blank=True)
My form is stated with <form enctype="multipart/form-data" action="" method="post" autocomplete="off" class="row g-3">
#contracts_form.html
<label for="{{ form.subject.id_for_label }}">Attached File:</label>
{{form.attached_file}}
{% if Contracts.media %}
{% endif %}
#settings.py
MEDIA_ROOT=os.path.join(BASE_DIR, 'uploads/')
MEDIA_URL="/contracts-media/"
path('contracts/edit/<int:id>', views.contract_form, name='edit'), #edit/update form
path('contracts/add', views.contract_form, name = 'new-contract'), #add a contract
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
````
There's no text in your link tag
Try
Wonderful Linkiness

how to make a post request and get the radio button values in django

I'm doing a website in django but this is the first time i use this framework so i'm not so used to it. I need to save some information on a DB, and i need to take these information from some radio buttons. I tryied so many ways to get the data but nothing worked. So i'd like to ask how to get these data in models.py from a template.html.
This is the code in views.py:
def question1(request):
form = CHOICES(request.POST)
if request.method == 'POST':
form = CHOICES(request.POST)
if form.is_valid():
selected = form.cleaned_data.get("NUMS")
return render(request, 'q1.html', {'form': form})
This is the template question1.html:
<form class="form-inline" method='POST' action="" enctype='multipart/form-data'>{% csrf_token %}
{% csrf_token %}
{{form.path}}
</form>
Then there is the form in forms.py:
NUMS = [
('one', 'one'),
('two', 'two'),
('three', 'three'),
('four', 'four'),
('five', 'fives'),
]
class CHOICES(forms.Form):
NUMS = forms.ChoiceField(choices=NUMS, widget=forms.RadioSelect)
I checked and I think that the problem could be the request.method that is GET insted of POST.
So how can I make a POST request?
Thank you

Django - I'm getting "This field is required" error on UPDATING an object

When I try to use a form to edit an object that includes an image upload I get "This field is required". A similar form works fine to create the object, but when I retrieve the object and attempt to modify other fields, it fails on the image.
#-------models.py:
class Star(models.Model):
firstname = models.CharField(max_length=32)
lastname = models.CharField(max_length=32, blank=True)
portrait = models.ImageField(upload_to='images/')
#------views.py:
class StarForm(forms.ModelForm):
class Meta:
model = Star
fields = ["firstname", "lastname", "portrait"]
def staredit(request, star_id):
instance = Star.objects.get(pk=star_id)
form = StarForm(request.POST or None, instance=instance)
context = {
"form": form,
}
return render(request, "stars/edit.html", context)
def starchange(request):
form = StarForm(request.POST, request.FILES)
if form.is_valid():
newstar.save()
context = {
"message": "The form was posted",
}
return render(request, "stars/edit.html", context)
else:
context = {
"message": form.errors,
}
return render(request, "stars/edit.html", context)
#-----edit.html
<form action="/starchange" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
{{message}}
Error message:
portrait
This field is required.
You are not updating the instance, since you never have passed the instance to the view that should update it. When you make a POST requrest, the browser only submits the content of the form elements. There is no data about what has rendered the previous form, that data is lost.
You should specify the instance to update, so:
from django.shortcuts import get_object_or_404
def starchange(request, pk):
obj = get_object_or_404(Star, pk=pk)
form = StarForm(request.POST, request.FILES, instance=obj)
if form.is_valid():
form.save()
context = {
"message": "The form was posted",
}
return render(request, "stars/edit.html", context)
else:
context = {
"message": form.errors,
}
return render(request, "stars/edit.html", context)
in the urls, you thus should specify the primary key of the object to update:
urlpatterns = [
# …,
path('starchange/<int:pk>/', views.starchange, name='starchange')
]
and in the template, you should make a POST request to a view with the given instance:
<form action="{% url 'starchange' pk=form.instance.pk %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
This is one of the main reasons why often the same view is used both for a GET and POST request, since it makes it removes a lot of duplicate logic. Furthermore it is also more clean: you can use GET to retrieve the page, and POST to submit the page.
Note: In case of a successful POST request, you should make a redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.
Note: It is often better to use get_object_or_404(…) [Django-doc],
then to use .get(…) [Django-doc] directly. In case the object does not exists,
for example because the user altered the URL themselves, the get_object_or_404(…) will result in returning a HTTP 404 Not Found response, whereas using
.get(…) will result in a HTTP 500 Server Error.

Django templated does not display inputs to be filled

I need a call a form on an HTML template where the user posts data which saves to model
The code is running without any errors
But the html page display only title and button
No text input fields
I have a form which is to be displayed on a html page so the user can input data and it saves the data into the model.I am not getting any errors while executing th code but the template does not display the form it just shows the title and submit button
def boqmodel1(request):
form = boqform(request.POST)
if form.is_valid():
obj=form.save(commit=False)
obj.save()
context = {'form': form}
return render(request, 'create.html', context)
else:
context = {'error': 'The post has been successfully created.
Please enter boq'}
return render(request, 'create.html', context)
MyTemplate
<form action="" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Create boq"/>
</form>
MY Url
urlpatterns = [
url(r'^create/', views.boqmodel1, name='boqmodel1'),
path('', views.boq, name='boq'),
]
First of all, your first request, without submitting form is GET. When you submit a form you send POST.
The form is not displaying, because your form is not valid in the first place. Your function should look like this:
def boqmodel1(request):
context = {}
if request.method == "GET":
form = boqform()
context["form"] = form
# if you post a form do all the saving
if request.method == "POST":
form = boqform(request.POST)
context = {'form': form}
if form.is_valid():
obj=form.save()
return render(request, 'create.html', context)
else:
context["errors"] = form.errors
return render(request, 'create.html', context)
If method is GET init your form and pass it to your context, so you can display it on frontend.
If method is POST, init your form with your data from frontend (request.POST), check if the form is valid. If it is valid - save it. If it is not valid, return your errors and display them as you wish.

Proper way to handle multiple forms on one page in Django

I have a template page expecting two forms. If I just use one form, things are fine as in this typical example:
if request.method == 'POST':
form = AuthorForm(request.POST,)
if form.is_valid():
form.save()
# do something.
else:
form = AuthorForm()
If I want to work with multiple forms however, how do I let the view know that I'm submitting only one of the forms and not the other (i.e. it's still request.POST but I only want to process the form for which the submit happened)?
This is the solution based on the answer where expectedphrase and bannedphrase are the names of the submit buttons for the different forms and expectedphraseform and bannedphraseform are the forms.
if request.method == 'POST':
if 'bannedphrase' in request.POST:
bannedphraseform = BannedPhraseForm(request.POST, prefix='banned')
if bannedphraseform.is_valid():
bannedphraseform.save()
expectedphraseform = ExpectedPhraseForm(prefix='expected')
elif 'expectedphrase' in request.POST:
expectedphraseform = ExpectedPhraseForm(request.POST, prefix='expected')
if expectedphraseform.is_valid():
expectedphraseform.save()
bannedphraseform = BannedPhraseForm(prefix='banned')
else:
bannedphraseform = BannedPhraseForm(prefix='banned')
expectedphraseform = ExpectedPhraseForm(prefix='expected')
You have a few options:
Put different URLs in the action for the two forms. Then you'll have two different view functions to deal with the two different forms.
Read the submit button values from the POST data. You can tell which submit button was clicked: How can I build multiple submit buttons django form?
A method for future reference is something like this. bannedphraseform is the first form and expectedphraseform is the second. If the first one is hit, the second one is skipped (which is a reasonable assumption in this case):
if request.method == 'POST':
bannedphraseform = BannedPhraseForm(request.POST, prefix='banned')
if bannedphraseform.is_valid():
bannedphraseform.save()
else:
bannedphraseform = BannedPhraseForm(prefix='banned')
if request.method == 'POST' and not bannedphraseform.is_valid():
expectedphraseform = ExpectedPhraseForm(request.POST, prefix='expected')
bannedphraseform = BannedPhraseForm(prefix='banned')
if expectedphraseform.is_valid():
expectedphraseform.save()
else:
expectedphraseform = ExpectedPhraseForm(prefix='expected')
I needed multiple forms that are independently validated on the same page. The key concepts I was missing were 1) using the form prefix for the submit button name and 2) an unbounded form does not trigger validation. If it helps anyone else, here is my simplified example of two forms AForm and BForm using TemplateView based on the answers by #adam-nelson and #daniel-sokolowski and comment by #zeraien (https://stackoverflow.com/a/17303480/2680349):
# views.py
def _get_form(request, formcls, prefix):
data = request.POST if prefix in request.POST else None
return formcls(data, prefix=prefix)
class MyView(TemplateView):
template_name = 'mytemplate.html'
def get(self, request, *args, **kwargs):
return self.render_to_response({'aform': AForm(prefix='aform_pre'), 'bform': BForm(prefix='bform_pre')})
def post(self, request, *args, **kwargs):
aform = _get_form(request, AForm, 'aform_pre')
bform = _get_form(request, BForm, 'bform_pre')
if aform.is_bound and aform.is_valid():
# Process aform and render response
elif bform.is_bound and bform.is_valid():
# Process bform and render response
return self.render_to_response({'aform': aform, 'bform': bform})
# mytemplate.html
<form action="" method="post">
{% csrf_token %}
{{ aform.as_p }}
<input type="submit" name="{{aform.prefix}}" value="Submit" />
{{ bform.as_p }}
<input type="submit" name="{{bform.prefix}}" value="Submit" />
</form>
Wanted to share my solution where Django Forms are not being used.
I have multiple form elements on a single page and I want to use a single view to manage all the POST requests from all the forms.
What I've done is I have introduced an invisible input tag so that I can pass a parameter to the views to check which form has been submitted.
<form method="post" id="formOne">
{% csrf_token %}
<input type="hidden" name="form_type" value="formOne">
.....
</form>
.....
<form method="post" id="formTwo">
{% csrf_token %}
<input type="hidden" name="form_type" value="formTwo">
....
</form>
views.py
def handlemultipleforms(request, template="handle/multiple_forms.html"):
"""
Handle Multiple <form></form> elements
"""
if request.method == 'POST':
if request.POST.get("form_type") == 'formOne':
#Handle Elements from first Form
elif request.POST.get("form_type") == 'formTwo':
#Handle Elements from second Form
Django's class based views provide a generic FormView but for all intents and purposes it is designed to only handle one form.
One way to handle multiple forms with same target action url using Django's generic views is to extend the 'TemplateView' as shown below; I use this approach often enough that I have made it into an Eclipse IDE template.
class NegotiationGroupMultifacetedView(TemplateView):
### TemplateResponseMixin
template_name = 'offers/offer_detail.html'
### ContextMixin
def get_context_data(self, **kwargs):
""" Adds extra content to our template """
context = super(NegotiationGroupDetailView, self).get_context_data(**kwargs)
...
context['negotiation_bid_form'] = NegotiationBidForm(
prefix='NegotiationBidForm',
...
# Multiple 'submit' button paths should be handled in form's .save()/clean()
data = self.request.POST if bool(set(['NegotiationBidForm-submit-counter-bid',
'NegotiationBidForm-submit-approve-bid',
'NegotiationBidForm-submit-decline-further-bids']).intersection(
self.request.POST)) else None,
)
context['offer_attachment_form'] = NegotiationAttachmentForm(
prefix='NegotiationAttachment',
...
data = self.request.POST if 'NegotiationAttachment-submit' in self.request.POST else None,
files = self.request.FILES if 'NegotiationAttachment-submit' in self.request.POST else None
)
context['offer_contact_form'] = NegotiationContactForm()
return context
### NegotiationGroupDetailView
def post(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
if context['negotiation_bid_form'].is_valid():
instance = context['negotiation_bid_form'].save()
messages.success(request, 'Your offer bid #{0} has been submitted.'.format(instance.pk))
elif context['offer_attachment_form'].is_valid():
instance = context['offer_attachment_form'].save()
messages.success(request, 'Your offer attachment #{0} has been submitted.'.format(instance.pk))
# advise of any errors
else
messages.error('Error(s) encountered during form processing, please review below and re-submit')
return self.render_to_response(context)
The html template is to the following effect:
...
<form id='offer_negotiation_form' class="content-form" action='./' enctype="multipart/form-data" method="post" accept-charset="utf-8">
{% csrf_token %}
{{ negotiation_bid_form.as_p }}
...
<input type="submit" name="{{ negotiation_bid_form.prefix }}-submit-counter-bid"
title="Submit a counter bid"
value="Counter Bid" />
</form>
...
<form id='offer-attachment-form' class="content-form" action='./' enctype="multipart/form-data" method="post" accept-charset="utf-8">
{% csrf_token %}
{{ offer_attachment_form.as_p }}
<input name="{{ offer_attachment_form.prefix }}-submit" type="submit" value="Submit" />
</form>
...
This is a bit late, but this is the best solution I found. You make a look-up dictionary for the form name and its class, you also have to add an attribute to identify the form, and in your views you have to add it as a hidden field, with the form.formlabel.
# form holder
form_holder = {
'majeur': {
'class': FormClass1,
},
'majsoft': {
'class': FormClass2,
},
'tiers1': {
'class': FormClass3,
},
'tiers2': {
'class': FormClass4,
},
'tiers3': {
'class': FormClass5,
},
'tiers4': {
'class': FormClass6,
},
}
for key in form_holder.keys():
# If the key is the same as the formlabel, we should use the posted data
if request.POST.get('formlabel', None) == key:
# Get the form and initate it with the sent data
form = form_holder.get(key).get('class')(
data=request.POST
)
# Validate the form
if form.is_valid():
# Correct data entries
messages.info(request, _(u"Configuration validée."))
if form.save():
# Save succeeded
messages.success(
request,
_(u"Données enregistrées avec succès.")
)
else:
# Save failed
messages.warning(
request,
_(u"Un problème est survenu pendant l'enregistrement "
u"des données, merci de réessayer plus tard.")
)
else:
# Form is not valid, show feedback to the user
messages.error(
request,
_(u"Merci de corriger les erreurs suivantes.")
)
else:
# Just initiate the form without data
form = form_holder.get(key).get('class')(key)()
# Add the attribute for the name
setattr(form, 'formlabel', key)
# Append it to the tempalte variable that will hold all the forms
forms.append(form)
I hope this will help in the future.
view:
class AddProductView(generic.TemplateView):
template_name = 'manager/add_product.html'
def get(self, request, *args, **kwargs):
form = ProductForm(self.request.GET or None, prefix="sch")
sub_form = ImageForm(self.request.GET or None, prefix="loc")
context = super(AddProductView, self).get_context_data(**kwargs)
context['form'] = form
context['sub_form'] = sub_form
return self.render_to_response(context)
def post(self, request, *args, **kwargs):
form = ProductForm(request.POST, prefix="sch")
sub_form = ImageForm(request.POST, prefix="loc")
...
template:
{% block container %}
<div class="container">
<br/>
<form action="{% url 'manager:add_product' %}" method="post">
{% csrf_token %}
{{ form.as_p }}
{{ sub_form.as_p }}
<p>
<button type="submit">Submit</button>
</p>
</form>
</div>
{% endblock %}
Based on this answer by #ybendana:
Again, we use is_bound to check if the form is capable of validation. See this section of the documentation:
Bound and unbound forms
A Form instance is either bound to a set of data, or unbound.
If it’s bound to a set of data, it’s capable of validating that data and rendering the form as HTML with the data displayed in the HTML.
If it’s unbound, it cannot do validation (because there’s no data to validate!), but it can still render the blank form as HTML.
We use a list of tuples for form objects and their details allowing for more extensibility and less repetition.
However, instead of overriding get(), we override get_context_data() to make inserting a new, blank instance of the form (with prefix) into the response the default action for any request. In the context of a POST request, we override the post() method to:
Use the prefix to check if each form has been submitted
Validate the forms that have been submitted
Process the valid forms using the cleaned_data
Return any invalid forms to the response by overwriting the context data
# views.py
class MultipleForms(TemplateResponseMixin, ContextMixin, View):
form_list = [ # (context_key, formcls, prefix)
("form_a", FormA, "prefix_a"),
("form_b", FormB, "prefix_b"),
("form_c", FormC, "prefix_c"),
...
("form_x", FormX, "prefix_x"),
]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Add blank forms to context with prefixes
for context_key, formcls, prefix in self.form_list:
context[context_key] = formcls(prefix=prefix)
return context
def post(self, request, *args, **kwargs):
# Get object and context
self.object = self.get_object()
context = self.get_context_data(object=self.object)
# Process forms
for context_key, formcls, prefix in self.form_list:
if prefix in request.POST:
# Get the form object with prefix and pass it the POST data to \
# validate and clean etc.
form = formcls(request.POST, prefix=prefix)
if form.is_bound:
# If the form is bound (i.e. it is capable of validation) \
# check the validation
if form.is_valid():
# call the form's save() method or do whatever you \
# want with form.cleaned_data
form.save()
else:
# overwrite context data for this form so that it is \
# returned to the page with validation errors
context[context_key] = form
# Pass context back to render_to_response() including any invalid forms
return self.render_to_response(context)
This method allows repeated form entries on the same page, something I found did not work with #ybendana's answer.
I believe it wouldn't be masses more work to fold this method into a Mixin class, taking the form_list object as an attribute and hooking get_context_data() and post() as above.
Edit: This already exists. See this repository.
NB:
This method required TemplateResponseMixin for render_to_response() and ContextMixin for get_context_data() to work. Either use these Mixins or a CBV that descends from them.
If you are using approach with class-based views and different 'action' attrs i mean
Put different URLs in the action for the two forms. Then you'll have two different view functions to deal with the two different forms.
You can easily handle errors from different forms using overloaded get_context_data method, e.x:
views.py:
class LoginView(FormView):
form_class = AuthFormEdited
success_url = '/'
template_name = 'main/index.html'
def dispatch(self, request, *args, **kwargs):
return super(LoginView, self).dispatch(request, *args, **kwargs)
....
def get_context_data(self, **kwargs):
context = super(LoginView, self).get_context_data(**kwargs)
context['login_view_in_action'] = True
return context
class SignInView(FormView):
form_class = SignInForm
success_url = '/'
template_name = 'main/index.html'
def dispatch(self, request, *args, **kwargs):
return super(SignInView, self).dispatch(request, *args, **kwargs)
.....
def get_context_data(self, **kwargs):
context = super(SignInView, self).get_context_data(**kwargs)
context['login_view_in_action'] = False
return context
template:
<div class="login-form">
<form action="/login/" method="post" role="form">
{% csrf_token %}
{% if login_view_in_action %}
{% for e in form.non_field_errors %}
<div class="alert alert-danger alert-dismissable">
{{ e }}
<a class="panel-close close" data-dismiss="alert">×</a>
</div>
{% endfor %}
{% endif %}
.....
</form>
</div>
<div class="signin-form">
<form action="/registration/" method="post" role="form">
{% csrf_token %}
{% if not login_view_in_action %}
{% for e in form.non_field_errors %}
<div class="alert alert-danger alert-dismissable">
{{ e }}
<a class="panel-close close" data-dismiss="alert">×</a>
</div>
{% endfor %}
{% endif %}
....
</form>
</div>
Here is simple way to handle the above.
In Html Template we put Post
<form action="/useradd/addnewroute/" method="post" id="login-form">{% csrf_token %}
<!-- add details of form here-->
<form>
<form action="/useradd/addarea/" method="post" id="login-form">{% csrf_token %}
<!-- add details of form here-->
<form>
In View
def addnewroute(request):
if request.method == "POST":
# do something
def addarea(request):
if request.method == "POST":
# do something
In URL
Give needed info like
urlpatterns = patterns('',
url(r'^addnewroute/$', views.addnewroute, name='addnewroute'),
url(r'^addarea/', include('usermodules.urls')),
if request.method == 'POST':
expectedphraseform = ExpectedphraseForm(request.POST)
bannedphraseform = BannedphraseForm(request.POST)
if expectedphraseform.is_valid():
expectedphraseform.save()
return HttpResponse("Success")
if bannedphraseform.is_valid():
bannedphraseform.save()
return HttpResponse("Success")
else:
bannedphraseform = BannedphraseForm()
expectedphraseform = ExpectedphraseForm()
return render(request, 'some.html',{'bannedphraseform':bannedphraseform, 'expectedphraseform':expectedphraseform})
This worked for me accurately as I wanted. This Approach has a single problem that it validates both the form's errors. But works Totally fine.
I discovered a pretty interesting way to send TWO Forms from a single page using the same view. I tried many options but just wanted something that can just work. So here is something that I discovered. But it only works when there are just TWO Forms on a page.
I am using just try and except method to first try first form and if that doesnt works than try second form. This is quiet interesting to know that it works absolutely fine. Don't use it on scalable application as it can create troublesome or may risk the security of the application, else use Class based view to submit mutiple forms or create seperate views for each form.
def create_profile(request):
if request.method=='POST':
try:
biograph = Biography(name=name, email=email, full_name=full_name, slug_name=slug_name, short_bio=short_bio)
biograph.save()
except:
social = SocialMedia(twitter=twitter, instagram=instagram, facebook=facebook, linkedin=linkedin, github=github)
social.save()