如何在Django中获取URL(带有协议和域)(没有请求)?

gue*_*tli 23 django url cron

我想在cron工作中发送邮件.邮件应包含指向我的应用程序的链接.

在cron作业中,我没有请求对象,也不能使用request.build_absolute_uri().

AFAIK的站点框架可以在这里提供帮助.但是没有给我协议(http vs https)?

我的应用程序是可重用的,有时会在http和有时在https网站上托管.

更新

我搜索一个常见的django方式.可以创建自定义设置,但首选django标准的解决方案.

相关问题:https://code.djangoproject.com/ticket/16734

Ale*_*zov 22

TL; DR:没有任何"标准""Django-ish"这样做的方式,但框架推广的DRY原则假设单一配置存储,因此自定义设置似乎是一个好方法.

默认情况下,Django可以从单个实例为任意数量的域提供服务,而HTTP请求(更准确地说,它的HTTP_HOST标头)是Django用来确定当前主机的唯一内容.由于您的cron作业显然不属于HTTP周期,因此您应该将域存储在设置中的某个位置...

# settings.py
DEFAULT_DOMAIN = 'https://foobar.com'
# or, depending on your configuration:
DEFAULT_DOMAIN = 'https://{}'.format(ALLOWED_HOSTS[0])
Run Code Online (Sandbox Code Playgroud)

...使用小型上下文处理器,可以更轻松地处理模板:

# yourapp/context_processors.py
from django.conf import settings

def default_domain(request):
    return {'default_domain': settings.DEFAULT_DOMAIN}
Run Code Online (Sandbox Code Playgroud)

...然后在电子邮件中使用它:

# yourapp/templates/email/body.html
<a href="{{ default_domain }}{% url 'target' %}">Click here</a>
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用sites框架,但如果您正在为单个域提供服务,那么基于设置的解决方案对我来说似乎更简单,更清晰.

  • @guettli,对,这是我刚刚为了说明解决方案而编写的自定义设置。按照您喜欢的方式命名并将其设置为您正在使用的任何主机。默认情况下,Django 对“默认”域一无所知,因为不存在这样的东西 - 您可以使用“https”和“http”,服务多个域(甚至可能有子域)等等。我同意这有点令人困惑,但这就是 Django 提供的开箱即用的灵活性的代价。 (2认同)

Eug*_*sky 15

这项任务有一个特殊的标准模块 - Sites Framework.它添加了Site模型,它描述了特定的站点.该模型具有domain项目域的字段,以及name- 人类可读的站点名称.

您将模型与网站相关联.像这样:

from django.db import models
from django.contrib.sites.models import Site

class Article(models.Model):
    headline = models.CharField(max_length=200)
    # ...
    site = models.ForeignKey(Site, on_delete=models.CASCADE)
Run Code Online (Sandbox Code Playgroud)

当您需要为对象创建URL时,您可以使用以下代码:

   >>> from django.contrib.sites.models import Site
   >>> obj = MyModel.objects.get(id=3)
   >>> obj.get_absolute_url()
   '/mymodel/objects/3/'
   >>> Site.objects.get_current().domain
   'example.com'
   >>> 'https://%s%s' % (Site.objects.get_current().domain, obj.get_absolute_url())
   'https://example.com/mymodel/objects/3/'
Run Code Online (Sandbox Code Playgroud)

这样,您可以在它们之间传播多个域和内容.即使您只有一个域名,我也建议您使用它来实现保持域名设置的良好标准.

安装非常简单:

  1. 添加'django.contrib.sites'到您的INSTALLED_APPS设置.

  2. 定义SITE_ID设置:

     SITE_ID = 1
    
    Run Code Online (Sandbox Code Playgroud)
  3. 运行迁移.

  • 现在没有这样的地方.我认为协议应该与网站一起存储.django票务系统中存在问题和补丁 - https://code.djangoproject.com/ticket/26079#no1我希望以后它会被采用并成为一种标准方式.现在我们可以继承Site模型并使用必填字段扩展它.作为临时解决方法,可以在settings.py中存储协议​​,因为它很少变化. (3认同)
  • 看起来不错。缺少一部分:您使用“ https”。配置http方案的常见位置在哪里,以便可重复使用的应用程序可以毫无疑问地获取此值? (2认同)