Django Media Files (Images) Security - python

I am working on image handling in Django. I am using normal image model storing method.
So, my model is something like,
class PictureModel(models.Model):
def user_directory_path(instance, filename):
return 'images/{0}/{1}'.format(instance.user.username, filename)
user = models.ForeignKey(User, on_delete=models.CASCADE)
image = models.ImageField(upload_to=user_directory_path)
The view.py is somewhat like,
#login_required(login_url='/accounts/login/')
def myMethod(request):
user = request.user
myImage = PictureModel.objects.get(user=request.user)
return render(request, 'main/myPage.html', {'myImage': myImage})
I have a media root setup as,
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
The url.py setup is as follows,
url(r'^static/(?P<path>.*)$', django.views.static.serve, {'document_root': settings.STATIC_ROOT, 'show_indexes': settings.DEBUG})
Now in normal flow, the image uploading and fetching are working as expected. But the issue is regarding the user validation/authentication while fetching the media file.
Suppose, I am getting an image by the URL,
media/images/user_1/mypic.jpg
But the whole media folder gets exposed without any validations and I can access,
media/images/user_2/mypic.jpg
also through the browser. I have searched on this over the net and found there are some random third party libraries are available but they are not so standard/popular. Can anyone suggest the best practices and libraries to handle the situation.

Add this in your template
it solves the problem
<img style="height:200px; width:200px; border-radius:50%; margin:auto" src="{{ appname.function_name.image.url }}" alt="Photo">

Related

Populating Django SQL Database

I would like create a database for my images that I could access using django. For the model I want to create something along these lines of
class Images(models.Model):
Image_loc = models.CharField(max_length = 200)
Image_year = models.CharField(max_length = 200)
Image_date = models.DateTimeField('date taken')
Where image_loc is the image file location and image_year is the year that the image was taken. I would like to populate the database with multiple images. I am new to website design and django and was wondering if anyone knew how would I go about doing this?
For images, you should use ImageField. You'll need to install a library named Pillow for it to work (as per the Django docs I just linked). To do that, just run:
python -m pip install Pillow
You'll also need to set up your MEDIA_ROOT and MEDIA_URL (more on that here). All you need to do is append this to your projects settings.py:
# Media files
# https://docs.djangoproject.com/en/dev/topics/files/
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, "media/")
MEDIA_URL is the url path of the images.
MEDIA_ROOT is the location of the image files.
Then, add this to your PROJECT'S (not app's) urls.py:
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
...
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
If you set it up this way, you won't need the image_loc field, since that's automatically managed by ImageField. You can just replace that field with the new ImageField.

I couldn't play the audios that were uploaded to admin (the urls have quotation marks)

I created a new class in my model.py file:
class Audio(models.Model):
.....
audio_object = models.FileField(default='')
And I uploaded my audios to my admin page.
However, the audios don't play and I right-clicked to a new browser, it shows "Page Not Found" saying "The current path, appname/“/media/nameoftheaudio.mp3”, didn't match any of the URLconf defined in projectname.urls.
I reviewed the answers from Django MEDIA_URL and MEDIA_ROOT but it didn't solve my problems.
In my urls.py, I already have:
from django.conf import settings
from django.conf.urls.static import static
urlpatterns += staticfiles_urlpatterns()
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
And in my setting.py, I have:
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'assets'),
)
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Another piece of information is the audios I uploaded to another class work fine! And that is the first class model I created in this project. I can't detect what do I lack for this Audio class.
I am using Django 3.0.4
Thank you!!
Update: I think I found the issue: when I open the link for my audio, there are always quotation marks attached for "media/audio.mp3".
My screenshot
How can I remove the quotation marks; I am pretty sure several days ago the media files work fine but ever since I added a new class it became like this.
Many thanks for your help!!!

Django show ImageField

I have extended the base User from Django with the OneToOne method.
class Employee(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE)
floor = models.CharField(max_length = 100)
avatar = models.ImageField(upload_to='userimages')
The image is uploaded to media/userimages.
Now, when I try to show the avatar, I am trying this way, but it doesn't show anything.
<img src="media/{{ user.employee.avatar.url }}" alt="">
If I just output user.employee.avatar.url, I get:
'media/userimages/name.jpg'
The image exists in that folder, but it doesn't appear on the website.
I really can't figure out why it doesn't work. Any help is appreciated.
You should not use
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
to do this. This is okay only for debug purposes. Otherwise, it's your nginx/apache/other_server that should be responsible for serving static files and media files along with routing the .sock file generated by gunicorn/uwsgi.
I finally figured out how to make it work, so just in case somebody else has the same problem I am going to answer to my question. Basically just add this to settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'app/media')
And this to urls.py:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Viewing images uploaded to Django Admin

I have a simple Django admin page that uploads images to a product description. Everything works until I try to view the image by clicking on its path in the products information. I get this error:
Page not found (404)
Request URL: http://0.0.0.0:6666/the_image.jpg
I'm guessing I need to declare something in urls.py, but I have no idea where to start. I also tried changing my media paths in settings.py but I always get errors if I change to anything other than '/'
model.py
class Image(models.Model):
product_image = models.ForeignKey(Product)
image = models.ImageField(upload_to='/')
settings.py
MEDIA_ROOT = '/'
MEDIA_URL = '/'
admin.py
class InlineImage(admin.TabularInline):
model = Image
class ProductAdmin(admin.ModelAdmin):
inlines = [InlineImage]
Docs are here https://docs.djangoproject.com/en/dev/ref/settings/#media-root
You need to set MEDIA_ROOT and MEDIA_URL in your settings file like this
MEDIA_ROOT = /var/www/example.com/media/
MEDIA_URL = /media
and your upload_to should probably be the model name or something to identify it.
image = models.ImageField(upload_to='image')
Then the link should point the /media/image/NAME_OF_IMAGE.png
You will also need to have urls.py setup to server media files. For production you would want to do this in nginx with an alias. See https://docs.djangoproject.com/en/dev/howto/static-files/#serving-files-uploaded-by-a-user-during-development
Which says:
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = patterns('',
# ... the rest of your URLconf goes here ...
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Django Static URL not rendering images correctly

I'm writing a view that displays a set of images on a page.
This is the model
#models.py
class Movie(models.Model):
title = models.CharField(max_length = 500)
poster = models.ImageField(upload_to = 'qanda/static/movie_posters')
#index.html
<img src = "{{ STATIC_URL }}movie_posters/{{ movie.poster }}"></a>
When I runserver, the image doesn't appear. The URL the image is trying to load is
http://127.0.0.1:8000/static/movie_posters/qanda/static/movie_posters/image.jpg
When the URL it should be trying to load is
http://127.0.0.1:8000/static/movie_posters/image.jpg
My assumption is that since movie.poster is located at 'qanda/static/movie_posters', when I render it on HTML, it is loading the Static URL (127.0.0:8000/static) and then the location 'qanda/static/movie_posters' at the end. How do I make the image render correctly?
There are two pieces of how image url is calculated.
First in your settings.py you define MEDIA_ROOT. MEDIA_ROOT specifies an absolute folder on your computer where media will be stored. So for example for these settings:
MEDIA_ROOT = '/abs/path/to/media/'
and if you have a field
models.ImageField(upload_to='movie_posters')
then images will be stored at:
/abs/path/to/media/movie_posters/
/abs/path/to/media/movie_posters/poster.jpg <- example
This deals with where media is stored on your hard drive.
Second piece is how to calculate urls for these media files. For that you define MEDIA_URL in your settings.py. That essentially maps a URL to your MEDIA_ROOT location. So then if your MEDIA_URL is:
MEDIA_URL = 'http://localhost/media/'
Then if you want to access an image stored at movie_posters/poster.jpg which has an absolute path of /abs/path/to/media/movie_posters/poster.jpg, its URL should be http://localhost/media/movie_posters/poster.jpg. You can compute the URL by doing:
{{ MEDIA_URL }}{{ movie.poster }}
Please note that I am using MEDIA_URL instead of STATIC_URL. Those are not the same thing. Computing urls like that however is not very neat. Thats why Django's ImageField and FileField have an url attribute:
{{ movie.poster.url }}
Django will then compute the proper url depending on your MEDIA_URL setting.
Note:
For all of this to work, you have to have a separate media server running. Django does not serve any media files. In development it is only capable of serving static file (not same as media files). So in development one nice trick to serve media files is to use Python's simple web server. For that, open a new terminal (on Linux and Mac) or Command Prompt (on Windows) window/tab and navigate to your media folder. Then just execute the following command there:
python -m SimpleHTTPServer 8090
and make sure your setting is:
MEDIA_URL = 'http://localhost:8090/'
and then Python will serve your media files. That works nice for development.
If you want to serve your media just using the development server you can add this for the time being to your urls.py
urlpatterns = patterns( ...all your awesome urls...) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
you can define a custom template tag which returns the basename of the URL like this:
from django import template
import os
register = template.Library()
#register.filter
def getBasename(myURL):
return os.path.basename(myURL)
this should go in your custom template tags (eg. customTemplateTags.py) file within your templatetags directory of your app.
Then you can use the filter in order to get only the image filename, not the entire URL.
{% load customTemplateTags %}
<img src = "{{ STATIC_URL }}movie_posters/{{ movie.poster.url|getBasename }}"></a>

Categories

Resources