I have a page, and there are 3 types of button(apple,banana, orange), by clicking the first button, a form comes up to get information. The first button should send information to the apple Model, the banana button should send information to the banana Model and so orange!
here is my models.py:
from django.db import models
class Apple(models.Model):
first_name = models.CharField(max_length=100)
class Banana(models.Model):
first_name = models.CharField(max_length=100)
class Orange(models.Model):
first_name = models.CharField(max_length=100)
my forms.py:
from django import forms
class Fruit(forms.Form):
first_name = forms.CharField(max_length=100)
my views.py:
def fruitForm(request):
form = Fruit()
if request.method == 'POST' & request.id == 'apple':
form = Fruit(request.POST)
if form.is_valid():
Apple.objects.create(**form.cleaned_data)
elif request.method =='POST' & request.id =='orange':
form = Fruit(request.POST)
if form.is_valid():
Orange.objects.create(**form.cleaned_data)
elif request.method =='POST' & request.id =='banana':
form = Fruit(request.POST)
if form.is_valid():
Banana.objects.create(**form.cleaned_data)
return render(request, 'main/home.html', {'form':form})
my home.html:
<button class='btn btn-primary' data-target='#orange'> Add </button>
<form action=# method="POST" id = "orange">
{% csrf_token %}
{{ form.as_p }}
</form>
well, when I try go to main page (where the buttons are), I got this error:
'WSGIRequest' object has no attribute 'id'.
request doesn't have the id attribute, right? So, How can I get specific data to save in relative model?
You can add a name to a submit input, the value is the text content of the button so cannot really be used for this
<form>
<input type="submit" class="btn btn-primary" name="orange" value="Add">
<input type="submit" class="btn btn-primary" name="apple" value="Add">
</form>
This value will then be one of the keys in the post data
if 'orange' in request.POST:
pass
elif 'apple' in request.POST:
pass
The attributes of the POST request body come from the name attributes of the form inputs. So one way to handle this, if you want to keep your view function the same, is to add a hidden field to each form that distinguishes which model it should update:
<form action=# method="POST" id = "orange">
{% csrf_token %}
<input type="hidden" name="id" value="orange" />
{{ form.as_p }}
</form>
And similarly for the other 2 forms.
(This isn't the only way to solve this problem. You could, for example, have a variable in your URL which specifies which model to use. Then you could check its value in your view function. This requires a bit more work though, including changing your urls.py.)
Related
What I really want to do is , if a user click on "ADD more" button then a same form repeat itself and the values should store in database, if he/she doesn't click of that button then only the values from first form should be stored.
I am not able to get this, I just created a form , and a table in database for those details but can't loop though the form neither in data.
please help.
This is the form and the button:
This is the model.py code:
from django.db import models
class experience(models.Model):
company_name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
startdate = models.Datefield(default = 01-01-2020)
lastdate = models.DateField(default = 01-01-2020)
profile = models.CharField(max_length=100)
description = models.TextField(max_length = 250)
This is the views.py code:
from django.shortcuts import render, redirect
import requests
from django.contrib.auth.models import User, auth
# Create your views here.
def profile(request):
return render(request, 'profile.html')
Unfortunately, there's no built-in way (as far as I know) in Django to do that without Javascript, but here's an approach:
HTML:
<div class="container" id="experiencesContainer">
<form method='POST' name='experienceForm'>
{{form.as_p}}
</form>
<form method='POST' name='experienceForm'>
{{form.as_p}}
</form>
<button type="button" id="addMoreButton">Add more</button>
<button type="submit">Save Changes</button>
</div>
Django POST method:
# Get a list of submitted forms
experiences = request.POST.getlist('experienceForm')
for experience in experiences:
# this is how you loop throuh every form
experience.get('company_name)
Your javascript something like:
// clonning his childs as well
let cloneForm = document.querySelector('form[name=experienceForm]').cloneNode(true);
document.querySelector('div#experiencesContainer').appendChild(cloneForm);
// see this https://www.w3schools.com/jsref/met_node_clonenode.asp
Of course this code is not tested but I've done this in several projects before, hope it works!
A simple way would be to request the same view from the "Add", just make sure your form view saves the data when request method is POST.
<form action="{% url 'your-form-url' %}" method="GET">
{% csrf_token %}
<input type="submit" value="Add">
</form>
one other way to repeat forms would be using formsets. Formsets allow you to repeat the same form 'extra' times. Check out the documentation for more about this.
def repeat_form(request):
ExpFormSet = formset_factory(ExperienceForm, extra=3)
#extra defines the no. of forms you want to display
if request.method == 'POST':
formset = ExpFormSet(request.POST, request.FILES)
if formset.is_valid():
# do something with the formset.cleaned_data
#loop through each form in the formser
for form in formset.cleaned_data:
obj = form.save()
else:
formset = ExpFormSet()
return render(request, 'exp_form.html', {'formset': formset})
The corresponding template should be:-
<form method="post">
{{ formset.management_form }}
{% for form in formset %}
{{ form.as_p }}
{% endfor %}
</form>
Make sure you add form.management_form. Using the combination of the above might solve your problem of taking and saving several inputs.
This is my view.py and when i have a form which when i submit with the required fields it gives an appropriate output but when i don't input anything in the form and click submit i get an error saying "local variable 'researcher' referenced before assignment".
Also i want to know how do i keep my form data saved on the destination page
def about_experiment(request,ex_link_name):
if request.method == 'POST':
form = AboutHelp(request.POST)
if form.is_valid():
researcher = form.cleaned_data['researcher']
study = form.cleaned_data['study']
else:
form = AboutHelp()
return render(request, 'about_experiment.html', {'researcher': researcher, 'study': study})
my form on the source page is
<form action="{% url 'lazer.views.about_experiment' exp.link_name %}" method="POST" name="form">
{% csrf_token %}
<label>Researcher Name(s):<input type="text" name="researcher">
<lable>Study Summary<textarea rows="10" cols="50" placeholder="here you go" maxlength="500" class="form-control" name="study"></textarea>
<br>
<input type = "submit" value="Submit" class="btn btn-primary" />
</form>
My destination page where the form outputs are present
<h4> Name : {{ researcher }} </h4><br>
<h4> Summary : {{ study }} </h4>
in else part of views.py you mentioned researcher variable in render method that is producing this error.
so please add
researcher = None
before if statement
and also add
study = None
that will also create same error
forms.py
from django import forms
from .models import AboutHelp
class AboutHelpForm(forms.ModelForm):
class Meta:
model = AboutHelp
fields = '__all__'
views.py
def about_experiment(request,ex_link_name):
researcher = None
study = None
form = AboutHelpForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
form.save()
return render(request, 'about_experiment.html', {'researcher': researcher, 'study': study})
researcher and study are not assignment if request method is not POST and form is not valid. You should define this variable before if statement:
def about_experiment(request,ex_link_name):
researcher = ''
study = ''
if request.method == 'POST':
...
I've got a feedback app in django and it all seems to work fine, no errors i can submit the form and it all seems to work, however i have my model registered into my admin however when i submit the form i doesn't appear in my admin. Sorry if this is very basic i just cant get my head around it please help.
in my models.py
class Feedback(models.Model):
email = models.CharField(max_length=100)
message = models.CharField(max_length=1000)
def __unicode__(self):
return self.title
which i then pass through to forms.py
class FeedbackModelForm(forms.ModelForm):
class Meta:
model = Feedback
fields = ["email", "message"]
and my view is
def feedbackform(request):
form = FeedbackModelForm(request.Post or None)
if form.is_valid():
form.save()
return render(request, "feedback.html", {"form": form})
now in my html looks like this
{% block content %}
<div id="feedback">
<div id="feedback-form" style='display:none;' class="col-xs-4 col-md-4 panel panel-default">
<form method="POST" action="{{ form }}" class="form panel-body" role="form">{% csrf_token %}
<div class="form-group">
<input class="form-control" name="email" autofocus placeholder="Your e-mail" type="email" />
</div>
<div class="form-group">
<textarea class="form-control" name="message" required placeholder="Please write your feedback here..." rows="5"></textarea>
</div>
<button class="btn btn-primary pull-right" type="submit">Send</button>
</form>
</div>
<div id="feedback-tab">Feedback</div>
</div>
{% endblock %}
and in my admin
from .models import Feedback
from .forms import FeedbackModelForm
class FeedbackAdmin(admin.ModelAdmin):
form = FeedbackModelForm
admin.site.register(Feedback, FeedbackAdmin)
You have passed the
{{ form }}
as the action attribute, which is completely wrong. Put it inside a div as
{{ form.as_p }}
that will work for you.
And in the action attribute pass a url in the form of
{% url 'home_page_example' %}
if you wanted to remain in the same page and redirect via view
you can write
action = "."
Show us how did you register your model in the admin.
Make sure that you explicit config the form, like this
class FeedbackAdmin(admin.ModelAdmin)
form = FeedbackModelForm
admin.site.register(Feedback, FeedbackAdmin)
You should return email or message in def __unicode__(self):, not title.
class Feedback(models.Model):
email = models.CharField(max_length=100)
message = models.CharField(max_length=1000)
def __unicode__(self):
return self.email
I think that you should check if the view is currently saving your Feedback.
Try inspecting the DB or in a manage.py shell check if len(Feedback.objects.all()) change when you submit a Feedback in your view.
Also, I recommend you to change the email field to an EmailField and use the FormView class based view.
I want to save changed values of ModelForm to database. I'm having problems even I follow this documentation if I'm right that it can be possible with initial values: Documentation- providing initial values
models.py:
class Settings(models.Model):
url = models.URLField(max_length=100, default='https://website.com')
maxCount = models.SmallIntegerField(default=30)
views.py:
def Settings(request):
settingsObj = Settings.objects.get(id=1)
form = SettingsForm(initial={'url': settingsObj.url, 'maxCount':settingsObj.maxCount}, instance=settingsObj)
if form.is_valid():
form.save()
forms.py:
class SettingsForm(forms.ModelForm):
class Meta:
model = Settings
fields = ['url', 'maxCount']
templates
<form class="form-horizontal" role="form" method="POST">{% csrf_token %}
<div class="form-group">
<div class="col-sm-offset-1 col-sm-6">
{{ form.as_p }}
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-1 col-sm-6">
<button type="submit" class="btn btn-primary btn-lg btn-block">Accept</button>
</div>
</div>
</form>
Currently the form is showing the current values from database, but isn't saving changed data. form.is_valid() returns True, but form.save() seems to do nothing.
The initial argument and the instance argument in your call to SettingsForm() serve the exact same purpose, because you are using the fields of the instance individually in each field of initial.
The save() method is not working because you need to populate the form with data from request.POST.
This view should work:
def settings(request):
settingsObj = Settings.objects.get(id=1)
if request.POST:
form = SettingsForm(request.POST, instance=settingsObj)
if form.is_valid():
form.save()
else:
form = SettingsForm(instance=settingsObj)
context = { ..., 'form': form, ... }
return render(request, 'template-address', context)
This is my form:
from django import forms
class UploadFileForm(forms.Form):
titl = forms.CharField(max_length=50)
ffile = forms.FileField()
This is my views.py file:
def handle_uploaded_file(file_path):
print "handle_uploaded_file"
dest = open(file_path.name,"wb")
for chunk in file_path.chunks():
dest.write(chunk)
dest.close()
def handle_upload(request):
c = {}
c.update(csrf(request))
if request.method == "POST":
form = UploadFileForm(request.POST)
if form.is_valid():
handle_uploaded_file(request.FILES["ffile"])
return HttpResponseRedirect("/thanks")
else:
form = UploadFileForm()
c.update({"form":form})
return render_to_response("upload.html",c)
And this is the content of upload.html:
<form enctype="multipart/form-data" method="post" action="/handle_upload/">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Upload it"/>
</form>
Whenever I try to submit the form, I get a "This field is required" for the ffile field. What am I doing wrong? Just to mention, I am uploading a file each time.
Just for future reference. I had the same error, though I included request.FILES in form initialization. The problem was in the template: I forgot to add enctype="multipart/form-data" attribute to the <form> tag.
form = UploadFileForm(request.POST, request.FILES)
If you have included request.FILES and added the enctype="multipart/form-data", but are still seeing this error, it could be you are not declaring the <input> correctly.
For example, if explicitly declare the input html in your template like:
<input type="file" value="Upload CSV File" />
You may not be passing the expected input id or name attributes of the input form element.
Be sure that your template is using the form element tag, i.e. {{ form.file }},
which django will then render as: <input id="id_file" name="file" type="file" required=""> on the page.