I'm a Django beginner, how do I get the ID of each image uploaded with form?
class Image(models.Model):
imageuploader_profile=models.ForeignKey(settings.AUTH_USER_MODEL)
upload_image=models.ImageField()
def upload(request):
if request.method == 'POST':
form=UploadForm(request.POST, request.FILES)
if form.is_valid():
post=form.save(commit=False)
post.imageuploader_profile=request.user
post.save()
return redirect....
else:
form=UploadForm
return render......
view.py
def home(request) :
all_images=Image objects.filter(imageuploader_profile=request.user)
context={'all_images':all_images}
return render(request, 'home.html', context)
My home.html
{% for post in all_images %}
{% if post upload_images %}
<img src="{{ post upload_image.url }}">
{% endif %}
{% endfor%}
I want to get all IDs in my template.
You can write a new method/view to get all IDs:
def get_images_ids():
images_ids = Image.objects.values_list('id)
print(images_ids)
return images_ids
Here the explanation for values_list (you also can use values() if you need more, or the attribute flat=True).
If you call get_images_ids() you get all IDs of all images in a queryset (or in a list with flat=True). If you need to filter them use .filter().
In your views.py
def home(request) :
all_images=Image objects.filter(imageuploader_profile=request.user)
context={'all_images':all_images, all_images_ids: get_images_ids()}
return render(request, 'home.html', context)
In your template do this:
{% for post in all_images %}
{% if post upload_images %}
<img src="{{ post.upload_image.url }}">
<span>{{ post.id }}</span>
{% endif %}
{% endfor%}
or
<ul>
{% for id in all_images_ids %}
<li>{{ id }}</li>
{% endfor%}
</ul>
You can't get id of the image unless you first create an object in database, in other words you will have to execute post.save() first and then you can run post.id to get id. Here is an example with your code.
class Image(models.Model):
imageuploader_profile=models.ForeignKey(settings.AUTH_USER_MODEL)
upload_image=models.ImageField()
def upload(request):
if request.method == 'POST':
form=UploadForm(request.POST, request.FILES)
if form.is_valid():
post=form.save(commit=False)
post.imageuploader_profile=request.user
post.save()
print(post.id) # This will print id of submitted post in your console
return redirect....
else:
form=UploadForm
Note: ID of post is automatically created in the database after you run post.save()
You can get the ID of the image after post.save() executes.
So before the return statement you can access post.id or post.pk to get the image ID.
UPDATE:
class Image(models.Model):
imageuploader_profile=models.ForeignKey(settings.AUTH_USER_MODEL)
upload_image=models.ImageField()
def upload(request):
if request.method == 'POST':
form=UploadForm(request.POST, request.FILES)
if form.is_valid():
post=form.save(commit=False)
post.imageuploader_profile=request.user
post.save()
# here you can access post.id or post.pk
return redirect....
else:
form=UploadForm
If you want to get all uploaded images id then use Image.objects.values_list('id)
Related
When filling out a form I get "This field is required." even though all fields are filled in.
It doesn't have to do with setting required to False or anything like that, because all fields are required.
views.py
def upload(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
title = form.cleaned_data['title']
username = request.user.get_username()
category = form.cleaned_data['category']
handle_uploaded_file(request.FILES['file'],title,username,category)
return HttpResponseRedirect('')
else:
form = UploadFileForm()
return render(request, 'main/upload.html', {'form': form})
function
def handle_uploaded_file(f,title,username,category):
with open('/uploads/' + category + '/' + title, 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
forms.py
class UploadFileForm(forms.Form):
title = forms.CharField(max_length=50)
category = forms.CharField(max_length=50)
file = forms.FileField()
upload.html
{% extends 'base.html' %}
{% block title %}Upload{% endblock %}
{% block content %}
{% if user.is_authenticated %}
Uploading as: {{ user.username }}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit"/>
</form>
{% else %}
<p>You are not logged in</p>
login
{% endif %}
{% endblock %}
The error I get when filling out a form is: "This field is required"
Screenshot:
When I select a file and it throws the error it unselects whatever file I've selected, similar to how the password field is cleared when hitting sign up without completing every field.
The file isn't being submitted with the request because you didn't sent the correct enctype on the form element. Here are Django's docs concerning that.
<form method="post" enctype="multipart/form-data">
One way to verify this/debug it would be to print the form's data form.data, request.POST and/or request.FILES before the call to is_valid. Or verifying the request in a browser's dev tools.
So I'm working on a Django project and this is my views.py file:
def new_topic(request, pk):
board = get_object_or_404(Board, pk=pk)
user = User.objects.first() # TODO: get the currently logged in user
if request.method == 'POST':
form = NewTopicForm(request.POST)
if form.is_valid():
topic = form.save()
return redirect('board_topics', pk=board.pk)
else:
form = NewTopicForm()
return render(request, 'new_topic.html', {'form': form})
When I ran my server, I got an error saying:
UnboundLocalError: local variable 'form' referenced before assignment
This is my new_topic.html file
{% extends 'base.html' %}
{% block title %}Start a New Topic{% endblock %}
{% block breadcrumb %}
<li class="breadcrumb-item">Boards</li>
<li class="breadcrumb-item">{{ board.name }}</li>
<li class="breadcrumb-item active">New topic</li>
{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-success">Post</button>
</form>
{% endblock %}
The line if form.is_valid(): fails on a GET request, because you're only defining form when request.method == 'POST'.
This can be fixed by changing some indentation:
if request.method == 'POST':
form = NewTopicForm(request.POST)
if form.is_valid():
topic = form.save()
return redirect('board_topics', pk=board.pk)
else:
form = NewTopicForm()
return render(request, 'new_topic.html', {'form': form})
I don't find any issue with indentation, but with initialization. Kindly initialize for before rendering it! Make changes as shown below will definitely work out and it's a very genuine and proper way to get rid of it:
def new_topic(request, pk):
board = get_object_or_404(Board, pk=pk)
user = User.objects.first() # TODO: get the currently logged in user
form = NewTopicForm()
if request.method == 'POST':
form = NewTopicForm(request.POST)
if form.is_valid():
topic = form.save()
return redirect('board_topics', pk=board.pk)
else:
form = NewTopicForm()
return render(request, 'new_topic.html', {'form': form})
I need form where user can create article with several images. I use django-multiupload app for image field. I can select several images but when I try to submit the form I have message under the image field: "Field is empty and field is required". Where is my mistake? Why I have such message when image field is not empty?
Also maybe someone can advice good examples or apps to save several images. I would be very grateful for any help.
models.py:
class Article(models.Model):
description = models.TextField(_('Description'))
class Image(models.Model):
article= models.ForeignKey(Article, on_delete=models.CASCADE)
image = models.FileField(_('Image'), upload_to='images/%Y/%m/%d/')
forms.py:
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ('description', )
image = MultiFileField()
def save(self, commit=True):
instance = super(ArticleForm, self).save(commit)
for each in self.cleaned_data['image']:
Image.objects.create(image=each, article=instance)
return instance
views.py:
def article_add(request):
data = dict()
if request.method == 'POST':
article_form = ArticleForm(request.POST, request.FILES)
if article_form.is_valid():
article = article_form.save(commit=False)
******
article.save()
data['form_is_valid'] = True
articles = Article.objects.all
context = {'articles': articles}
context.update(csrf(request))
data['html_article'] = render_to_string('project/article_list.html', context)
else:
data['form_is_valid'] = False
else:
article_form = ArticleForm()
context = {'article_form': article_form}
data['html_article_form'] = render_to_string('project/article_add.html', context, request=request)
return JsonResponse(data)
article_add.html:
{% load widget_tweaks %}
<form method="post" action="{% url 'article_add' %}" class="article-add-form">
{% csrf_token %}
{% for field in article_form %}
<div class="form-group{% if field.errors %} has-danger{% endif %}">
<label class="form-control-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
{% render_field field class="form-control" %}
{% for error in field.errors %}
<div class="form-control-feedback">{{ error }}</div>
{% endfor %}
</div>
{% endfor %}
<button type="submit">Submit</button>
</form>
Try adding "min_num" constraint on the image field,
image = MultiMediaField(min_num=1, media_type='image')
EDIT
def article_add(request):
if request.method == 'POST':
article_form = ArticleForm(request.POST, request.FILES)
if article_form.is_valid():
article = article_form.save(commit=False)
******
article.save()
#assume you have already a view in the name 'article_list'.
return redirect('article_list')
else:
article_form = ArticleForm()
context = dict(article_form=article_form)
return render(request, 'project/article_add.html', context)
The problem maybe because you were trying to render two templates in a single view, also when using django template rendering render is a shortcut function, which is mostly preferred to use, rather than string converting and parsing into json.
Also, 'article_list' must be another view, which shows the list of all the articles, after adding a new article, you should consider redirecting to the list view. Here you were trying to render multiple templates, in a single view. You could make of something like this in your list view,
def article_list(request):
articles = Article.objects.all()
context = dict(articles=articles)
return render(request, 'project/article_list.html', context)
Although, these are my personal opinion regarding the code you just shared. Try this approach...
I want to edit two forms in Django. A form for 'Motel' and its 'Images'. In my app, users can upload multiple images to the 'Motel' model. And now, editing the images with 'get()' function is giving me,
MultipleObjectsReturned get() returned more than one MotelImages -- it returned 4!
Models
class Motel(models.Model):
user= models.ForeignKey(User)
title= models.CharField(max_length=120)
body= models.TextField()
#other fields
class MotelImages(models.Model):
motel= models.ForeignKey(Motel, default=None, related_name='images')
image= models.ImageField(upload_to='company', verbose_name= 'Image')
class MotelImagesForm(forms.ModelForm):
image= forms.ImageField(label='Image',)
def __init__(self, *args, **kwargs):
super(MotelImagesForm,self).__init__(*args, **kwargs)
self.fields['image'].widget= forms.FileInput(attrs={'name':'image',
'multiple':'multiple'})
Views for saving the form
def create_motel(request):
if request.method=="POST":
motelForm= MotelForm(request.POST, request.FILES)
formset=MotelImagesForm(request.POST, request.FILES)
if motelForm.is_valid() and formset.is_valid():
human= True
motel_form= motelForm.save(commit=False)
motel_form.user= request.user
motel_form.pub_date= datetime.datetime.now()
motel_form.save()
for image in request.FILES.getlist('image',[]):
photo= MotelImages(motel=motel_form, image=image)
photo.save()
messages.success(request,
"Welldone Boy")
return HttpResponseRedirect('/view_all/')
else:
print motelForm.errors, formset.errors
else:
motelForm=MotelForm()
formset= MotelImagesForm()
return render(request, 'motels/add_motel.html',{'motelForm': motelForm, 'formset':formset})
Views for editing the form
#login_required
def edit_motel(request,motel_id=None,slug=None,template_name='motel_edit.html'):
if id:
post=get_object_or_404(Motel,id=motel_id,slug=slug)
images=MotelImages.objects.get(motel=motel_id)
else:
post=Motel(user=request.user)
images=MotelImages(user=request.user)
if request.POST:
motelform=MotelForm(request.POST,request.FILES, instance=post)
formset=MotelImagesForm(request.POST,request.FILES, instance=images)
if form.is_valid() and formset.is_valid():
form.save()
formset.save()
redirect_url=reverse('moteldetail',kwargs={'motel_id':motel_id,'slug':slug})
return render(request, 'motels/updatenotice.html')
else:
form=MotelForm(instance=post)
formset= MotelImagesForm(instance=images)
return render(request, template_name,{'formset':formset,'motelform':motelform})
Template for editing the form
<form id="post_form" method="post" action=""
enctype="multipart/form-data">
{% csrf_token %}
{% for hidden in motelform.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in motelform %}
{{ field.name }}
{{ field }} <br />
{% endfor %}
{{ formset.management_form }}
{% for form in formset %}
{{ form }}
{% endfor %}
<input type="submit" name="submit" value="Submit" />
</form>
What am I missing?
images = MotelImages.objects.get(motel=motel_id)
Since get can return only one object, you want to use filter:
images = MotelImages.objects.filter(motel__pk=motel_id)
images will be a list of the relevant images.
I use a simple form to edit the name of a invoice (invoice_text). When I submit the changes it redirects back to index page. The problem is that the index page is showing the old records. This is only in Firefox. Internet Explorer shows the changes directly. F5 helps, but of course it needs to show the new (edited) information.
forms.py
class InvoiceForm(ModelForm):
class Meta:
model = Invoice
fields = ('Invoice_text',)
views.py
def index(request):
latest_invoice_list = Invoice.objects.order_by('-pub_date')[:5]
context = {'latest_invoice_list': latest_invoice_list}
return render(request, 'invoices/index.html', context)
def invoice_edit(request, pk):
obj = get_object_or_404(Invoice, pk=pk)
if request.method == "POST":
form = InvoiceForm(request.POST, instance=obj)
if form.is_valid():
obj = form.save(commit=False)
obj.Invoice_text = request.POST['Invoice_text']
obj.save()
return HttpResponseRedirect('/invoices/')
else:
form = InvoiceForm(instance=obj)
return render(request, 'polls/edit_Invoice.html', {'form': form})
Index.html template
{% if latest_invoice_list %}
<ul>
{% for invoice in latest_invoice_list %}
<li>{{ invoice.invoice_text }} | edit</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
This is strange, but you should be able to use the #never_cache decorator to prevent it:
from django.views.decorators.cache import never_cache
#never_cache
def index(request):
....