Django:在没有请求对象的情况下获取绝对URL

24 投票
2 回答
14930 浏览
提问于 2025-04-16 06:52

我有一个模型,像下面这样。当创建一个实例时,我想给相关人员发一封电子邮件:

class TrainStop(models.Model):
    name = models.CharField(max_length=32)
    notify_email = models.EmailField(null=True, blank=True)

def new_stop_created(sender, instance, created, *args, **kwargs):

    # Only for new stops
    if not created or instance.id is None: return

    # Send the status link
    if instance.notify_email:
        send_mail(
            subject='Stop submitted: %s' % instance.name,
            message='Check status: %s' % reverse('stop_status', kwargs={'status_id':str(instance.id),}),
            from_email='admin@example.com',
            recipient_list=[instance.notify_email,]
        )
signals.post_save.connect(new_stop_created, sender=TrainStop)

但是,reverse这个调用只返回了URL的路径部分。例如:/stops/9/status/。我需要一个完整的URL,比如http://example.com/stops/9/status/。我该如何获取当前网站的主机名和端口(对于不使用80端口的测试实例)呢?

我最初的想法是通过在settings.py中设置一个变量来实现,这样我就可以根据需要访问它。不过,我想也许有人会有更好的建议。

2 个回答

4

要获取当前网站的信息,可以使用一个叫做Site的对象:

如果你无法访问请求对象,可以使用Site模型管理器的get_current()方法。你需要确保你的设置文件中包含SITE_ID这个设置。这个例子和前面的例子是一样的:

from django.contrib.sites.models import Site

def my_function_without_request():
    current_site = Site.objects.get_current()
    if current_site.domain == 'foo.com':
        # Do something
        pass
    else:
        # Do something else.
        pass

更多信息请查看: http://docs.djangoproject.com/en/dev/ref/contrib/sites/

5

正如yedpodtrzitko提到的,有一个网站框架,但正如你所说,这个设置过程还是比较手动的。

在settings.py里有一个设置,但这个设置的手动程度也只比网站框架稍微好一点。它可以处理多个域名,就像网站框架和SITE_ID设置一样。

有一个想法是关于替换get_absolute_url的,这样可以让类似的事情变得简单一些,不过我觉得它的实现也面临同样的问题,比如如何获取域名、协议(http还是https)等等。

我一直在考虑一个中间件的想法,它可以检查进来的请求,并根据HTTP HOST头的值出现的频率来构建一个“最可能的域名”设置。或者它可以在每个请求中单独设置这个值,这样你就总是能使用当前的域名。我还没有认真研究这个想法,但这是一个值得考虑的方向。

撰写回答