Can't get past Django MultiValueDictKeyError on specific form id? - python

So, everytime I submit my form, I always get this error
MultiValueDictKeyError at /template/ 'form-21-id'
Here is my views.py:
class SomeTemplate(TemplateView):
template_name = 'template/index.html'
def get_context_data(self, **kwargs):
context = super(AttendanceTemplate, self).get_context_data(**kwargs)
instruction = Instruction(self.request.user.username)
sections_list = self.request.GET.getlist('sections_list')
term = self.request.GET.get('term', instruction.term)
enrollments = Enrollment.objects.using('api').prefetch_related('profile').filter(section_id__in=['111111'], term=term)
attendanceQuery = Enrollment.objects.using('api').prefetch_related('student').filter(section_id__in=['111111'], term=term)
#logger.error(dir(attendanceQuery))
#logger.error(attendanceQuery.values())
for enrollment in attendanceQuery:
#logger.error(enrollment.student.first_name)
attendance, created = Attendance.objects.update_or_create(
section_id=enrollment.section_id,
term=enrollment.term,
first_name=enrollment.student.first_name,
last_name=enrollment.student.last_name,
email_address=enrollment.student.email_address,
meeting_date=timezone.now(),
section_info=3,
)
something = Attendance.objects.filter(section_id__in=['111111'], term=term)
formset = AttendanceFormSet(queryset=something)
combined = zip(enrollments, formset)
context['combined'] = combined
context['formset'] = formset
return context
def post(self, request):
formset = AttendanceFormSet(request.POST)
logger.error(formset.errors)
if formset.is_valid():
formset = formset.save();
return render_to_response("template/index.html", {'formset': formset},context_instance=RequestContext(request))
else:
return HttpResponse(request.POST)
Here is my index.html file:
<form method="POST" action="">
{% csrf_token %}
{{ formset.management_form }}
{% for enrollment, form in combined %}
{{ form.id }}
{% for hidden in combined %}
{{ hidden.hidden_fields }}
{% endfor %}
<div class="wrapper-formset">
<div>
{{ form.first_name.value }}
{{ form.last_name.value }}
{{ form.email_address.value }}
</div>
<div class="clear-all"></div>
</div>
{% endfor %}
<button type="submit" class="save btn btn-default">Save</button>
</form>
I've included the following key form properties in my template as well:
form.id
management form
hidden fields
What am I missing? Doing it wrong? DB issue?

Related

Django Image not uploading

I am unable to have the file in a inlineformset_factory actually upload to the DB or static folder. The form completes then executes succeful_url. Im just not understanding why this isn't uploading the files after submit. Any help is greatly appreciated.
Edit: I am not getting any errors at all.
[12/Mar/2020 15:04:02] "POST /agent/listings/new/ HTTP/1.1" 302 0
[12/Mar/2020 15:04:02] "GET /agent/dashboard/ HTTP/1.1" 200 6915
Model.py
class Listing(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4,editable=False)
agent = models.ForeignKey(CustomUser, on_delete=models.DO_NOTHING)
class Images(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
image = models.ImageField(upload_to="listing/images/")
listing_id = models.ForeignKey(Listing, on_delete=models.DO_NOTHING)
Forms.py
class ListingImage(forms.ModelForm):
class Meta:
model = Images
exclude = ()
ListingImageFormSet = inlineformset_factory(Listing, Images, fields=['image'], form=ListingImage, extra=2)
Views.py
class AgentNewListing(CreateView):
model = Listing
fields = ['agent']
template_name = 'agent/new_listing.html'
success_url = '/agent/dashboard/'
def get_context_data(self, **kwargs):
data = super(AgentNewListing, self).get_context_data(**kwargs)
if self.request.POST:
data['listing_form'] = ListingImageFormSet(self.request.POST)
else:
data['listing_form'] = ListingImageFormSet()
return data
def form_valid(self, form):
context = self.get_context_data()
listingform = context['listing_form']
with transaction.atomic():
form.instance.agent = self.request.user
self.object = form.save(commit=False)
if listingform.is_valid():
listingform.instance = self.object
listingform.save()
return super(AgentNewListing, self).form_valid(form)
def dispatch(self, request, *args, **kwargs):
if not is_valid_agent(self.request.user):
return redirect('/agent/signin/')
return super(AgentNewListing, self).dispatch(request, *args, **kwargs)
Template.htlm
{% extends 'agent/agent_base.html' %}
{% block agent_body %}
{% load crispy_forms_tags %}
<!-- Page Heading -->
<div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h3 mb-0 text-gray-800">New Listing</h1>
</div>
<div class="col-sm-6 col-lg-6 ml-2">
<form action="" method="post" enctype="multipart/form-data">{% csrf_token %}
{{ form|crispy }}
<table class="table">
{{ listing_form.management_form|crispy }}
{% for form in listing_form.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
</tr>
</thead>
{% endif %}
<tr class="">
{% for field in form.visible_fields %}
<td>
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<input class="btn btn-primary" type="submit" value="Submit"/> back to the list
</form>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.formset/1.2.2/jquery.formset.js"></script>
<script type="text/javascript">
$('.formset_row').formset({
addText: 'add family member',
deleteText: 'remove',
prefix: 'familymember_set'
});
</script>
{% endblock %}
Settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Urls.py
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
The problem was I wasn't calling the self.request.FILES in the inlineformeset. The solution is in the view and looks like this.
def get_context_data(self, **kwargs):
data = super(AgentNewListing, self).get_context_data(**kwargs)
if self.request.POST:
data['listing_form'] = ListingImageFormSet(self.request.POST, self.request.FILES)
else:
data['listing_form'] = ListingImageFormSet()
return data

Django update model entry using form fails

I want to update a model entry using a form. the problem is that instead of updating the entry it creates a new entry.
def edit(request, c_id):
instance = get_object_or_404(C, id=int(c_id))
if request.POST:
form = CForm(request.POST, instance=instance)
if form.is_valid():
form.save()
return redirect('/a/b', c_id)
else:
form = CForm(instance=instance)
args = {}
args.update(csrf(request))
args['form'] = form
args['c_id'] = c_id
return render_to_response('a/b.html', args)
HTML code:
<form action="/a/edit/{{ c_id }}/" method="post">
{% csrf_token %}
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
<input type="submit" value="Submit"/>
</form>
CForm class code
class CForm(forms.ModelForm):
class Meta:
model = C
fields = ['name', 'code']
You're checking the request for a POST method incorrectly. request.POST isn't a boolean, it contains a dictionary of post variables and is always going to have the CSRF token in it so it will always be "truthy". What you need is request.method.
Instead of:
if request.POST:
Replace it with:
if request.method == "POST":

UpdateView with Multiple Formset not working

I tried creating a generic UpdateView for a model with generic relations with 2 other models, based on the CreateView provided in this tutorial.
The form and formsets are populated as expected, but when I save I get redirected to the model detail page and changes are not saved.
My question is similar to this one but the suggestions provided are not helpful because they are specific to the former question.
Here is my code :
# models.py
class Ingredient(models.Model):
...
content_type = models.ForeignKey(ContentType, editable=False)
object_id = models.PositiveIntegerField(editable=False)
content_object = GenericForeignKey()
class Step(models.Model):
Same as Ingredient
class Recipe(models.Model):
...
ingredients = generic.GenericRelation(Ingredient)
steps = generic.GenericRelation(Step)
# forms.py
class RecipeForm(forms.ModelForm):
class Meta:
model = Recipe
IngredientFormSet = generic_inlineformset_factory(Ingredient, extra=1)
StepFormSet = generic_inlineformset_factory(Step, extra=1)
# views.py
class RecipeUpdate(UpdateView):
model = Recipe
form_class = RecipeForm
template_name = 'app_recipes/recipe_add.html'
def get(self, request, *args, **kwargs):
self.object = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
ingredient_form = IngredientFormSet(instance = self.object)
step_form = StepFormSet(instance = self.object)
return self.render_to_response(self.get_context_data(
form=form,
ingredient_form=ingredient_form,
step_form=step_form))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
ingredient_form = IngredientFormSet(self.request.POST, instance=self.object)
step_form = StepFormSet(self.request.POST, instance=self.object)
if (form.is_valid() and ingredient_form.is_valid() and step_form.is_valid()):
return self.form_valid(form, ingredient_form, step_form)
else:
return self.form_invalid(form, ingredient_form, step_form)
def form_valid(self, form, ingredient_form, step_form):
self.object = form.save()
ingredient_form.instance = self.object
ingredient_form.save()
step_form.instance = self.object
step_form.save()
return HttpResponseRedirect(self.get_success_url())
def form_invalid(self, form, ingredient_form, step_form):
return self.render_to_response(self.get_context_data(
form=form,
ingredient_form=ingredient_form,
step_form=step_form))
def get_success_url(self):
return reverse('recipe_detail', kwargs={'pk': self.object.pk})
I am using the same template used by CreateView :
...
<script src="{{ STATIC_URL }}js/jquery.formset.js"></script> # django-dynamic-formset
<script type="text/javascript">
$(function() {
$(".inline.{{ ingredient_form.prefix }}").formset({
prefix: "{{ ingredient_form.prefix }}",
})
$(".inline.{{ step_form.prefix }}").formset({
prefix: "{{ step_form.prefix }}",
})
})
</script>
...
<form action="." method="post">
{% csrf_token %}
<div>
{{ form.as_p }}
</div>
<fieldset>
<legend>Recipe Ingredients</legend>
{{ ingredient_form.management_form }}
{{ ingredient_form.non_form_errors }}
{% for form in ingredient_form %}
{{ form.id }}
<div class="inline {{ ingredient_form.prefix }}">
{% for field in form.visible_fields %}
<div>
{{ field.errors }}
{{ field.label_tag }}
{{ field }}
</div>
{% endfor %}
</div>
{% endfor %}
</fieldset>
<fieldset>
<legend>Recipe Steps</legend>
{{ step_form.management_form }}
{{ step_form.non_form_errors }}
{% for form in step_form %}
{{ form.id }}
<div class="inline {{ step_form.prefix }}">
{% for field in form.visible_fields %}
<div>
{{ field.errors }}
{{ field.label_tag }}
{{ field }}
</div>
{% endfor %}
</div>
{% endfor %}
</fieldset>
<input type="submit" value="Add recipe" class="submit" />
</form>
...
NB : I use django-dynamic-formset in the template to dynamically add and remove forms in formsets.
Thank you

Multiple Forms and Formsets in CreateView

I have 2 models, Father and Son.
I have a page to register Father. On the same page I have a formset to register Son.
On page has a button "more" to add another Father and their respective Son on the same page.
Does anyone have any examples using CreateView?
Class based views are still new, so I'll write this out. The process is simple:
First, create the forms for your objects. One of the forms will be repeated. Nothing special to be done here.
class SonInline(ModelForm):
model = Son
class FatherForm(ModelForm):
model = Father
Then, create your formset:
FatherInlineFormSet = inlineformset_factory(Father,
Son,
form=SonInline,
extra=1,
can_delete=False,
can_order=False
)
Now, to integrate it with your CreateView:
class CreateFatherView(CreateView):
template_name = 'father_create.html'
model = Father
form_class = FatherForm # the parent object's form
# On successful form submission
def get_success_url(self):
return reverse('father-created')
# Validate forms
def form_valid(self, form):
ctx = self.get_context_data()
inlines = ctx['inlines']
if inlines.is_valid() and form.is_valid():
self.object = form.save() # saves Father and Children
return redirect(self.get_success_url())
else:
return self.render_to_response(self.get_context_data(form=form))
def form_invalid(self, form):
return self.render_to_response(self.get_context_data(form=form))
# We populate the context with the forms. Here I'm sending
# the inline forms in `inlines`
def get_context_data(self, **kwargs):
ctx = super(CreateFatherView, self).get_context_data(**kwargs)
if self.request.POST:
ctx['form'] = FatherForm(self.request.POST)
ctx['inlines'] = FatherInlineFormSet(self.request.POST)
else:
ctx['form'] = Father()
ctx['inlines'] = FatherInlineFormSet()
return ctx
Finally, here is the template:
The key part is the jquery django-dynamic-formset plugin that keeps adding new inline forms:
<form id="father-form" method="POST" enctype="multipart/form-data" action=".">
{% csrf_token %}
<div class="row">
{% for f in form %}
<div class="span3">{{ f.label }}<br />{{ f }}
{% if f.errors %}
{% for v in f.errors %}
<br /><span style="color:red;">{{ v }}</span>
{% endfor %}
{% endif %}
</div>
{% endfor %}
</div>
<hr />
<h2>Sons:</h2>
<table class="table-striped">
<table>
{% for f2 in inlines %}
<tr id="{{ f2.prefix }}-row">
{% for i in f2 %}
<td>
{{ i }}{% if i.errors %}<span style="color:red;">{{ i.errors }}</span>{% endif %}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
{{ inlines.management_form }}
<input type="submit" class="btn btn-primary" value="Go Go Gadget →">
</form>
<script type="text/javascript">
$(function() {
$('#father-form tr').formset({
prefix: '{{ inlines.prefix }}'
});
})
</script>

Can Dynamic number of formset be used in a single view and passed o a single Template

I have the following view,template and form through which i am implementing the formset. I intend to implement multiple formsets in a single view/template but my number of formsets is dynamic based on user input. How can i have multiple dynamic number of formsets in this code?
Can i do this with dictionary element i.e by creating a dictionary of formsets??
My view is as follows:
def show (request):
b = request.session["s1"] # count of no of period ids
c = request.session["s2"] # account number inserted by user
d = request.session["s3"] # year inserted by customer
a = account_period.objects.filter(year=d).values('id')
e = account_period.objects.filter(year=d).values('month')
f = account_period.objects.filter(id = a).values('year')
butt = formset_factory(bu, extra=b)
if request.method == 'POST'
formset = butt(request.POST)
if formset.is_valid():
z = account_tab.objects.get(account_number=c)
pr = date.today()
i=0
for form in formset.forms:
x = form.cleaned_data['value']
y = account_period.objects.get(id=a[i:(i+1)])
try:
uip = budget.objects.get(account_no = c,account_period = a[i:(i+1)])
if uip.budget_amount != x
uip.budget_amount = x
uip.save()
except budget.DoesNotExist:
w = budget(account_no = z, account_period = y, budget_amount = x, created_by_login = 'me')
w.save()
i=i+1
pass
return HttpResponse('thanks')
form is
class bu(forms.Form):
value = forms.CharField()
template is
<html>
<head>
<title>BUDGET</title>
</head>
<body>
<p>BUDGET MANAGEMENTS</p>
<p>Your Account Number is : {{ account_number }}.</p> <p>You Chose {{ period }} {{month}} as period<p>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="." method="post">{% csrf_token %}
{{ formset.management_form }}
<table>
{% for form in formset.forms %}
{{ form }}
{% endfor %}
</table>
<input type="submit" value="Submit">
</form>
</body>
</html>
#
#rohan
my GET method return has many variables which has to be passed into template so i tried to pass the dictionary formsetlist (after appying the changes u suggested) in following 2ways
1)
formset = butt( return render_to_response('budgetfinalform.html', {'account_number': c,'period':d,'month':e,'year':f,'formset': formset},context_instance=RequestContext(request))
2)
ctx ={'formsetlist': formset}
formset = butt( return render_to_response('budgetfinalform.html', {'account_number': c,'period':d,'month':e,'year':f,ctx,context_instance=RequestContext(request))
but obtained "unboundlocalerror : local variable 'formset' referenced before assignment"
I would do something like:
def show (request):
#initial view processing
# fomset_count taken as parameter or user input
formsetlist = []
#create formset list
for i in range(0, formset_count):
formsetlist.append(formset_factory(bu, extra=b))
# other view related code
# for GET method
ctx = { 'formsetlist': formset }
return render_to_response('your_template_name', ctx,
context_instance = RequestContext(request)
)
In template:
<form action="." method="post">{% csrf_token %}
{% for formset in formsetlist %}
{{ formset.management_form }}
<table>
{% for form in formset.forms %}
{{ form }}
{% endfor %}
</table>
{%endfor%}
<input type="submit" value="Submit">

Categories