I am really new to Django! I have a page that displays items with checkboxes next to them. The number of items/checkboxes varies. When a button is pressed, I want the corresponding checked item to be modified.
So far, I have tried to wrap it all in one form:
<form method="post">
{% csrf_token %}
{% for event in items %}
{{ event.eventID }}
<input type="checkbox" value="{{ event.eventID }}" name="choices">
{% endfor %}
<button type="submit">Approve</button>
</form>
I want to collect them in a Django form field. I am trying to use ModelMultipleChoiceField:
class ApproveEventForm(forms.Form):
choices = forms.ModelMultipleChoiceField(queryset = Event.objects.all(), widget=forms.CheckboxSelectMultiple())
And in my views, I want to edit the selected items:
def approve_event(request):
if request.method == "POST":
form = ApproveEventForm(request.POST)
print(form.errors)
if form.is_valid():
for item in form.cleaned_data['choices']:
item.approved = True
item.save()
else:
form = ApproveEventForm()
unapproved = Event.objects.filter(approved=False)
return render(request, 'app/approve_event.html', {'items': unapproved, 'form': form})
My form is not valid and form.errors prints: choices "" is not a valid value for a primary key.
How can I fix this? Or is there another way to access the selected items?
Edit: passed the form to the template.
Managed to fix it using MultipleChoiceField instead of ModelMultipleChoiceField. Then populated the choices with existing event IDs and passed it to the template.
In forms:
choices = forms.MultipleChoiceField(widget = forms.CheckboxSelectMultiple())
In views:
form.fields['choices'].choices = [(x.eventID, "Event ID: " + x.eventID) for x in unapproved]
Had to change some of the logic for finding and editing Event objects too.
Related
I have created a form for getting the value and placing it in the table. But whenever I click on Submit button, it doesn't store or give any error.It is simply staying in that page itself.
Model.py
class Employee(models.Model):
ename=models.CharField(max_length=120)
eaddress=models.CharField(max_length=120)
eemail=models.CharField(max_length=120)
ephone=models.CharField(max_length=120)
emobile=models.CharField(max_length=120)
eid=models.CharField(max_length=120)
egender=models.CharField(max_length=120)
ehire=models.DateTimeField()
edob=models.DateTimeField()
class Meta:
db_table="employee"
views.py
def employee(request):
emp=Employee.objects.all()
return render(request,'employee.html',{'emp':emp})
def addemployee(request):
if request.method == 'POST':
emp = EmployeeForm(request.POST)
if emp.is_valid():
try:
form.save()
return redirect(employee)
except:
pass
else:
emp = EmployeeForm()
return render(request,'addemployee.html',{'emp':emp})
addemployee.html:
<form method="POST" action="add_employee">
{% csrf_token %}
{{emp.ename}}
{{emp.eemail}}
{{emp.emobile}}
<button type="submit">Submit</button>
</form>
You need to display your form errors in template. So update your view and template like this:
def addemployee(request):
emp = EmployeeForm(request.POST or None)
if request.method == 'POST':
if emp.is_valid():
try:
emp.save()
return redirect(employee)
except Exception as e:
raise e # for debug purpose now
return render(request,'addemployee.html',{'emp':emp})
addemployee.html:
<form method="POST" action="add_employee">
{% csrf_token %}
{{ emp.errors }} // it will render form errors
{{emp.ename}}
{{emp.eemail}}
{{emp.emobile}}
<button type="submit">Submit</button>
</form>
I am assuming your form is not validating because you have many fields like eid, egender etc which are required for saving it in Database. If you are using Modelform, then you can use {{ emp.as_p }} as per form rendering documentation for rendering form instead of {{emp.ename}} {{emp.eemail}} {{emp.emobile}}.
I have the form that looks like this:
class ItemForm(forms.Form):
item = forms.IntegerField()
And this is view for my form:
def testform(request):
item_form = formset_factory(ItemForm, extra=2)
if request.method == 'POST':
item_formset = item_form(request.POST, prefix='items')
if item_formset.is_valid():
for items in item_formset:
cd = items.cleaned_data
item = cd.get('item')
return render(request, 'testform/result.html', {'item_formset':item_formset})
else:
item_formset = item_form(prefix='items')
return render(request, 'testform/index.html', {'item_formset':item_formset})
Here is my result.html:
{% for i in cd %}
{{item}}
{% endfor%}
On result.html page i want to show all values of item formset that input on form page. But I've got just clean page.
What i'm doing wrong. Thanks for your help
You need to iterate over your formset, which you're passing to your render method as 'item_formset'. So your result.html should look like:
{% for item_form in item_formset %}
{{ item_form.item }}
{% endfor %}
Notice you'll be accessing the item field on each formset form, just as you would in a normal form.
You can iterate over each element in form set or display the entire formset at a time. You can find it here: https://docs.djangoproject.com/en/1.7/topics/forms/formsets/#understanding-the-managementform
So I am making an update form and I want to allow the user to update fields he wants to update and leave the rest alone. But django won't let him leave the build_name field alone with no changes because build_name is a primarykey and has to be unique. However it is the object itself that is triggering the fact that the name already exists.
def update(request, id):
title = 'Updating Build'
the_name = champBuild.objects.filter(pk=id).values_list('build_name', flat=True)
form = champBuildUpdateForm(request.POST or None, initial={'build_name': str(the_name)[3:-2]})
if form.is_valid():
champBuild.objects.filter(pk=id).update(build_name=form.cleaned_data.get('build_name'))
return HttpResponseRedirect('/lolBuilds/detail/{}'.format(form.cleaned_data.get('build_name')))
context = {
'title': title,
'form': form
}
return render(request, 'lolBuilds/update.html', context)
and this is the create.html
<form method='POST' action=''>{% csrf_token %}
{{ form.as_p }}
<input type='submit' value='create'/>
</form>
This is what happens when I click update without changing the Build name field.
I am trying to submit a form and it will not pass as is_valid in the view.
The form uses forms.Modelforms which I do not have a lot of experience with.
I checked {{ form.errors }} in the template but didn't get anything back.
I appreciate the time and expertise
Form
class AddSubcategory(forms.ModelForm):
class Meta:
model = Subcategory
fields = ['category']
subcategory_name = forms.CharField(max_length=255)
View
#login_required
#locationed
def add_subcategory(request, location):
subcat_form = AddSubcategory(request.POST)
if subcat_form.is_valid():
submitted_subcat_name = subcat_form.cleaned_data['subcategory_name']
selected_cat = subcat_form.cleaned_data['category']
_, was_created = Subcategory.objects.get_or_create(name=submitted_subcat_name, category=selected_cat)
return HttpResponseRedirect(reverse('manage_cat_subcat', args=(location.slug,)))
else:
cat_form = AddCategory()
subcat_form = AddSubcategory()
return render(request, 'inventory/manage_cat_subcat.html', {'location': location,'cat_form': cat_form,'subcat_form':subcat_form})
Template (form)
<form class="form-inline" action="{% url 'add_subcategory' location.slug %}" method="post">
{% csrf_token %}
{{subcat_form.category}}
{{subcat_form.subcategory_name}}
<button class="btn btn-small" type="submit">Add Subcategory</button>
</form>
You specify in fields that you need id, category and name but you don't put them in your form in your template.
You have only category and subcategory_name.
You can add those two elements in your template OR remove them from the fields list.
Also you don't specify an action for your form, you should give the view where the data from your form should be sent.
I'm looking for a convenient solution to create an 'edit settings' key/values page.
Parameters model :
class Parameter(models.Model):
key = models.CharField(max_length=50)
value = models.CharField(max_length=250)
showInUI = models.SmallIntegerField()
Initial Keys/Values are already inserted in table.
I load them and send them using a model formset factory using these lines :
ParameterFormSet = modelformset_factory(Parameter, extra=0, fields=('key', 'value'))
parameterFormSet = ParameterFormSet(queryset=Parameter.objects.filter(showInUI=1))
return render_to_response('config.html', {'parameterFormSet': parameterFormSet}, context_instance=RequestContext(request))
Template side, when formset is displayed, keys and values are shown as inputs.
I'd like to find a convenient way to display form keys as readonly labels and values as inputs. And, when submited, validate them according django standards.
I've read a lot of stuff, I guess the solution may be a custom widget, but I could find a reliable solution.
Thanks for reading.
EDIT :
Working solution
views.py
def config(request):
ParameterFormSet = modelformset_factory(Parameter, extra=0, fields=('value',))
if request.method == "POST":
try:
formset = ParameterFormSet(request.POST, request.FILES)
except ValidationError:
formset = None
return HttpResponse("ko")
if formset.is_valid():
formset.save()
return HttpResponse("ok")
#ParameterFormSet = modelformset_factory(Parameter, extra=0, fields=('value',))
parameterFormSet = ParameterFormSet(queryset=Parameter.objects.filter(showInUI=1))
return render_to_response('config.html', {'parameterFormSet': parameterFormSet}, context_instance=RequestContext(request))
template
<form method="post">
{% csrf_token %}
{{ parameterFormSet.management_form }}
{% for form in parameterFormSet %}
<div>
{{ form.instance.key }}
{{ form }}
</div>
{% endfor %}
<input type="submit" />
</form>
If you do not want the value to be editable, don't include it in fields when creating the form set.
ParameterFormSet = modelformset_factory(Parameter, extra=0, fields=('value',)) # don't forget the trailing comma after 'value' otherwise it's not a tuple!
In your template, you can then loop through the forms in the form set, and display the key at the same time.
{% for form in parameter_form_set %}
{{ form.instance.key }}{# display the key related to this form #}
{{ form }}{# display the form #}
{% endfor %}