I'm doing a django app with a form using image file upload. I have a default image in case user doesnt choose an image. But when I save the form, my image isn't saved in my files. Any idea ?
Here's my code :
First my views.py
class AnimalCreateView(generic.CreateView):
model = Animal
form_class = AnimalForm
template_name = 'myApp/animal_create.html'
success_url = reverse_lazy('animal:index')
Then my models.py
class Animal(models.Model):
name= models.CharField()
animal_photo= models.ImageField(upload_to="images/",default="images/noPhoto.svg", null=False, blank=True)
def __str__(self):
return f'{self.name}'
And my animal_create html :
{% extends 'base.html' %}
{% load static %}
{% block content %}
<div class="container-fluid">
<div class="row">
<div class="col-lg-8 offset-lg-2">
<h4>My anmials</h4>
<table class="table">
<thead>
<tr>
<th> </th>
<th>Name</th>
<th>Photo</th>
</tr>
</thead>
<tbody>
{% for animal in animal_list%}
<tr>
<td>{{animal.name}}</td>
<p> {{ animal.photo.url }} </p> #check url file
<td class="picture-thumb">
{% if animal.photo.url %}
<img src="{{ animal.photo.url}}"" />
{% else %}
<img src="{% static 'images/noPhoto.svg' %}" />
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock content %}
When I save my file and then check my html or django admin page, all the rows of animal_photo are using the default file...
Where are you using form from context? And also, to upload an images(files) you need to set
{% if form.is_multipart %}
<form enctype="multipart/form-data" method="post" action="/foo/">
{% else %}
<form method="post" action="/foo/">
{% endif %}
https://docs.djangoproject.com/en/3.1/ref/forms/api/#testing-for-multipart-forms
I write a twitter-like app in django,
I've got two models:
class Tweet(models.Model):
content = models.CharField(max_length=140)
creation_date = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Replies(models.Model):
reply = models.CharField(max_length=140)
tweet = models.ForeignKey(Tweet, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.reply
And the fragment of template:
{% block content %}
{% for t in tweets %}
<table class="table1">
<br>
<tr>
<td>
#{{t.user}}
<br> <br>
{{t.content}}
<br> <br>
{{t.creation_date}}
</td>
#######
#######
</tr>
</table>
{% endfor %}
{% endblock %}
Between '####' i would like to have all the replies to the specific tweet, how can i do that?
Thanks in advance
something like this should do the trick:
{% block content %}
{% for t in tweets %}
<table class="table1">
<br>
<tr>
<td>
#{{t.user}}
<br> <br>
{{t.content}}
<br> <br>
{{t.creation_date}}
</td>
{% for reply in t.replies_set.all %}
{{reply.user}} {{reply.reply}}
{% endfor %}
</tr>
</table>
{% endfor %}
{% endblock %}
Here is a link to the documentation that explains many to one relationships in detail https://docs.djangoproject.com/en/3.0/topics/db/examples/many_to_one/
#Steffen - it works, however you need to remove '()' at the end of
for reply in t.replies_set.all()
I have to create a form to make a post with fields like Title, description and images. I could successfully create a post with a single image, but when it comes to multiple images, it is not getting saved. Upon research found that i have to use a separate model and form for images. But i cannot see how is it accomplished in the views. So how do i accomplish this the easy way?
Models.py
class news(models.Model):
title = models.CharField(max_length=100)
description= models.TextField(max_length=500)
class newsimages(models.Model):
image = models.ImageField(upload_to='/images/')
related = models.ForeignKey(news,on_delete=models.CASCADE,null=True)
You can do with inline_formset
create a form
class ImageForm(ModelForm):
class Meta:
model = newsimages
exclude = ()
ImageFormSet = inlineformset_factory(news, newsimage, form=ImageForm, extra=1)
You CreateView would be something like:
class NewsCreate(CreateView):
model = news
fields = ['title', 'description']
success_url = some_url
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['images'] = ImageFormSet(self.request.POST or None)
return ctx
def form_valid(self, form):
ctx = self.get_context_data()
images = context['images']
with transaction.atomic():
self.object = form.save()
if images .is_valid():
images.instance = self.object
images.save()
return super().form_valid(form)
in news_form.html
<form method="post" enctype="multipart/form-data">
{{ form.as_p }}
<table>
{{images.management_form}}
{% for f in images.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
</tr>
</thead>
{% endif %}
<tr class="{% cycle row1,row2 %} formset_row">
{% 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 type="submit" value="Save"/>
</form>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="{% static 'formset/jquery.formset.js' %}"></script>
<script type="text/javascript">
$('.formset_row').formset({
addText: 'add image',
deleteText: 'remove',
prefix: 'images_set'
});
</script>
You will need to source jquery.formset.js which I think you'll find in django admin static files.
When trying to upload an image file to a form on one of my Django webpages, I can select the image by clicking 'Choose File' and selecting the file in the Dialog box that is displayed.
However, when I then click the 'Upload' button, to upload the image to the project via the form, I get an error page which says:
MultiValueDictKeyError at /projects/6215/upload-budget-pdf/
The 'Traceback' on the error page shows that the error is happening in the view:
def upload_budget_pdfs(request, project_id):
project = Project.objects.get(id=project_id)
# budget_formset = BudgetUploadFormset(request.POST, request.FILES)
drawing_formset = DrawingUploadFormset(request.POST, request.FILES, prefix="drawings")
if drawing_formset.is_valid():
print 'Saving drawing_formset'
print "Before", [b.id for b in project.budget_versions.all()]
for drawing_form in drawing_formset:
if drawing_form.instance.budget:
print 'Instance', drawing_form.instance.budget
drawing = drawing_form.save(commit=False)
drawing.budget = drawing_form.instance.budget
drawing.save()
print drawing, [b.id for b in project.budget_versions.all()]
else: print 'Drawing formset not valid.',drawing_formset.errors
budget_formset = BudgetPresentationFormset(request.POST, request.FILES, instance=project, prefix="presentations")
if budget_formset.is_valid() and budget_formset.has_changed():
updated_budget_presentations = budget_formset.save()
elif budget_formset.has_changed(): print 'Budget formset not valid.',budget_formset.errors
return HttpResponseRedirect(reverse('projects:concept', args=[project_id]))
and the particular line it's complaining about is:
if drawing_formset.is_valid():
As I understand, this error is usually caused by a call to request.POST?
I am calling request.POST in the parameter where I define drawing_formset:
drawing_formset = DrawingUploadFormset(request.POST, request.FILES, prefix="drawings")
From what I've seen elsewhere on SO, it seems I should be passing a parameter to request.POST, i.e. that line would become:
drawing_formset = DrawingUploadFormset(request.POST["someParameter"], request.FILES, prefix="drawings")
But I'm not sure exactly what I should be passing to the call to POST as a parameter...? Is this definitely what I need to do to fix the MultiValueDictKeyError? If so, what would I need to be passing as a parameter, or if not, how can I resolve this issue?
Edit
The full error message displayed in the browser when I click the 'Upload' button, having attached an image file to the form, is:
MultiValueDictKeyError at /projects/6215/upload-budget-pdf/
"u'drawings-3-id'"
Request Method: POST
Request URL: http://localhost:8000/projects/6215/upload-budget-pdf/
Django Version: 1.9.1
Exception Type: MultiValueDictKeyError
Exception Value:
"u'drawings-3-id'"
Exception Location: /Users/.../.virtualenvs/.../lib/python2.7/site-packages/django/utils/datastructures.py in getitem, line 85
Python Executable: /Users/.../.virtualenvs/.../bin/python
Python Version: 2.7.6
and the Traceback shows:
/Users/.../Documents/Dev/.../.../projects/views.py in upload_budget_pdfs
if drawing_formset.is_valid(): ...
▼ Local vars
Variable Value
project
<Project: Test 1>
drawing_formset
<django.forms.formsets.DrawingFormFormSet object at 0x113223cd0>
project_id
u'6215'
request
<WSGIRequest: POST '/projects/6215/upload-budget-pdf/'>
The output displayed in the console when I click the 'Upload' button, and am taken to the webpage displaying the error is:
Internal Server Error: /projects/6215/upload-budget-pdf/
Traceback (most recent call last):
File "/.../.../.virtualenvs/.../lib/python2.7/site-packages/django/core/handlers/base.py", line 140, in get_response
response = middleware_method(request, callback, callback_args, callback_kwargs)
File "/.../.../Documents/Dev/.../.../.../middleware.py", line 72, in process_view
return permission_required(required_permission)(view_func)(request,*view_args,**view_kwargs)
File "/.../.../.virtualenvs/.../lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 23, in _wrapped_view
return view_func(request, *args, **kwargs)
File "/.../.../Documents/Dev/.../.../projects/views.py", line 1003, in upload_budget_pdfs
if drawing_formset.is_valid():
File "/.../.../.virtualenvs/.../lib/python2.7/site-packages/django/forms/formsets.py", line 316, in is_valid
self.errors
File "/.../.../.virtualenvs/.../lib/python2.7/site-packages/django/forms/formsets.py", line 290, in errors
self.full_clean()
File "/.../.../.virtualenvs/.../lib/python2.7/site-packages/django/forms/formsets.py", line 338, in full_clean
form = self.forms[i]
File "/.../.../.virtualenvs/.../lib/python2.7/site-packages/django/utils/functional.py", line 33, in get
res = instance.dict[self.name] = self.func(instance)
File "/.../.../.virtualenvs/.../lib/python2.7/site-packages/django/forms/formsets.py", line 144, in forms
for i in range(self.total_form_count())]
File "/.../.../.virtualenvs/.../lib/python2.7/site-packages/django/forms/models.py", line 587, in _construct_form
pk = self.data[pk_key]
File "/.../.../.virtualenvs/.../lib/python2.7/site-packages/django/utils/datastructures.py", line 85, in getitem
raise MultiValueDictKeyError(repr(key))
MultiValueDictKeyError: "u'drawings-3-id'"
Edit
The original view that's displaying the page on which I click the 'Upload' button to try to upload an image to the form is:
def concept(request, project_id):
project = Project.objects.prefetch_related('budget_versions').get(id=project_id)
deposit = Deposit.objects.get_or_create(project=project)[0]
presentations = project.budget_versions.select_related('meeting').prefetch_related('budget_items', 'cci_items', 'presenters').filter(version_number__isnull=False).annotate(vn=F('version_number') * -1).order_by('presentation_date', 'created', '-vn')
end_details = EndDetails.objects.get_or_create(project=project)[0]
presentation_formset = BudgetPresentationFormset(prefix="presentations", instance=project, queryset=presentations)
drawing_formset = DrawingUploadFormset(prefix="drawings", queryset=Drawing.objects.filter(budget__in=presentations).order_by('budget__presentation_date', 'budget__created'))
context = {
'project': project,
'presentations': presentations,
'presentation_formset': presentation_formset,
'drawing_formset': drawing_formset,
'deposit_form': DepositInfoForm(instance=deposit),
'ended_form': EndDetailsForm(instance=end_details),
'budget_notes_form': BudgetNotesForm(instance=project.budget_overview),
}
return render(request, 'projects/concept.html', context)
and the part of the template that's displaying the relevant parts of the page (i.e. the form, buttons, etc) is:
{% block content %}
<form method="POST" enctype="multipart/form-data" data-vat-status="{{project.vat_status}}" data-view-url="{% url 'projects:concept_save_ajax_2' project.id %}" class="autosave_form formset full-width" action="{% url 'projects:upload_budget_pdfs' project.id %}">
{% csrf_token %}
<div id="presentations" class="app-wrap center-apps middle">
{% with get|apps:'Budgets' as costing_app %}
{% for presentation in presentations %}
<div id="presentation-{{presentation.id}}" class="app sm {% if presentation.current_marker %}{{costing_app.color}}{% else %}{{app.color}}{% endif %}">
<a class="show-presentation bottom-right" name="presentation-{{presentation.id}}"><img class="icon" src="{% static 'img/edit-white.png' %}"></a>
<ul class="flush">
<li class=""><h2 class="p-t-lg">Presentation {{forloop.counter}}</h2></li>
<li>{{presentation.presentation_date|date:"d M y"|xor}}</li>
<li>{{presentation.details|xor|truncatechars:50}}</li>
{% if presentation.current_marker %}<li>({% if project.deposit_received%}Deposit{% else %}Current{% endif %} budget)</li>{% endif %}
</ul>
</div>
{% if forloop.last %}
{% endif %}
{% endfor %}
{# Add a new presentation #}
<div id="presentation-new" class="app sm {{costing_app.color}} outline">
<a id="new_presentation" data-view-url="{% url 'projects:save_new_presentation' project.id %}" class="filler show-presentation" name="presentation-new"></a>
<a name="presentation-new"></a>
<span class="big-head">+</span>
<h2 class="no-m">Add presentation</h2></li>
</div>
{% endwith %}
</div>
<div class="middle">
{{presentation_formset.management_form}}
{{drawing_formset.management_form}}
<div class="col-9 centered-block p-t-lg">
<table class="left fixed text-sm slim">
{# New presentation without budget #}
<tbody>
</tbody>
{# Edit presentation details #}
{% for presentation_form in presentation_formset %}
<tbody id="pres{{forloop.counter}}" class="presentation-form" name="presentation-{{presentation_form.instance.id|xor:'new'}}" style="display: none;">
{% if not forloop.last and presentation_form.instance.budget_items.count %}
<tr class="split-rows">
<td colspan="3">Exc VAT {% if not presentation_form.instance.current_marker %}{{presentation_form.instance.grand_total_exc_vat|money:'£'}}{% else %}{{project.budget_overview.updated_exc_vat|money:'£'}}{% endif %}</td>
<td colspan="3">Inc VAT {% if not presentation_form.instance.current_marker %}{{presentation_form.instance.grand_total_inc_vat|money:'£'}}{% else %}{{project.budget_overview.updated_inc_vat|money:'£'}}{% endif %}</td>
</tr>
{% endif %}
<tr>
{% for hidden in presentation_form.hidden_fields %}
<td class="hidden">{{ hidden }}</td>
{% endfor %}
</tr>
{% for field in presentation_form.visible_fields %}
<tr class="split-rows">
{% if not field.name == 'pdf_package_dep' %}
<td colspan="6"><label>{{field.label}}</label></td>
{% endif %}
</tr>
<tr class="split-rows">
<td colspan="6">
{% if not field.name == 'pdf_package_dep' %}
{% if field.name == 'presentation_date' %}
{% with presentation_form.instance.meeting as meeting %}
{% include "projects/includes/meeting_bit.html" with employee=request.user.employee meeting=meeting UID=presentation_form.instance.id %}
{% endwith %}
{# <a class="ical_trigger button" data-view-url="{% url 'events:add_to_cal' %}" {% if not field.value %}style="display:none"{% endif %}>Add to calendar</a> #}
{% else %}
{{field}}
{% endif %}
{% endif %}
</td>
</tr>
{% endfor %}
{% if presentation_form.instance.id %}
{# PDF uploads #}
{% with drawing_form=drawing_formset|getval:forloop.counter0 %}
{# budget_pdf_form=budget_pdf_formset|getval:forloop.counter0 #}
<tr>
{% if not forloop.last %}
<td colspan="3"><label>Budget PDF package</label></td>
{% endif %}
<td colspan="3"><label>Drawings</label></td>
</tr>
<tr>
{% if not forloop.last %}
<td colspan="3" class="center">
{% if presentation_form.instance.pdf_package_dep %}
<a class="button file-download pdf" href="{% url 'costing:pdf_open' presentation_form.instance.id %}?pdf=package_dep" target="_blank"></a><a class="pdf-clear" data-view-url="{% url 'costing:pdf_clear' presentation_form.instance.id %}?pdf=package_dep"><img class="icon m-l-sm m-b-md" src="{% static "img/bin.png" %}"></a>
{% else %}
{{presentation_form.pdf_package_dep}}
{% endif %}
</td>
{% endif %}
{% for d_field in drawing_form.visible_fields %}
{% if drawing_form.instance.pdf %}
<td colspan="3" class="center">
<a class="button file-download pdf" href="{% url 'costing:pdf_open' presentation_form.instance.id %}?pdf=drawings" target="_blank"></a><a class="pdf-clear" data-view-url="{% url 'costing:pdf_clear' presentation_form.instance.id %}?pdf=drawings"><img class="icon m-l-sm m-b-md" src="{% static "img/bin.png" %}"></a>
</td>
{% else %}
<td colspan="3">{{d_field}}</td>
{% for d_hidden in drawing_form.hidden_fields %}
<td class="hidden">{{d_hidden}}</td>
{% endfor %}
{% endif %}
{% endfor %}
<tr>
<td colspan="1" class="p-t-md"></td>
<td colspan="4" class="p-t-md"><input type="submit" value="upload"></td>
<td colspan="1" class="p-t-md"></td>
</tr>
</tr>
{% endwith %}
{% endif %}
<tr>
<td colspan="3">
<a class="button email_trigger m-t-md" style="width:auto;" data-view-url="{% url 'comms:open_email_template' project.id %}?template=6&budget={{presentation_form.instance.id}}">Email client meeting report</a>
</td>
</tr>
<tr>
<td class="p-t-md">
<a {% if forloop.last %}id="refresh_presentations"{% endif %}class="update_presentation button fill">Done</a>
</td>
<td colspan="2">
{% if presentation_form.instance.id and not presentation_form.instance.budget_items.count %}
<a class="button fill" href="{% url 'costing:delete_presentation' presentation_form.instance.id %}">Delete</a>
{% endif %}
</td>
</tr>
</tbody>
{% endfor %}
</table>
</div>
</div>
</form>
<form method="POST" enctype="multipart/form-data" data-vat-status="{{project.vat_status}}" data-view-url="{% url 'projects:concept_save_ajax' project.id %}" class="autosave_form full-width">
{% csrf_token %}
<div class="col-12 box">
<div>
<table class="right fixed m-t-md">
<tr>
{% for hidden in deposit_form.hidden_fields %}
{{hidden}}
{% endfor %}
{% for field in deposit_form.visible_fields %}
<td class="p-r-md">{{field.label}}</td><td class="p-r-md">{{field}}</td>
{% endfor %}
<td><a class="email_trigger button" data-view-url="{% url 'comms:open_email_template' project.id %}?template=7">Raise invoice</a></td>
</tr>
</table>
</div>
</div>
<div class="col-6 box">
<div>
<div class="expand-header"><strong class="m-t-md">Costing notes</strong></div>
<table class="vertical-table left">
{% include "projects/includes/stacked_form.html" with form=budget_notes_form %}
</table>
</div>
</div>
<div class="col-6 box">
<div>
<div class="expand-header"><strong class="m-t-md">Project rejected by client?</strong></div>
<table class="vertical-form left">
{% include "projects/includes/stacked_form.html" with form=ended_form %}
</table>
</div>
</div>
</form>
{% endblock content %}
and DrawingUploadFormset is defined in forms.py with:
class DrawingUploadForm(ValidatedForm):
class Meta(object):
model = Drawing
fields = ['pdf',]
DrawingUploadFormset = modelformset_factory(Drawing, form=DrawingUploadForm, max_num=12, extra=1, can_delete=False)
In models.py,I created a character type field called "category".After the user enters the category name,it is saved in the database and now I want to display all the category names stored in the database.I created four category names.I can see all four in the database but when displaying it in the UI, I see NONE instead of the category names.
views.py,
def add_cat(request):
form = CatForm(request.POST or None)
context = {"form":form}
if form.is_valid():
instance = form.save(commit=False)
category = form.cleaned_data.get("category")
instance.category = category
instance.save()
messages.add_message(request, messages.INFO, 'Category Added')
return render(request,"add-cat.html",context)
forms.py,
class CatForm(forms.ModelForm):
class Meta:
model = Add_cat
fields = ['category']
My template file,
{% extends "admin-menu.html" %}
{% block content %}
{% load staticfiles %}
<head>
<link rel="stylesheet" href="{% static 'style.css' %}">
</head>
<h2 style="text-align: center;">Add Category</h2>
<form method="POST">
{% csrf_token %}
<table align="center">
{{form.as_table}}
</table>
<input type="submit" value="Add" style="margin-left: 48%;"/>
<input type="reset" value="Cancel"/>
</form>
{% if messages %}
<ul class="messages" style="list-style-type: none;">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
 
<form id="id1">
{% for field in form %}
<table align="center">
<tr><th>Category Name</th></tr>
<tr><td>{{field.value}}</td></tr>
</table>
{% endfor %}
</form>
{% endblock %}
Try like this
def add_cat(request):
form = CatForm(request.POST or None)
catagories = <model>.objects.all()
context = {"form":form, 'categories':categories}
if form.is_valid():
instance = form.save(commit=False)
category = form.cleaned_data.get("category")
instance.category = category
instance.save()
messages.add_message(request, messages.INFO, 'Category Added')
return render(request,"add-cat.html",context)
In templates
{% for category in categories %}
<table align="center">
<tr><th>Category Name</th></tr>
<tr><td>{{ category }}</td></tr>
</table>
{% endfor %}