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

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

本文介绍了如何在Django中的资源URL中的IP地址后输出端口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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"字段将无法正确链接,除非它包含这样的端口:

"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",

更多详情

堆栈:

  • Ubuntu
  • Docker(撰写)
  • Nginx
  • Gunicorn 19.9.0
  • Django 2.1.7
  • Django REST 框架 3.9.2
  • Python 3+
  • Postgres/psycopg2

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

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

我不确定这是 nginx 问题、Django 设置问题还是我的代码是如何配置的.我无法通过 Google 找到任何其他报告的案例(可能是因为我还是 Django 的新手,尽管遵循了以下教程,但不确定配置是否正确).

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.

有这个问题,但我没有使用 ImageField,我想为我使用 FileField 的情况找到解决方案.对主要问题的评论表明也不需要添加端口,所以它可能是基础设施问题而不是 Django 问题?这方面的指导会很棒.

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

推荐答案

感谢 这个问题 略有不同.

解决方案 1

在nginx配置的Host头中添加端口号如下:

Add the port number in the Host header in the nginx config as follows:

    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 如下:

Change the Host header in the nginx config to http_host as follows:

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

无论哪种情况,DRF 现在都会按如下方式返回图像 URL(图像链接).

In either case, the image URLs are now returned as follows by DRF (image link).

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"
        }
    ]
}

这篇关于如何在Django中的资源URL中的IP地址后输出端口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-26 02:22