Image in Django admin is generated with wrong URL - django

I'm trying out Django and ran into the following problem:
I have a model class Property which has various attributes amongst which is an image. The image property is defined as:
image = models.FileField(
upload_to = 'properties',
default = 'properties/house.jpeg')
The directory properties is a sub directory of images which is defined in settings.py as:
MEDIA_ROOT = '/Users/.../Development/pms/images/'
MEDIA_URL = 'http://localhost:8000/images/'
Derived from similar posts on SO regarding this topic, I added the following to my Property model:
def admin_image(self):
return '<img src="images/%s" width="100"/>' % self.image
admin_image.allow_tags = True
I then added admin_image() as a property to the list display:
list_display = ('admin_image', ...)
When I check the URL for the image in the admin application, I get the following:
http://127.0.0.1:8000/admin/properties/property/images/properties/house.jpeg/
This generates a 404 as the URL is generated incorrectly. Firstly the path is incorrect and secondly there's a trailing / at the end of the URL.
I'm obviously missing something... What do I do wrong?
EDIT:
Thanks to #okm for the various pointers. I did the following:
Added the following to my urls.py:
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.conf import settings
... original url patterns ...
urlpatterns += staticfiles_urlpatterns()
if settings.DEBUG:
urlpatterns += patterns('',
url(r'^images/(?P<path>.*)$', 'django.views.static.serve', {
'document_root': settings.MEDIA_ROOT,
}),
)
Then in settings.py set MEDIA_ROOT:
absolute/filesystem/path/to/images
And in settings.py set MEDIA_URL:
/images/

According to the doc & here, try self.image.url instead of '...' % self.image

Related

How to serve media files correctly in django subdomains (using django-hosts) in development?

I have this model Blog and using it in 'blog' subdomain created with 'django-hosts'.
My subdomains in 'hosts.py':
from django.conf import settings
from django_hosts import patterns, host
host_patterns = patterns('',
host(r'blog', 'blog.urls', name='blog'),
host(r'(|www)', settings.ROOT_URLCONF, name='www'),
)
And Blog model - Note that 'title_image' field powered by 'sorl.thumbnail' and 'content' field is a 'django-ckeditor' uploadable field:
class Blog(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL,
verbose_name=_('author'),
on_delete=models.CASCADE,
related_name='blog_author')
title = models.CharField(verbose_name=_('title'), max_length=200)
title_image = ImageField(verbose_name=_('title image'), blank=True)
content = RichTextUploadingField(verbose_name=_('content'))
I've' created a simple ListView for blog that show every blog title, content and title_image to viewer:
class BlogListView(ListView):
"""Everyone can see all blogs"""
template_name = 'blog/templates/blog/blog_list_view.html'
model = Blog
context_object_name = 'blogs'
And my blog.urls:
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
path('', views.BlogListView.as_view(), name='blog_list_view'),
]
When I'm using my blog subdomain (eg: blog.localhost:8000/) it doesn't show any image to me whether it's the title_image or any image in django-ckeditor powered 'content' field.
But when I'm not using subdomain and instead use 'blog' app as other 'URLCONF' path (eg: localhost:8000/blog/) I can see every images without any problem.
Anyone knows why using subdomains, media files does not shown and how to fix it?
I figured it out.
What you need to do is load the MEDIA folder in your urls.py where your hosts is pointing to.
So in your blog.urls
from django.urls import path
from django.conf import settings
from . import views
app_name = 'blog'
urlpatterns = [
path('', views.BlogListView.as_view(), name='blog_list_view'),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
first of all in settings.py
MEDIA_DIR = BASE_DIR / 'media'
MEDIA_ROOT = MEDIA_DIR
MEDIA_URL = '/media/'
then in main project urls.py
from django.conf.urls import url
from django.views.static import serve
from django.conf import settings
url(r'^media/(?P<path>.*)$', serve,{'document_root': settings.MEDIA_ROOT}),
url(r'^static/(?P<path>.*)$', serve,{'document_root': settings.STATIC_ROOT}),
]
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root = settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
and I would ugget in your models use this
title_image = models.ImageField(upload_to='title_images', blank=True)
if you are using app locally then this work fine if the problem is causing in production then use cloudinary

loading local files in django

I have a folder in c:\images, images here are updated by another app. Then I wanted a Django application to read those images on the admin site. The django applicationis sitting in c:\inetpub\wwwroot\myapp I have tried adding below lines in settings.py
CURRENT_PATH = os.path.abspath(os.path.dirname(__file__))
MEDIA_ROOT = os.path.join(CURRENT_PATH, '../../images').replace('\\','/')
MEDIA_URL = 'images/'
I also tried including the whole path in django admin as below in admin.py
def img_field(self, obj):
return format_html('<img src="{}" width="500" height="500" />'.format("c:\images\phot1.png"))
If i put online image link it works fine as below:
def img_field(self, obj):
img = "https://www.thebalancesmb.com/thmb/5G9LJXyFzbTVS-Fj_32sHcgJ8lU=/3000x0/filters:no_upscale():max_bytes(150000):strip_icc():format(webp)/start-online-business-with-no-money-4128823-final-5b87fecd46e0fb00251bb95a.png"
return format_html('<img src="{}" width="500" height="500" />'.format(img))
How can i get around this?
I got it I just needed to add the below lines in urls.py
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [
#urls here
]
urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
It is working fine.

Django Oscar change URL pattern

I have setup a django-oscar project and I'm trying to configure the URLs. My goal is to change /catalogue to /catalog.
As per the documentation I've added app.py in myproject/app.py
myproject/app.py
from django.conf.urls import url, include
from oscar import app
class MyShop(app.Shop):
# Override get_urls method
def get_urls(self):
urlpatterns = [
url(r'^catalog/', include(self.catalogue_app.urls)),
# all the remaining URLs, removed for simplicity
# ...
]
return urlpatterns
application = MyShop()
myproject/urls.py
from django.conf.urls import url, include
from django.contrib import admin
from . import views
from .app import application
urlpatterns = [
url(r'^i18n/', include('django.conf.urls.i18n')),
url(r'^admin/', admin.site.urls),
url(r'', application.urls),
url(r'^index/$',views.index, name = 'index'),
]
The project server runs without any error, but when I try localhost:8000/catalog I get
NoReverseMatch at /catalog/ 'customer' is not a registered namespace.
The expected output is localhost:8000/catalog should return the catalogue page.
You can try this
in app.py
from django.conf.urls import url, include
from oscar import app
class MyShop(app.Shop):
# Override get_urls method
def get_urls(self):
urls = [
url(r'^catalog/', include(self.catalogue_app.urls)),
# all the remaining URLs, removed for simplicity
# ...
]
urls = urls + super(MyShop,self).get_urls()
return urls
application = MyShop()
And in your urls.py
you can simply add this
from myproject.app import application as shop
url(r'', shop.urls),
Hope it help for you
Expanding on c.grey's answer to specify how to replace instead of add the urls -
from django.conf.urls import url, include
from oscar import app
class MyShop(app.Shop):
def get_urls(self):
urls = super(MyShop, self).get_urls()
for index, u in enumerate(urls):
if u.regex.pattern == r'^catalogue/':
urls[index] = url(r'^catalog/', include(self.catalogue_app.urls))
break
return urls
application = MyShop()
You need to include the URLs, not reference them directly.
url(r'', include('application.urls')),

Django ImageField Image Not Displaying

I'm trying to use Django 2.0. I'm using the development 'runserver' right now, so please keep in mind that I'm not in production yet. I am familiar with the differences between the two with regard to static files.
I have a Blog Post model. In the admin, I want to be able to add an image to my model using ImageField. I'd like it to be optional, and provide a default image if none is added.
I am able to load images in admin. I am unable to render my image in my template. The console shows that Django is trying to GET my image, but my configurations have not worked so far.
Here's my model and relevant field:
from PIL import Image
class Post(models.Model):
....
thumbnail = models.ImageField(default='/img/default.png', upload_to='img', blank=True, null=True)
....
My model works well aside from the ImageField. My View works well, and I don't think there is any issue there.
Here is my urls.py
....
from django.conf.urls.static import static
from django.conf import settings
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from . import views
urlpatterns = [
....
path('posts/', views.PostListView.as_view(), name='post_list'),
path('post/<int:pk>/', views.PostDetailView.as_view(), name='post_detail'),
path('post/random/', views.random_post, name='random_post'),
]
urlpatterns += staticfiles_urlpatterns()
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
I'm not at all sure about how to handle static files vs. media files in my urls.py, especially with changes to Django in version 2.0.
Here's my relevant settings.
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_URL = '/static/'
TEMPLATES = [
{
...
'OPTIONS': {
'context_processors': [
....
'django.contrib.messages.context_processors.media',
....
]
},
},
]
MEDIA_ROOT = os.path.join(BASE_DIR, 'media').replace('\\', '/')
MEDIA_URL = '/media/'
I am equally unsure of what to put in my settings.py concerning media. My static CSS files are working just fine. I have a logo image in my static files that is rendering in my base template.
Here is my template tag for the ImageField:
<img class="card-image mr-3" src="{{ post.thumbnail.url }}" alt="Generic placeholder image">
Lastly, my /static folder and my /media folder are in the same directory. These are both in my app directory, /blog.
Can anyone see any blaring errors here, or can they make suggestions? My issue is the default image is not loading. The default image IS in the correct directory /media/img/. The console warning says "Not Found: /media/img/default.png".
Thanks in advance. Any suggestions will be helpful.
Django ImageField for Admin Panel
There is important thing you have to define your MEDIA_URL in urls.py.
Without this definition framework doesn't gives to you permission to access image
Setting.py
MEDIA_URL = '/uploads/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')
urls.py
if settings.DEBUG: # new
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Models.py
class Product(models.Model):
title = models.CharField(max_length=150)
image=models.ImageField(blank=True,upload_to='images/')
def __str__(self):
return self.title
def image_tag(self):
return mark_safe('<img src="{}" height="50"/>'.format(self.image.url))
image_tag.short_description = 'Image'
Admin.py
class ProductAdmin(admin.ModelAdmin):
list_display = ['title','image_tag']
readonly_fields = ('image_tag',)
Printing the media root helped me solve this issue. Thanks Alasdair.
I don't think there was any issue with my model field above.
The urls.py code that I ended up using is directly from Django docs for Django 2.0 in handling static files https://docs.djangoproject.com/en/2.0/howto/static-files/.
The changes I made to Settings were done thanks to printing my MEDIA_ROOT in the console. I changed the syntax and the direction of a slash (blog\media). I also deleted the context processor shown above in my TEMPLATES options.
Here's what works for me:
models.py
thumbnail = models.ImageField(default='img/default.png', upload_to='img', blank=True, null=True)
urls.py
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [...] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
settings.py
MEDIA_ROOT = os.path.join(BASE_DIR, 'blog\media')
MEDIA_URL = '/media/'
print(MEDIA_ROOT)
Template tag
<img class="card-image mr-3" src="{{ post.thumbnail.url }}" alt="Generic placeholder image">

MEDIA_URL Page 404 Error Django

I am running on a local server and when I go to http://127.0.0.1:8000/media/ in my browser it says page not found.
Settings:
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
STATIC_URL = '/static/'
Root URL:
from django.conf.urls import url, include
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
url(r'^polls/', include('mysite.polls.urls')),
url(r'^admin/', admin.site.urls),
url(r'^submit/', include('mysite.uploads.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Model for User Upload:
from django.db import models
class Document(models.Model):
description = models.CharField(max_length=255, blank=True)
document = models.FileField(upload_to='documents/')
uploaded_at = models.DateTimeField(auto_now_add=True)
Following the Django documentation:
Serving files uploaded by a user during development
During development, you can serve user-uploaded media files from MEDIA_ROOT using the django.contrib.staticfiles.views.serve() view.
This is not suitable for production use! For some common deployment strategies, see Deploying static files.
For example, if your MEDIA_URL is defined as /media/, you can do this by adding the following snippet to your urls.py:
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# ... the rest of your URLconf goes here ...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
https://docs.djangoproject.com/en/1.10/howto/static-files/
As pointed above in the comments by Alasdair, This is the normal behaviour of Django. If you visit the full file path like 127.0.0.1/media/file.jpg, Django will render the file instead of raising a 404 error.
Why is this happening?
If you look at the source of the view that serves the media/static files, you'll find these lines:
if os.path.isdir(fullpath):
if show_indexes:
return directory_index(newpath, fullpath)
raise Http404(_("Directory indexes are not allowed here."))
What it does is, it checks if the path requested is a directory or not. If yes, then it checks if the variable show_indexes is True, then it will return the index of the files inside the media directory. Since, show_indexes is False by default, it raises 404.
To set show_indexes to True, you can do this:
urlpatterns = [
# ... the rest of your URLconf goes here ...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT, show_indexes=True)
This won't raise the 404 and will display a list of files inside media dir.
P.S.: I don't think displaying file indices is a good idea, unless, of course, that's something you really want. It puts server under extra load to generate the indices. And someone can download the files recursively using a program like wget etc. Even those files that are meant to be private.