- How do I add the host port to the URLs in my serialized responses? Django is currently providing them without port so the links are broken.
- Or, if adding the port is not the correct approach, how do I change my configuration such that I don't need to specify port in the URL while accessing the resource?
Output (missing port ":1337" in image_url field)
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"user": 1,
"title": "Post 1",
"slug": "post1",
"image_url": "http://0.0.0.0/mediafiles/publisher/sample-image4.jpg",
"content": "First",
"draft": false,
"publish": "2019-04-26",
"updated": "2019-04-26T22:28:35.034742Z",
"timestamp": "2019-04-26T22:28:35.034795Z"
}
]
}
"image_url" field will not link correctly unless it includes the port like this:
"image_url": "http://0.0.0.0:1337/mediafiles/publisher/sample-image4.jpg",
More details
Stack:
- Ubuntu
- Docker (compose)
- Nginx
- Gunicorn 19.9.0
- Django 2.1.7
- Django REST Framework 3.9.2
- Python 3+
- Postgres/psycopg2
I am using Django REST framework to return a list of serialized objects. The objects contain a FileField called "image" and I can output the URL of this image. The only thing is when I click that link in the output in my browser, I cannot access the resource without manually adding the server port in the address like
http://0.0.0.0:1337/mediafiles/publisher/sample-image4.jpg
I'm not sure if it's an nginx issue, a Django settings issue or just how my code is configured. I'm having trouble finding any other reported cases via Google (probably because I'm still new to Django and not sure the correct configuration despite following tutorials).
I tried some of these solutions but they do not output the port.
There's this question, but I'm not using ImageField and I want to find a solution for cases where I'm using FileField. The comment on the main question indicates that adding the port should not be required too, so perhaps it's an infra problem and not a Django problem? Guidance on this would be awesome.
models.py
class Post(models.Model):
class Meta:
ordering = ('timestamp',)
user = models.ForeignKey(User, on_delete=models.PROTECT)
title = models.CharField(max_length=120)
slug = models.SlugField(unique=True)
image = models.FileField(upload_to='publisher/', null=True, blank=True)
content = models.TextField()
draft = models.BooleanField(default=False)
publish = models.DateField(auto_now=False, auto_now_add=False)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
def __str__(self):
return self.title
def __unicode__(self):
return str(self.id)
def get_absolute_url(self):
return reverse("post:detail", kwargs={"slug":self.slug})
serializers.py
class PostSerializer(serializers.ModelSerializer):
image_url = serializers.SerializerMethodField()
class Meta:
model = Post
fields = [
'id',
'user',
'title',
'slug',
'image_url',
'content',
'draft',
'publish',
'updated',
'timestamp',
]
def get_image_url(self, post):
request = self.context.get('request')
if post.image and hasattr(post.image, 'url'):
image_url = post.image.url
return request.build_absolute_uri(image_url)
else:
return None
urls.py
urlpatterns = [
path('admin/', admin.site.urls),
re_path('blog/(?P<version>(v1|v2))/', include('blog.urls'))
]
...
[
url(r'^posts/$', PostListAPIView.as_view(), name='posts'),
]
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
views.py
class PostListAPIView(generics.ListAPIView):
model = Post
queryset = Post.objects.all()
serializer_class = PostSerializer
docker-compose.yml
version: '3.7'
services:
web:
build: ./app
command: gunicorn hello_django.wsgi:application --bind 0.0.0.0:8000
volumes:
- ./app/:/usr/src/app/
- static_volume:/usr/src/app/staticfiles
- media_volume:/usr/src/app/mediafiles
ports:
- "8000"
env_file: ./app/.env
environment:
- DB_ENGINE=django.db.backends.postgresql
- DB_USER
- DB_PASSWORD
- DB_HOST=db
- DB_PORT=5432
- DATABASE=postgres
depends_on:
- db
networks:
- backend
db:
image: postgres:10.7-alpine
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data/
networks:
- backend
nginx:
build: ./nginx
volumes:
- static_volume:/usr/src/app/staticfiles
- media_volume:/usr/src/app/mediafiles
ports:
- "1337:80"
depends_on:
- web
networks:
- backend
networks:
backend:
driver: bridge
volumes:
postgres_data:
static_volume:
media_volume:
nginx.conf
upstream hello_django {
server web:8000;
}
server {
listen 80;
location / {
proxy_pass http://hello_django;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /staticfiles/ {
alias /usr/src/app/staticfiles/;
}
location /mediafiles/ {
alias /usr/src/app/mediafiles/;
}
location /favicon.ico {
access_log off;
log_not_found off;
}
}
See Question&Answers more detail:
os