一尘不染

如何在Django中资源URL中IP地址之后输出端口?

docker

  1. 如何在序列化响应中将主机端口添加到URL?Django当前没有提供端口,因此链接已断开。
  2. 或者,如果添加端口不是正确的方法,那么如何更改我的配置,以便在访问资源时无需在URL中指定端口?

输出 (image_url字段中缺少端口“:1337”)

{
    "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”字段将无法正确链接:

"image_url": "http://0.0.0.0:1337/mediafiles/publisher/sample-image4.jpg",

更多细节

堆:

  • Ubuntu
  • Docker(撰写)
  • Nginx的
  • unicorn19.9.0
  • Django 2.1.7
  • Django REST框架3.9.2
  • Python 3+
  • Postgres / psycopg2

我正在使用Django REST框架返回序列化对象的列表。这些对象包含一个名为“
image”的FileField,我可以输出该图像的URL。唯一的事情是,当我单击浏览器输出中的链接时,如果不手动在以下地址中添加服务器端口,则无法访问资源

http://0.0.0.0:1337/mediafiles/publisher/sample-image4.jpg

我不确定这是nginx问题,Django设置问题还是我的代码配置方式。我在通过Google查找其他报告的案例时遇到了麻烦(可能是因为我还是Django的新手,尽管遵循了教程,但不确定正确的配置)。

我尝试了其中一些解决方案,但它们不输出端口。

有这个问题,但是我没有使用ImageField,而是想找到一种解决方案,以解决使用FileField的情况。对主要问题的评论表明,也不需要添加端口,所以也许这是一个基础问题,而不是Django问题?对此的指导将是很棒的。

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;
    }
}

阅读 419

收藏
2020-06-17

共1个答案

一尘不染

由于这个问题,我终于找到了解决图像URL的方法,这个问题稍有不同。

解决方案1

将端口号添加到nginx配置中的Host标头中,如下所示:

    location / {
        proxy_pass http://hello_django;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host:1337;                               <<------- HERE
        proxy_redirect off;
    }

解决方案2

将nginx配置中的Host标头更改http_host如下:

    location / {
        proxy_pass http://hello_django;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;                               <<------- HERE
        proxy_redirect off;
    }

无论哪种情况,DURL(图像链接)现在都按以下方式返回图像URL 。

HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "count": 1,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 2,
            "user": 1,
            "title": "First post",
            "slug": "first",
            "image_url": "http://0.0.0.0:1337/mediafiles/publisher/background.gif",    <----HERE
            "content": "Second post content.",
            "draft": false,
            "publish": "2019-05-22",
            "updated": "2019-05-22T09:41:36.257605Z",
            "timestamp": "2019-05-22T07:58:01.471534Z"
        }
    ]
}
2020-06-17