【问题标题】:How can I get the full/absolute URL (with domain) in Django?如何在 Django 中获取完整/绝对 URL(带域)?
【发布时间】:2011-01-21 16:31:59
【问题描述】:

如何在 Django without the Sites module 中获取完整/绝对 URL(例如 https://example.com/some/path)?这太傻了……我不需要查询我的数据库来获取 URL!

我想将它与reverse() 一起使用。

【问题讨论】:

标签: django


【解决方案1】:

根据要求使用方便的request.build_absolute_uri() 方法,将相关网址传递给它,它会给你一个完整的。

默认情况下,返回request.get_full_path() 的绝对 URL,但您可以将相对 URL 作为第一个参数传递给它以将其转换为绝对 URL。

>>> request.build_absolute_uri()
'https://example.com/music/bands/the_beatles/?print=true'
>>> request.build_absolute_uri('/bands/?print=true')
'https://example.com/bands/?print=true'

【讨论】:

  • 网址:localhost/home/#/test 怎么样?我只能看到localhost/home。我怎样才能看到 sharp 之后的部分?
  • # 之后的所有内容都不会传递给服务器,它是浏览器独有的功能
  • 在模板中(不能提供参数)你可以这样做:{{ request.build_absolute_uri }}{{ object.get_absolute_url }} - 嘿嘿,完整的网址。
  • 如果我无权访问请求怎么办?就像在 Django-REST-Framework 的序列化器中一样?
  • 我不得不使用{% if request.is_secure %}https://{% else %}http://{% endif %}{{ request.get_host }}{{ object.get_absolute_url }},因为{{ request.build_absolute_uri }} 有一个斜杠,而{{ object.get_absolute_url }} 以斜杠开头,导致URL 中出现双斜杠。
【解决方案2】:

在处理一个项目时,我开始知道在 Django 中获取完整/绝对 URL。

如果您的网址在地址栏中如下所示:

https://stackoverflow.com/questions/2345708

如果您想在模板中显示上述 URL。

  1. {{ request.path }}#Without GET parameters.
  2. {{ request.get_full_path }}#with GET parameters

对于以上两个代码,这将在你的模板中打印出来

questions/2345708

另一种获取完整网址的方法是:

  • {{request.build_absolute_uri}}

这将在您的模板中打印:

https://stackoverflow.com/questions/2345708

【讨论】:

    【解决方案3】:

    不是绝对网址,但我只是想获得主机。如果您想在 view.py 中获得主机,您可以这样做

    def my_view(request):
       host = f"{ request.scheme }://{ request.META.get('HTTP_HOST') }"
    

    【讨论】:

      【解决方案4】:
      class WalletViewSet(mixins.ListModelMixin, GenericViewSet):
          serializer_class = WalletSerializers
          pagination_class = CustomPaginationInvestment
      
          def get_queryset(self):
      
              ######################################################
              print(self.request.build_absolute_uri())
              #####################################################
      
              wallet, created = Wallet.objects.get_or_create(owner=self.request.user)
              return Wallet.objects.filter(id=wallet.id)
      

      你会得到这样的输出

      http://localhost:8000/v1/wallet
      HTTP GET /v1/wallet 200 [0.03, 127.0.0.1:41608]
      

      【讨论】:

        【解决方案5】:

        如果有人有兴趣在 模板中 获取带有参数的绝对反向 url,最简洁的方法是创建自己的绝对版本的 {% url %} 模板标签通过扩展和使用现有的默认代码。

        这是我的代码:

        from django import template
        from django.template.defaulttags import URLNode, url
        
        register = template.Library()
        
        class AbsURLNode(URLNode):
            def __init__(self, view_name, args, kwargs, asvar):
                super().__init__(view_name, args, kwargs, asvar)
        
            def render(self, context):
                url     = super().render(context)
                request = context['request']
        
                return request.build_absolute_uri(url)
        
        
        @register.tag
        def abs_url(parser, token):
        
            urlNode = url(parser, token)
            return AbsURLNode( urlNode.view_name, urlNode.args, urlNode.kwargs, urlNode.asvar  )
        

        在模板中的使用:

        {% load wherever_your_stored_this_tag_file %}
        {% abs_url 'view_name' parameter %}
        

        将呈现(示例):

        http://example.com/view_name/parameter/
        

        而不是

        /view_name/parameter/
        

        【讨论】:

          【解决方案6】:
          <div class='col-12 col-md-6'>
              <p class='lead'>Login</p>
              {% include 'accounts/snippets/form.html' with form=login_form next_url=request.build_absolute_uri %}
          </div>
          

          例如,这里是说加载表单并告诉表单下一个 URL 是此代码从中生成的当前 URL

          【讨论】:

          • 所以基本上 request.build_absolute_uri 将构建当前位置的 URL
          【解决方案7】:

          试试下面的代码:

          {{ request.scheme }}://{{ request.META.HTTP_HOST }}
          

          【讨论】:

          • 那只会给出没有路径和查询字符串的域,不是吗?
          【解决方案8】:

          您可以传递请求 reverse('view-name', request=request) 或将 reverse() 包含在 build_absolute_uri request.build_absolute_uri(reverse('view-name'))

          【讨论】:

          • 我得到的第一个建议:reverse() got an unexpected keyword argument 'request'
          【解决方案9】:

          这在我的模板中对我有用:

          {{ request.scheme }}://{{ request.META.HTTP_HOST }}{% url 'equipos:marca_filter' %}
          

          我需要完整的 url 将其传递给 js fetch 函数。 希望对您有所帮助。

          【讨论】:

            【解决方案10】:

            我遇到了这个线程,因为我想为成功页面构建一个绝对 URI。 request.build_absolute_uri() 给了我当前视图的 URI,但为了获取我的成功视图的 URI,我使用了以下内容....

            request.build_absolute_uri(reverse('success_view_name'))

            【讨论】:

              【解决方案11】:

              正如其他答案中提到的,如果您可以访问requestrequest.build_absolute_uri() 是完美的,只要不同的 URL 指向不同的数据库,sites 框架就很棒。

              但是,我的用例略有不同。我的登台服务器和生产服务器访问同一个数据库,但get_current_site 都返回了数据库中的第一个site。要解决此问题,您必须使用某种环境变量。您可以使用 1) 环境变量(类似于 os.environ.get('SITE_URL', 'localhost:8000'))或 2) 不同服务器的不同 SITE_IDs 和 different settings.py

              希望有人会觉得这很有用!

              【讨论】:

                【解决方案12】:

                还有 ABSOLUTE_URL_OVERRIDES 可用作设置

                https://docs.djangoproject.com/en/2.1/ref/settings/#absolute-url-overrides

                但这会覆盖 get_absolute_url(),这可能是不可取的。

                与其只为此安装站点框架或做一些这里提到的依赖请求对象的其他东西,我认为更好的解决方案是将它放在 models.py 中

                在 settings.py 中定义 BASE_URL,然后将其导入 models.py 并创建一个定义 get_truly_absolute_url() 的抽象类(或将其添加到您已经在使用的类中)。可以这么简单:

                def get_truly_absolute_url(self):
                    return BASE_URL + self.get_absolute_url()
                

                子类化它,现在你可以在任何地方使用它。

                【讨论】:

                  【解决方案13】:

                  如果您不想访问数据库,可以通过设置来完成。然后,使用上下文处理器将其添加到每个模板:

                  # settings.py (Django < 1.9)
                  ...
                  BASE_URL = 'http://example.com'
                  TEMPLATE_CONTEXT_PROCESSORS = (
                      ...
                      'myapp.context_processors.extra_context',
                  )
                  # settings.py (Django >= 1.9)
                  TEMPLATES = [
                      {
                          'BACKEND': 'django.template.backends.django.DjangoTemplates',
                          'DIRS': [],
                          'APP_DIRS': True,
                          'OPTIONS': {
                              'context_processors': [
                                  'django.template.context_processors.debug',
                                  'django.template.context_processors.request',
                                  'django.contrib.auth.context_processors.auth',
                                  'django.contrib.messages.context_processors.messages',
                                  # Additional
                                  'myapp.context_processors.extra_context',
                              ],
                          },
                      },
                  ]
                  
                  # myapp/context_processors.py
                  from django.conf import settings
                  
                  def extra_context(request):
                      return {'base_url': settings.BASE_URL}
                  
                  # my_template.html
                  <p>Base url is {{ base_url }}.</p>
                  

                  【讨论】:

                  • 好东西。这结合 .env 更好地满足我的用例。
                  【解决方案14】:

                  如果您无法访问request,则您不能按照此处某些解决方案中的建议使用get_current_site(request)。您可以改用本机站点框架和get_absolute_url 的组合。在后台设置至少一个Site,确保你的模型有get_absolute_url()方法,然后:

                  >>> from django.contrib.sites.models import Site
                  >>> domain = Site.objects.get_current().domain
                  >>> obj = MyModel.objects.get(id=3)
                  >>> path = obj.get_absolute_url()
                  
                  >>> url = 'http://{domain}{path}'.format(domain=domain, path=path)
                  >>> print(url)
                  'http://example.com/mymodel/objects/3/'
                  

                  https://docs.djangoproject.com/en/dev/ref/contrib/sites/#getting-the-current-domain-for-full-urls

                  【讨论】:

                  • 当您无法访问 HttpRequest 对象时,这非常方便。例如在任务、信号等方面。
                  • 在使用它之前你应该启用站点框架docs.djangoproject.com/en/dev/ref/contrib/sites/…
                  • 要将 example.com 也更改为:Site.objects.all()[0] 返回 'example.com' 并且 id=1,在 settings.py 中指定。只需执行 Site.objects.create(name='production', domain='prodsite.com') 并在 settings.py 中设置 SITE_ID=2。现在 Site.objects.get_current().domain 返回 'prodsite.com'。
                  • 您可以将request设置为None或致电get_current_site(None)
                  • 我的开发域是“127.0.0.1:8000”,生产域是“paidfor.pythonanywhere.com”。我希望我的 Django 自己找到它在哪个域上运行。
                  【解决方案15】:

                  django-fullurl

                  如果您尝试在 Django 模板中执行此操作,我发布了一个小型 PyPI 包 django-fullurl,让您可以将 urlstatic 模板标签替换为 fullurlfullstatic,例如这个:

                  {% load fullurl %}
                  
                  Absolute URL is: {% fullurl "foo:bar" %}
                  
                  Another absolute URL is: {% fullstatic "kitten.jpg" %}
                  

                  这些徽章有望自动保持最新状态:

                  在视图中,当然可以使用request.build_absolute_uri 代替。

                  【讨论】:

                  • 遗憾的是,这不适用于 2.0。可能需要推一个 PR。
                  • @StevenChurch 它应该可以工作。我尚未将 Django 2.0 标记为受支持,但现有版本应该可以工作。
                  • 为了我的需要,我通过从 Heroku 传递一个 ENV 进行故障回复来解决这个问题。我的问题是让 URL 传递给电子邮件模板。我不记得这个问题了,但由于 Django 的变化它没有工作。
                  • @StevenChurch 我认为创建电子邮件时的问题是没有request 对象可以从中获取域名。在这种情况下,您应该改用sites 框架,它从数据库中获取域名。请参阅django-absoluteuri,在此 PyPI 包的 README 的“另请参阅”部分中提到。
                  【解决方案16】:

                  在您看来,只需这样做:

                  base_url =  "{0}://{1}{2}".format(request.scheme, request.get_host(), request.path)
                  

                  【讨论】:

                    【解决方案17】:

                    如果您使用的是 django REST 框架,则可以使用来自 rest_framework.reverse 的反向功能。这与django.core.urlresolvers.reverse 的行为相同,只是它使用请求参数来构建完整的 URL。

                    from rest_framework.reverse import reverse
                    
                    # returns the full url
                    url = reverse('view_name', args=(obj.pk,), request=request)
                    
                    # returns only the relative url
                    url = reverse('view_name', args=(obj.pk,))
                    

                    已编辑以仅在 REST 框架中提及可用性

                    【讨论】:

                    • 我在使用 request=request 时遇到错误。这里似乎也没有记录请求docs.djangoproject.com/en/1.9/ref/urlresolvers/#reverse
                    • 我忘了提到这仅在您使用 REST 框架时可用。很好,我已经更新了我的答案。
                    • 是的,谢谢 - 这就像 django REST framework 的魅力
                    【解决方案18】:

                    我明白了:

                    wsgiref.util.request_uri(request.META)
                    

                    获取包含架构、主机、端口路径和查询的完整 uri。

                    【讨论】:

                      【解决方案19】:

                      你也可以使用:

                      import socket
                      socket.gethostname()
                      

                      这对我来说很好用,

                      我不完全确定它是如何工作的。我相信这有点低级别,并且会返回您的服务器主机名,这可能与您的用户用于访问您的页面的主机名不同。

                      【讨论】:

                      • 是的..你指出了问题。主机名不一定与域名相同。
                      • 这解决了一个非常不同的问题。考虑一个具有多个网站的共享托管服务器 - 使用上面的代码,所有生成 URL 的站点都将具有指向主机的所有此类 URL,这可能不是任何正在运行的网站。
                      【解决方案20】:

                      您还可以将get_current_site 用作网站应用程序的一部分 (from django.contrib.sites.models import get_current_site)。它接受一个请求对象,如果请求是None,则默认为您在settings.py 中使用SITE_ID 配置的站点对象。在using the sites framework的文档中阅读更多内容

                      例如

                      from django.contrib.sites.shortcuts import get_current_site
                      request = None
                      full_url = ''.join(['http://', get_current_site(request).domain, obj.get_absolute_url()])
                      

                      它不像request.build_absolute_url() 那样简洁/简洁,但是当请求对象不可用并且你有一个默认站点 URL 时它是可用的。

                      【讨论】:

                      • 我相信我的问题特别提到了“没有站点模块”。这会影响数据库吗?
                      • Sites 模块已被写入使用模块级缓存来缓存 Site 对象(即您不需要缓存框架),因此数据库应该只在站点第一次被网络进程。如果您的INSTALLED_APPS 中没有django.contrib.sites,则它根本不会访问数据库,并根据请求对象提供信息(请参阅get_current_site
                      • 那么您可以 +1,但 build_absolute_uri 看起来仍然是更简单、更清洁的解决方案。
                      • 如果您尝试在信号中生成 URL 以从中发送电子邮件,这是一个完美的答案。
                      • 如果您使用 https,则不起作用。是的,您可以添加 s,但是您是否在本地使用 https 进行开发?你是否总是知道,如果你有 https 但有时没有......?
                      【解决方案21】:

                      request.get_host() 会给你域名。

                      【讨论】:

                      • 问题说明,完整网址
                      【解决方案22】:

                      我知道这是一个老问题。但我认为人们仍然经常遇到这种情况。

                      有几个库可以补充默认的 Django 功能。我已经尝试了一些。反向引用绝对网址时,我喜欢以下库:

                      https://github.com/fusionbox/django-absoluteuri

                      我喜欢的另一个是:

                      https://github.com/RRMoelker/django-full-url

                      这个库允许您在模板中简单地编写您想要的内容,例如:

                      {{url_parts.domain}}
                      

                      【讨论】:

                        【解决方案23】:

                        另一种方式。您可以在 view.py 中使用 build_absolute_uri() 并将其传递给模板。

                        view.py

                        def index(request):
                            baseurl = request.build_absolute_uri()
                            return render_to_response('your-template.html', { 'baseurl': baseurl })
                        

                        your-template.html

                        {{ baseurl }}
                        

                        【讨论】:

                        • HttpRequest.build_absolute_uri(request) 等价于request.build_absolute_uri() 不是吗?
                        【解决方案24】:

                        要从模板创建到另一个页面的完整链接,您可以使用:

                        {{ request.META.HTTP_HOST }}{% url 'views.my_view' my_arg %}
                        

                        request.META.HTTP_HOST 给出主机名,url 给出相对名称。然后模板引擎将它们连接成一个完整的 url。

                        【讨论】:

                        【解决方案25】:

                        如果您想将它与reverse() 一起使用,您可以这样做:request.build_absolute_uri(reverse('view_name', args=(obj.pk, )))

                        【讨论】:

                        • 感谢您的帮助。没有什么比代码本身更好的了。 (另外,您可能指的是url_name 而不是view_name
                        • @Anupam reverse() 定义为:def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
                        • @ébewè 如何在模板中使用它?
                        • 如果有人感兴趣,如果你不需要任何参数,你可以省略args=(obj.pk, )部分。帮助了我!
                        • 感谢小伙伴的帮助,非常感谢。
                        【解决方案26】:

                        你可以试试“request.get_full_path()”

                        【讨论】:

                        • 这不包括域。
                        【解决方案27】:

                        检查传入的Request.META 字典。我认为它有服务器名称和服务器端口。

                        【讨论】:

                        猜你喜欢
                        • 2013-07-25
                        • 2013-04-08
                        • 1970-01-01
                        • 1970-01-01
                        • 2012-05-06
                        • 2022-12-23
                        • 1970-01-01
                        相关资源
                        最近更新 更多