I have defined a model with a 'pic' image field:
class Photo(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
teaser = models.TextField('teaser', blank=True)
pic = models.ImageField(upload_to = 'pic_folder/', default = 'pic_folder/None/default.jpg')
created=models.DateTimeField(default=datetime.datetime.now)
pub_date=models.DateTimeField(default=datetime.datetime.now)
categories = models.ManyToManyField(Category, blank=True)
likes = models.IntegerField(default=0)
dislikes = models.IntegerField(default=0)
visits = models.IntegerField(default=0)
slug = models.CharField(max_length=100, unique=True, blank=True)
And here is the upload form:
class PhotoForm(forms.ModelForm):
class Meta:
model= Photo
fields = ( 'title', 'pic','body', 'categories')
Wich post to this view:
#staff_member_required
def add_photo(request):
if request.method == 'POST':
form = PhotoForm(request.POST, request.FILES)
if form.is_valid():
form.save()
messages.info(request, "photo was added")
return render(request, 'home.html')
else:
messages.info(request, 'form not valid')
return render(request, 'home.html')
if request.method == 'GET':
form = PhotoForm()
args = {}
args.update(csrf(request))
args['form'] = form
return render(request, 'photo/add_photo.html', args)
The problem is that while photo objects are being saved and the file uploaded but the images are not displayed.
<div class="photo_body"><img src="pic_folder/someimage.jpg" ></div>
I also set
MEDIA_ROOT = '/path/to/my_project/pic_folder'
and run manage.py collectstatic, but they did not solve the problem.
I really got confused about this. So appreciate your hints.
First of all make a folder called media in your project's directory.
Django will store all your uploaded images inside media/pic_folder/ automatically.
In your settings.py file, add this:
MEDIA_URL = '/media/'
MEDIA_ROOT = '/path_to/media/' # write the path to the media folder you just created.
In your urls.py file, add the following lines at the top:
from django.conf import settings
from django.conf.urls.static import static
and add the following line at the end:
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
something like below:
urlpatterns = patterns('',
# Your urls here
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
And, finally, in your templates:
<img src="{{MEDIA_URL}}pic_folder/someimage.jpg" />
Related
I'm quite new to using Django and I am trying to develop a website where the user can download file at the end of the post.
Post model:
class Article(models.Model):
title = models.CharField(max_length=30)
content = models.TextField()
pub_date = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
file = models.FileField(upload_to='code_files/')
def __str__(self):
return self.title
I have a views:
def download(request):
response = HttpResponse(open(f"media/code_files/tests.py", 'rb').read())
response['Content-Type'] = 'text/plain'
response['Content-Disposition'] = f'attachment; filename=tests.py'
return response
How can I download the file linked with the post?
From Dajngo docs FileResponse is a subclass of StreamingHttpResponse optimized for binary files.
import os
from django.http import FileResponse
from django.views.decorators.http import require_POST
#require_POST
def download(request):
article = Article.objects.get(id=1)
fullpath = article.file.path
if not os.path.exists(fullpath):
raise Http404('{0} does not exist'.format(fullpath))
return FileResponse(
open(fullpath, 'rb'), as_attachment=True,
filename=article.file.name)
Assuming that you passed the Article object to your template from your views as a context.
context = {
'article' = article_obj,
}
In your HTML, you need to use the embed tag and the url of the FileField of the Article object.
<embed src="{{article.file.url}}" width="500" height="200">
You shouldn't need to write another view just to download the file. Just have the article in your context in the view where you want to show the link to download:
context = {'article': Article.objects.first()}
Make sure that you have also added your media URL in your settings:
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
and project urls.py:
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Then, for your article model, give each article a formatted file url:
class Article(models.Model):
#property
def formatted_file_url(self):
if self.file:
return settings.MEDIA_URL + self.file.url
else:
return 'No url'
Download with:
<a href="{{ article.formatted_file_url }}" download>
This is my model:
def group_based_upload_to(instance, filename):
return "media/image/lavorazione/{}".format(instance.prestazione.id,)
class ImmaginiLavorazioni(models.Model):
immagine = models.ImageField(upload_to=group_based_upload_to)
prestazione = models.ForeignKey(Listino, on_delete=models.SET_NULL, null=True,
blank=True, default=None, related_name='Listino3')
and my form:
class ImmagineUploadForm(forms.ModelForm):
class Meta:
model = ImmaginiLavorazioni
exclude = ('preventivo', )
I need a view to save an image in a specific path.
The name of path must be the pk of foreign key.
How can I do that?
I use a model of how a blog post works. You can adjust the example on your needs. You should try and avoid saving the location path from a view.
On your models.py:
# Create your models here.
def upload_location(instance, filename):
filebase, extension = filename.split(".")
return "%s/%s" % (instance.id, filename)
class Post(models.Model):
title = models.CharField(max_length=120)
slug = models.SlugField(unique=True)
image = models.ImageField(upload_to=upload_location,
null=True,
blank=True,
height_field="height_field",
width_field="width_field")
height_field = models.IntegerField(default=0)
width_field = models.IntegerField(default=0)
content = HTMLField()
formfield_overrides = {
models.TextField: {'widget': AdminPagedownWidget },
}
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
On your forms.py:
from django import forms
from pagedown.widgets import PagedownWidget
from pagedown.widgets import AdminPagedownWidget
from .models import Post
class PostForm(forms.ModelForm):
content = forms.CharField(widget=PagedownWidget(show_preview=False))
class Meta:
model = Post
fields = [
"title",
"content",
"image"
]
class PostModelForm(forms.ModelForm):
content = forms.CharField(widget=AdminPagedownWidget())
class Meta:
model = Post
fields = '__all__'
And on your settings.py:
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), "media_cdn")
Here is your view.py:
# Create your views here.
def post_create(request):
if not request.user.is_staff or not request.user.is_superuser:
raise Http404
form = PostForm(request.POST or None, request.FILES or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
messages.success(request, "Succefully Created")
return HttpResponseRedirect(instance.get_absolute_url())
context = {
"form": form,
}
return render(request, "post_form.html", context)
The next code has an example without form but you can modify based on your needs.
Below the settings.py
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.realpath(__file__))
MEDIA_ROOT = os.path.join(BASE_DIR, '../media')
Firstable, I defined the path of the image in the helpers.py
from django.conf import settings
from datetime import datetime
def upload_to_image_post(self, filename):
"""
Stores the image in a specific path regards to date
and changes the name of the image with for the name of the post
"""
current_date = datetime.now()
return '%s/posts/main/{year}/{month}/{day}/%s'.format(
year=current_date.strftime('%Y'), month=current_date.strftime('%m'),
day=current_date.strftime('%d')) % (settings.MEDIA_ROOT, filename)
You could define the image's name with some code like this one. But you have to regard you should have the pk to replace the name of the image
ext = filename.split('.')[-1]
name = self.pk
filename = '%s.%s' % (name, ext)
So, I called the def in my models.py, specifically in the image's field
from django.db import models
from django.utils.text import slugify
from .helpers import upload_to_image_post
class Post(models.Model):
"""
Store a simple Post entry.
"""
title = models.CharField('Title', max_length=200, help_text='Title of the post')
body = models.TextField('Body', help_text='Enter the description of the post')
slug = models.SlugField('Slug', max_length=200, db_index=True, unique=True, help_text='Title in format of URL')
image_post = models.ImageField('Image', max_length=80, blank=True, upload_to=upload_to_image_post, help_text='Main image of the post')
class Meta:
verbose_name = 'Post'
verbose_name_plural = 'Posts'
I hope this helped you
Now this is my models:
def group_based_upload_to(instance, immagine):
return "media/preventivo/{pk}/{image}".format(pk=instance.preventivo.id, image=immagine)
class ImmaginiLavorazioni(models.Model):
immagine = models.ImageField(upload_to=group_based_upload_to)
preventivo = models.ForeignKey(Preventivo, on_delete=models.SET_NULL, null=True, blank=True,
default=None, related_name='Listino3')
And this is my view:
def upload_immagine(request, pk):
member = get_object_or_404(Preventivo, pk=pk)
if request.method == 'POST':
form = ImmagineUploadForm(request.POST or None, request.FILES or None)
if form.is_valid():
newimmagine = form.save(commit=False)
newimmagine.preventivo_id = member.pk
newimmagine.save()
return redirect('preventivo_new2', pk=member.pk)
else:
form = ImmagineUploadForm(request.POST or None, request.FILES or None)
return render(request, 'FBIsystem/upload_immagine.html', {'member': member, 'form': form})
It save in db the file path and the foreign key like:
immagine= media/preventivo/6/image.jpg
preventivo_id = 6
but not create a folder and not save the uploaded image...
I'm new in Django. I need help. I want to display images. Here I saved image path to database and images to folder. Please help me to display those images.
views.py:
def uploadfile(request):
print('inside upload logic')
if request.method == 'POST':
form = FileUploadForm(request.POST, request.FILES)
if form.is_valid():
# ImageUpload(request.FILES['File_Name'])
myfile = request.FILES['File_Name']
fs = FileSystemStorage()
filename = fs.save(myfile.name, myfile)
uploaded_file_url = fs.url(filename)
newdoc = FileUpload(File_Name=myfile.name, File_path=uploaded_file_url, Description=request.POST['Description'])
newdoc.save()
#return HttpResponse("File uploaded successfuly")
return render(request, 'Login/fileupload.html')
else:
form = FileUploadForm()
return render(request, 'Login/fileupload.html', {
'form': form
})
def dataretrive(request):
newdoc=FileUpload.objects.all()
return render(request,'Login/displayimage.html',{'FileUpload':FileUpload})
MY Model:
class FileUpload(models.Model):
File_Name = models.CharField(max_length=255, blank=True)
File_path = models.FileField(upload_to='')
Description = models.CharField(max_length=255, blank=True)
Upload_Date = models.DateTimeField(auto_now_add=True)
Check this
Add this to your model:
class FileUpload(models.Model):
File_Name = models.CharField(max_length=255, blank=True)
File_path = models.FileField(upload_to='')
Description = models.CharField(max_length=255, blank=True)
Image = models.ImageField(upload_to=upload_location)
Upload_Date = models.DateTimeField(auto_now_add=True)
def upload_location(instance, filename):
filebase, extension = filename.split(".")
return "%s/%s" % (instance.id, filename)
In you settings.py file make sure to set MEDIA_URL and MEDIA_ROOT:
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
To access the MEDIA_URL in template you must add django.template.context_processors.media to your context_processeors inside the TEMPLATES config.
Add this to your template:
{% if instance.image %}
<img src="{{ instance.image.url }}" class='img-responsive' />
{% endif %}
I'm uploading certain media to a particular directory to secure it. The images are uploaded using an inlineformset_factory object.
The problem I have is that where viewing the uploaded record in the admin site it appears to prepend my settings.MEDIA_URL (/media/) to the path of the uploaded image.
ie.
http://localhost:8000/media/<relative image path>
What I would like it to use instead is a custom setting, settings.PROTECTED_MEDIA_URL ('src') to return the following path instead:
http://localhost:8000/scr/<relative image path>
Included below are what I believe are the relevant parts of the code.
Any insight is appreciated!
settings.py
...
MEDIA_URL = '/media/'
PROTECTED_MEDIA_URL = '/scr/'
...
model.py
...
from django.core.files.storage import FileSystemStorage
fs = FileSystemStorage(location = '/home/user/nginx_restricted')
def orig_car_id_folder(instance, filename):
return 'uploads/images/orig/{0}/{1}'.format(instance.car_id, filename)
class OwnersCar(models.Model):
brand = models.CharField(max_length=64)
...
class OwnersCarImages(models.Model):
car = models.ForeignKey(OwnersCar)
orig_image = models.ImageField(
upload_to=orig_car_id_folder,
verbose_name='Upload Image',
storage=fs
)
...
...
admin.py
from django.contrib import admin
from vehicle_admin_ac.models import OwnersCar, OwnersCarImages
class CarImageInline(admin.TabularInline):
model = OwnersCarImages
exclude = ('thumbnail',)
class OwnersCarAdmin(admin.ModelAdmin):
list_display = ('owner','brand',)
ordering = ('owner',)
search_fields = ('owner',)
inlines = [
CarImageInline,
]
admin.site.register(OwnersCar, OwnersCarAdmin)
urls.py
...
urlpatterns = patterns('',
url(r'^scr/(?P<protected_image_path>/uploads/images/(thumb|orig)/.*)$',
'vehicle_admin_ac.views.protected_view',
name='protected_view'),
...
)
...
views.py
...
#login_required
def protected_view(request, protected_image_path):
response = HttpResponse()
url = protected_image_path
response['Content-Type']=""
response['X-Accel-Redirect'] = "/protected/{0}".format(url)
return response
#login_required
def add_vehicle(request):
ImageFormSet = inlineformset_factory(OwnersCar, OwnersCarImages, form=InitialCarImageForm, extra=3)
owners_car = OwnersCar()
if request.method == 'POST':
form = forms.OwnersCarForm(request.POST, instance=owners_car)
formset = ImageFormSet(request.POST, request.FILES, instance=owners_car)
if formset.is_valid() and form.is_valid():
new_car = form.save(commit=False)
new_car.owner = request.user
new_car.save()
formset.save() # save() method works fine with 'inlineformset_factory'
return HttpResponseRedirect(new_car.get_absolute_url())
else:
form = forms.OwnersCarForm()
formset = ImageFormSet()
return render_to_response('add_new.html',
{'form': form, 'formset': formset},
context_instance=RequestContext(request))
...
Here's a link the relevant part of the docs that I'd missed, explaining the base_url argument.
I'm been working on this Photo Organizer and Sharing App Part I at http://lightbird.net/dbe/photo.html. I'm trying to add a picture and when I do . I get this error.
Page not found (404)
Request Method: GET
Request URL: http://donkey123.pythonanywhere.com/admin/photo/image/1/images/Penguins_7.jpg/
image object with primary key u'1/images/Penguins_7.jpg' does not exist.
You're seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.
My Models is
from django.db import models
from django.contrib.auth.models import User
from django.contrib import admin
from string import join
import os
from PIL import Image as PImage
from mysite.settings import MEDIA_ROOT
class Album(models.Model):
title = models.CharField(max_length=60)
public = models.BooleanField(default=False)
def __unicode__(self):
return self.title
class Tag(models.Model):
tag = models.CharField(max_length=50)
def __unicode__(self):
return self.tag
class Image(models.Model):
title = models.CharField(max_length=60, blank=True, null=True)
image = models.FileField(upload_to="images/")
tags = models.ManyToManyField(Tag, blank=True)
albums = models.ManyToManyField(Album, blank=True)
created = models.DateTimeField(auto_now_add=True)
rating = models.IntegerField(default=50)
width = models.IntegerField(blank=True, null=True)
height = models.IntegerField(blank=True, null=True)
user = models.ForeignKey(User, null=True, blank=True)
def __unicode__(self):
return self.image.name
def save(self, *args, **kwargs):
"""Save image dimensions."""
super(Image, self).save(*args, **kwargs)
im = PImage.open(os.path.join(MEDIA_ROOT, self.image.name))
self.width, self.height = im.size
super(Image, self).save(*args, ** kwargs)
def size(self):
"""Image size."""
return "%s x %s" % (self.width, self.height)
def __unicode__(self):
return self.image.name
def tags_(self):
lst = [x[1] for x in self.tags.values_list()]
return str(join(lst, ', '))
def albums_(self):
lst = [x[1] for x in self.albums.values_list()]
return str(join(lst, ', '))
def thumbnail(self):
return """<img border="0" alt="" src="/media/%s" height="40" />""" % (
(self.image.name, self.image.name))
thumbnail.allow_tags = True
class AlbumAdmin(admin.ModelAdmin):
search_fields = ["title"]
list_display = ["title"]
class TagAdmin(admin.ModelAdmin):
list_display = ["tag"]
class ImageAdmin(admin.ModelAdmin):
search_fields = ["title"]
list_display = ["__unicode__", "title", "user", "rating", "size", "tags_", "albums_","thumbnail","created"]
list_filter = ["tags", "albums","user"]
def save_model(self, request, obj, form, change):
obj.user = request.user
obj.save()
I think My Models,py is fine but I think the problem lay at the
MEDIA_ROOT= and MEDIA URL=
My MEDIA_ROOT = '/home/donkey123/mysite/photo'
and my MEDIA_URL is "" which is blank.
I don't know what to put for my MEDIA_URL which is the problem.
Thanks in advance
In your model (note there is no need for the slash at the end):
image = models.FileField(upload_to="images")
That means these images will go in {media folder}/images/
In settings.py:
MEDIA_ROOT = os.path.join(os.path.dirname(__file__), '../../web/media').replace('\\','/')
That means the media folder is: project_root/web/media
So the images from this model will go in: project_root/web/media/images
The stuffs above define where the images are saved on the filesystems. Now what you want to do is to define where they will be accessed via HTTP.
In settings.py define the url pointing to the media folder:
MEDIA_URL = '/media/'
Then the images from this model will be in:
http://my-url/media/images/image_name.jpg
Tests these settings without your model/library first with one image. Then read the following:
To reply to your specific questions:
My MEDIA_ROOT = '/home/donkey123/mystic/photo' => see my example, the MEDIA_ROOT should be relative to your settings.py file so it will work when going live, on another dev machine, etc.
and my MEDIA_URL= is "" which is blank. => that should be '/media/' because in the model you are doing this:
def thumbnail(self):
return """<a href="/media/%s">
Hope that helps
settings.py
import os
PROJECT_ROOT = os.path.join(os.path.dirname(__file__), '..')
SITE_ROOT = PROJECT_ROOT
MEDIA_ROOT = os.path.join(SITE_ROOT, 'media')
MEDIA_URL = '/media/'
Problem is with the regular expression in your urls.py, which is taking everything after 1 and passing it in as the primary key.
I think, When any web page is removed or moved then 404 happens. Otherwise your hosting provider is not good.