How to Upload an Image to Django - django

I have spent over three days on this. It appears that something saved to the db, but when I try to access it in the template, I can only get the object of the db. I can not access it. I believe it was not saved successfully because I don't see a media folder where it would be saved. This is what I have so far.
# settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'), )
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# forms.py
from .models import Pic
from django import forms
class ImageForm(forms.ModelForm):
class Meta:
model= Pic
fields= ["picture"]
# models.py
class Pic(models.Model):
picture = models.ImageField(upload_to = 'media/', default = 'media/None/no-img.jpg', null=True, blank= True)
# views.py
def upload(request):
form = ImageForm
context = {}
userBio = Bio.objects.get(userData = User.objects.get(id = request.session['client']['id']))
if request.method == 'POST':
# .is_valid checks the models parameters via forms method
form = ImageForm(request.POST,request.FILES)
if form.is_valid():
form.save()
print("succesful uploaded image")
return redirect("/dashboard")
else:
print("Not a valid input from form....")
messages.error(request,"Not a valid input")
return redirect("/dashboard")
<!-- dashboard.html -->
<form rule="form" class="border border--secondary" method="POST" action="/manageFile" enctype="multipart/form-data">
{% csrf_token%}
<input type="file" name = "update">
<input type = "submit">
</form>
{% if pictures %}
{% for pic in pictures%}
<img src="{{pic}}" alt="{{pic}}">
{% endfor %}
{% endif%}
In the template, it appears as Pic object(1).
In the terminal, it appears as
Query set Pic: Pic object (1)
Here's what I render to the template.
def dash(request):
try:
_id = request.session['client']['id']
except:
return redirect("/loginPg")
userBio = Bio.objects.get(userData = User.objects.get(id = request.session['client']['id']))
print("its right here")
theUploads = Pic.objects.all()
print("This image object -", theUploads)
content = {
"title" : userBio.title,
"qA" : userBio.quoteA,
"qB" : userBio.quoteB,
"desc" : userBio.desc,
"authorA" : userBio.authorA,
"authorB" : userBio.authorB,
"pictures" : theUploads
}
return render(request, "GoEnigma/dashboard.html", content)
# urls.py
from django.conf.urls.static import static
from django.conf import settings
# urls []
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

This was hard to spot, because you render the form field yourself:
class ImageForm(forms.ModelForm):
class Meta:
model= Pic
fields= ["picture"]
<input type="file" name = "update">
So the name of the file field is update, not picture. Change that to picture and it should work, though it's much better to use django to render the form, so you don't mistakes like this and changes to the form get propagated to the html.

If the picture is being saved in the database than the error is with rendering the template. To render the images in template you need to get the {{model_class.model_fields.url}} so in your case the class is pic, the field is picture.
try this in your template <img src="{{pic.picture.url}}">

put parentheses after ImageForm and add request.POST in ImageForm if it is Post request.
def upload:
form = ImageForm()
if request.method == 'POST':
# .is_valid checks the models parameters via forms method
form = ImageForm(request.POST, request.FILES)
if form.is_valid():
form.save()
print("succesful uploaded image")
return redirect("/dashboard")
else:
print("Not a valid input from form....")
messages.error(request,"Not a valid input")
return redirect("/dashboard")
Also check maybe you haven't added url path for serving media files
so add these following lines in urls.py file of main project.
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# ..... all regular paths
]
if setting.DEBUG: # if true
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Check official documents here

Related

How to pass multiple kwargs parameter to Django Class Based View (ListView) at HTML page?

Views.py
class CalendarWeekView(LoginRequiredMixin, generic.ListView):
login_url = 'signup'
model = Event
template_name = 'calendar.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
d = get_date(self.request.GET.get('month', None))
w = int(self.request.GET.get('week', None))
cal = Calendar(d.year, d.month, w)
html_cal = cal.formatmonth(withyear=True)
context['calendar'] = mark_safe(html_cal)
context['prev_month'] = prev_month(d)
context['next_month'] = next_month(d)
context['current_month'] = current_month(d)
context['next_week'] = next_week(w)
return context
urls.py
app_name = 'calendarapp'
urlpatterns = [
path('week/', views.CalendarWeekView.as_view(), name='calendarWeek'),
]
calendar.html
href="{% url 'calendarapp:calendarWeek' %}?{{ next_week}}/?{{ current_month }}"
How to pass multiple kwargs parameter to Django Class Based View (ListView) at HTML page using URL Path at HTML page ?
The parameters in a Query string [wiki] are separated by an &, so you can call this with:
href="{% url 'calendarapp:calendarWeek' %}?week={{ next_week}}&month={{ current_month }}"
That being said, for a fixed number of parameters, it is often better to work with path parameters [Django-doc], this is more convenient to use in the {% url … %} template tag [Django-doc], and results in cleaner and more elegant URLs.

How to download uploaded files through a link in Django

I am uploading a file and saving it on a folder outside the media folder. I want to add a download link in a template to be able to download the file directly. I am not sure what to add in the URL, if I should add something
I tried this in the template it says URL not found
Download File
views.py
def uploaddata(request):
if request.user.is_authenticated:
if request.method == 'POST':
form = uploadform(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('file_list')
else:
form = uploadmetaform()
return render(request, 'uploaddata.html', {
'form': form
})
else:
return render(request, 'home.html')
HTML page
<tbody>
{% for data in dataset %}
<tr>
<td>{{data.path_id}}</td>
<td>{{ data.tar_gif }}</td>
<td>
Download File
</td>
</tr>
{% endfor %}
</tbody>
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
Assigned_Group= models.CharField(max_length=500, choices=Group_choices, default='Please Select')
def __str__(self):
return self.user.username
upload file
def nice_user_folder_upload(instance, filename):
extension = filename.split(".")[-1]
return (
f"{instance.user_profile.Assigned_Group}/{filename}"
)
class uploadmeta(models.Model):
path = models.ForeignKey(Metadataform, on_delete=models.CASCADE)
user_profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, null=True, verbose_name='Username')
document = models.FileField(upload_to=nice_user_folder_upload, verbose_name="Dataset") # validators=[FileExtensionValidator(allowed_extensions=['tar', 'zip'])]
def __str__(self):
return self.request.user
Actually simple way of doing it by using html download attribute
the way you achieve this is by
<a href="{{data.document.url}}" download> Download File</a>
or you also use :
Download File
1.settings.py:
MEDIA_DIR = os.path.join(BASE_DIR,'media')
#Media
MEDIA_ROOT = MEDIA_DIR
MEDIA_URL = '/media/'
2.urls.py:
from django.conf.urls.static import static
urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
3.in template:
<a href="{{ file.url }}" download>Download File.</a>
Work and test in django >=3
for more detail use this link:
https://youtu.be/MpDZ34mEJ5Y
Look at this post:
How to serve downloadable files using Django (Chris Gregori) ?
Maybe a better way to not expose the path of the files, even the names if you do want to do that. I do not like the idea to show the structure of the paths to users. Other things you can accomplish with this is to validate who can download the files if you check the request.user with your database for every file is served, and it is pretty simple.
Basically, the publication refers to using the xsendfile module so django generates the path to the file (or the file itself), but the actual file serving is handled by Apache/Lighttpd. Once you've set up mod_xsendfile, integrating with your view takes a few lines of code:"
from django.utils.encoding import smart_str
response = HttpResponse(mimetype='application/force-download') # mimetype is replaced by content_type for django 1.7
response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file_name)
response['X-Sendfile'] = smart_str(path_to_file)
# It's usually a good idea to set the 'Content-Length' header too.
# You can also set any other required headers: Cache-Control, etc.
return response
As I said before, I do not like the idea of having published the path to the file.
With this pointer to the information, you can research and get this working.
Hope it works for you.

TypeError at /index/:Expected binary or unicode string, got <Image: 43474673_7bb4465a86.jpg>

I want to use retrained model to classify image by using Django.
In my Django project:
model.py:
from django.db import models
class Image(models.Model):
photo = models.ImageField(null=True, blank=True)
def __str__(self):
return self.photo.name
setttings.py
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'imageupload')
urls.py
from django.conf.urls import url
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
from imageupload import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index, name='index'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
views.py
from django.shortcuts import render
from .form import UploadImageForm
from .models import Image
import os, sys
import tensorflow as tf
def index(request):
if request.method == 'POST':
form = UploadImageForm(request.POST, request.FILES)
if form.is_valid():
picture = Image(photo=request.FILES['image'])
picture.save()
#if os.path.isfile(picture.photo.url):
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
image_path = picture
# Read in the image_data
image_data = tf.gfile.FastGFile(image_path, 'rb').read()
# Loads label file, strips off carriage return
label_lines = [line.rstrip() for line in
tf.gfile.GFile("retrained_labels.txt")]
# Unpersists graph from file
with tf.gfile.FastGFile("retrained_graph.pb", 'rb') as f:
graph_def = tf.GraphDef()
graph_def.ParseFromString(f.read())
tf.import_graph_def(graph_def, name='')
with tf.Session() as sess:
# Feed the image_data as input to the graph and get first prediction
softmax_tensor = sess.graph.get_tensor_by_name('final_result:0')
predictions = sess.run(softmax_tensor, {'DecodeJpeg/contents:0': image_data})
# Sort to show labels of first prediction in order of confidence
top_k = predictions[0].argsort()[-len(predictions[0]):][::-1]
a =[]
label = []
for node_id in top_k:
human_string = label_lines[node_id]
score = predictions[0][node_id]
a = [human_string, score]
label.append(a)
return render(request, 'show.html', {'picture':picture, 'label':label})
else:
form = UploadImageForm()
return render(request, 'index.html', {'form': form})
index.html
<p>hello index!</p>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
show.html
<h1>This is show!!</h1>
<img src="{{ picture.photo.url }}" />
<br>
<p>Picture'name is: </p>{{ picture.photo.name }}
<br>
<p>The picture's label:</p>
{{ label }}
<br>
I succeeded in uploading a image later, the browser have the error:
the screenshot of the error
Thank you!!
The question had solved!!This is the change:
image_path = picture.photo.path
and there are two to be change:
1. label_lines = [line.rstrip() for line in tf.gfile.GFile("imageupload/retrained_labels.txt")]
2. with tf.gfile.FastGFile("imageupload/retrained_graph.pb", 'rb') as f:
the change is relative path.
My guess is that the error is where you have this line:
image_path = picture
You've saved the image, so what you really want in the image_path variable is the path to where it's stored on disk. It might be that you're hoping the __str__ function you define in model.py will do this for you, but there's no conversion to string happening in this case.
image_path is an image, not the path:
...
image_path = picture
# Read in the image_data
image_data = tf.gfile.FastGFile(image_path, 'rb').read()
...
get the image's path to the file and pass it to FastGFile

Download Files in Django

I need some help understanding how to download files from my django site to a users machine. I have already created a fairly basic way to upload the files. The files are then an instance of a class and are saved in my "media" folder. What I need help with is how to serve the files. I want the user to be able to visit a page and click on the files they want to download. For some reason I can't find any resources on how to do this. Here are my files at this point
urls.py
url(r'^admin/', include(admin.site.urls)),
url(r'^upload/', views.upload),
url(r'^download/', views.download),
url(r'^success/', views.success),
)
if settings.DEBUG:
urlpatterns = patterns('',
url(r'^media/(?P<path>.*)$', 'django.views.static.serve',{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
) + urlpatterns
models.py
class WorkSheet(models.Model):
worksheet_name = models.CharField(max_length= 150, default = '')
creator = models.ForeignKey(User, default = True)
worksheet_file = models.FileField(upload_to = 'worksheets', default = True)
number_of_stars = models.PositiveIntegerField(default = 0)
category = models.CharField(max_length = 100, default = '')
class UploadWorkSheetForm(ModelForm):
class Meta:
model = WorkSheet
exclude = ('number_of_stars',
'creator',)
views.py
def upload(request):
if request.method == 'POST':
form = UploadWorkSheetForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return http.HttpResponseRedirect('/success/')
else:
form = UploadWorkSheetForm()
return render(request, 'upload.html', {'form': form})
def download(request):
return render_to_response('download.html')
def success(request):
return render_to_response('upload_success.html')
So basically I want the user to visite www.mysite.com/download and be able to download a file. Thank you!!
.
.
.
.
.
.
.
.
.
Also, is it a problem that my upload file view does not have a handler like this?
def handle_uploaded_file(file,path=''):
filename = file._get_name()
destination_file = open('%s/%s' % (settings.MEDIA_ROOT, str(path) + str(filename)), 'wb+')
for chunk in file.chunks():
destination_file.write(chunk)
destination_file.close()
In your download view, you are just rendering a download.html, but you are not sending any contexts to it. I would may be send a queryset of worksheets,(Worksheet.objects.all()) as a context to the template. And in the template, do something like
{% for worksheet in worksheets %}
{{ worksheet.worksheet_file.url }}
{% endfor %}
Then you would have all the file urls present in your WorkSheet.objects.all() query.
If possible I would handle all the upload logic in the models file itself, something like this

Cannot get MEDIA_URL from Django widget's template

I am a new Djangoer, and figuring out how to build custom widget, my problem is cannot get the MEDIA_URL in my widget's template, while the form use MySelectWidget able to get the MEDIA_URL itself.
#
#plus_sign.html
#
<a href="" class="" id="id_{{ field }}">
<img src="{{ MEDIA_URL }}images/plus_sign.gif" width="10" height="10" alt="Add"/>
</a>
^ cannot load the {{ MEDIA_URL}} to this widget's template, and therefore I can't load the .gif image properly. :(
#
#custom_widgets.py
#
from django import forms
class MySelectMultiple(forms.SelectMultiple):
def render(self, name, *args, **kwargs):
html = super(MySelectMultiple, self).render(name, *args, **kwargs)
plus = render_to_string("plus_sign.html", {'field': name})
return html+plus
#
#forms.py
#
from django import forms
from myapp.custom_widgets.py import MySelectMultiple
class MyForm(forms.ModelForm):
contacts = forms.ModelMultipleChoiceField(Contact.objects, required=False, widget=MySelectMultiple)
#
#views.py
#
def AddContacts(request):
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
new = form.save()
return HttpResponseRedirect('/addedContact/')
else:
form = MyForm()
return render_to_response('shop/my_form.html', {'form': form}, context_instance=RequestContext(request))
#
#my_form.html
#
{% extends "base.html" %}
{% block content %}
{{ form.contacts }}
{% endblock %}
Please let me know how can I load the widget's image properly. Thank you so much for all responses.
Context processors only get applied when you use a RequestContext.
Your render method should be something like:
from django.template import RequestContext
def render(self, name, *args, **kwargs):
html = super(MySelectMultiple, self).render(name, *args, **kwargs)
context = RequestContext({'field': name})
plus = render_to_string("plus_sign.html", context)
return html + plus
And, as was mentioned by #czarchaic, make sure the media context processor is in TEMPLATE_CONTEXT_PROCESSORS (it should be by default).
Docs link.
Actually the correct way to do this is using Widget Media.
When defining your widget, you should define a Media inner class in which you should include a CSS file in order to style your widget. In this case make the <a> tag not to display text and have a plus sign background image.
class MyWidget(TexInput):
...
class Media:
css = {
'all': ('my_widget.css',)
}
If you really need to include the MEDIA_URL inside your rendered widget, I'd recommmend to import it directly from django.conf.settings and include settings.MEDIA_URL in your rendering context.
from django.conf import settings
class MyWidget(TextInput):
...
def render(self):
return render_to_string('my_widget.html', {
'MEDIA_URL': settings.MEDIA_URL,
...
})
Make sure the context processor is being loaded in settings.py
TEMPLATE_CONTEXT_PROCESSORS=(
...other processors,
"django.core.context_processors.media",
)
It is loaded by default if you don't specify TEMPLATE_CONTEXT_PROCESSORS, but if specified, the above processor must also be included.
http://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors
I think we can do in this way, to pass the RequestContext, in order to access the MEDIA_URL without making another variable, and passing other variables at the 2nd parameter of the render_to_string method.
If we use:
context = RequestContext({'field': name})
The {{ field }} in the widget's template is empty and not able to access.
Here is the block which can access the MEDIA_URL as well as the {{ field }}.
However, I agree using the inner Media class for complex javascript and CSS setting. However, for a simple image src path, I think this will do.
def render(self, name, *args, **kwargs):
html = super(SelectMultipleWithModalDialog, self).render(name, *args, **kwargs)
**context = RequestContext({})
popup_plus = render_to_string("widgets/modal_dialog_plus_sign.html", {'field': name}, context_instance=context)**
return html + popup_plus
Please correct me if this is not the good way of doing it. Thanks for all participants of this thread.