2016-01-25 9 views
16

Chcę wysyłać maile w zadaniu cron. Wiadomość powinna zawierać link do mojej aplikacji.Jak mogę uzyskać adres URL (z protokołem i domeną) w Django (bez żądania)?

W zadaniu cron nie mam obiektu żądania i nie można użyć request.build_absolute_uri().

AFAIK w ramach serwisu może pomóc tutaj. Ale nie daje mi protokołu (http vs https)?

Moja aplikacja jest wielokrotnego użytku i czasami jest hostowana na http, a czasem na stronach https.

Aktualizacja

wyszukiwać wspólnego django sposób. Tworzenie własnych ustawień jest możliwe, ale preferowane jest rozwiązanie ze standardami django.

Powiązane problem: https://code.djangoproject.com/ticket/16734

+0

Ile różnych domen obsługuje jedna instancja Django? –

+0

@AlexMorozov w moim bieżącym kontekście jeden pojedynczy serwer instancji Django tylko jedna domena. Ale aplikacja jest zainstalowana na wielu różnych serwerach. Niektóre serwują przez http, a niektóre przez https. – guettli

+0

Używam ustawień do obsługi w takim scenariuszu, szczególnie gdy nie mam obiektu żądania. Coś jak ustawienia.HOST_ADDRESS + "{0}". Format (resource_path) powinien wykonać zadanie. Powinno być możliwe wielokrotne użycie przy zmianie konfiguracji minimalnej poprzez rozszerzenie ustawień podstawowych do różnych plików ustawień używanych w konkretnej witrynie (np .: --settings = settings.site1) – rreddy

Odpowiedz

8

Do tego zadania jest specjalny standardowy moduł - Sites Framework. Dodaje model witryny, który opisuje konkretną witrynę. Ten model ma pole domain dla domeny projektu i name - czytelną dla człowieka nazwę witryny.

Powiązanie modeli ze stronami. Tak:

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) 

Kiedy trzeba dokonać URL dla obiektu można użyć coś jak następującego kodu:

>>> 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/' 

W ten sposób można mieć wiele domen i rozpowszechniania treści między nimi. Nawet jeśli masz tylko jedną domenę, polecam jej użycie, aby osiągnąć dobry, wygodny i wygodny sposób na zachowanie ustawień domeny.

Installatioin jest dość proste:

  1. Dodaj 'django.contrib.sites' z ustawieniami INSTALLED_APPS.

  2. Zdefiniuj ustawienia site_id:

    SITE_ID = 1 
    
  3. Run przeniesiony.

+1

Wygląda ładnie. Brakuje jednej części: używasz "https". Gdzie jest wspólne miejsce do konfiguracji schematu http, aby aplikacja wielokrotnego użytku mogła przyjąć tę wartość bez zgadywania? – guettli

+3

Na razie nie ma takiego miejsca. Myślę, że protokół powinien być przechowywany wraz z witryną. Jest problem i łatka w systemie biletowym django - https://code.djangoproject.com/ticket/26079#no1 Mam nadzieję, że później zostanie on przyjęty i stanie się standardowym sposobem. Teraz możemy podklasować model strony i rozszerzyć go o wymagane pola. Jako tymczasowe obejście można zapisać protokół w pliku settings.py, ponieważ zmienia się bardzo rzadko. –

+0

Dziękujemy za podanie linku do biletu django. Miło widzieć, że to jeszcze nie rozwiązany problem. – guettli

16

TL; DR: Nie ma żadnego „standard” „Django-owski” sposób to robić, ale suchej zasada promowana przez ramy zakłada sklep pojedynczej konfiguracji, więc ustawienie niestandardowe wydaje się być dobrym rozwiązaniem.

Domyślnie Django może obsługiwać dowolną liczbę domen z jednej instancji, a żądanie HTTP (dokładniej jego nagłówek HTTP_HOST) jest jedyną rzeczą, której Django używa do określenia bieżącego hosta. Jak twoi crona są oczywiście z cyklu HTTP, należy zapisać swoją domenę gdzieś w ustawieniach ...

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

... z małym procesora kontekstowego, aby łatwiej poradzić templating:

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

def default_domain(request): 
    return {'default_domain': settings.DEFAULT_DOMAIN} 

... a następnie używać go w wiadomości e-mail:

# yourapp/templates/email/body.html 
<a href="{{ default_domain }}{% url 'target' %}">Click here</a> 

Alternatywnie można skorzystać z ram sites, ale jeśli służąc sing le domain, rozwiązanie oparte na ustawieniach wydaje mi się dużo prostsze i czystsze.

+0

"DEFAULT_DOMAIN" jest ustawieniem niestandardowym? Nie mogłem go znaleźć tutaj: https://docs.djangoproject.com/es/1.9/topics/settings/ – guettli

+0

@guettli, tak, jest to ustawienie niestandardowe, które właśnie zilustrowałem, aby zilustrować rozwiązanie. Nazwij to, jak ci się podoba i ustaw go na jakimkolwiek hoście, z którego korzystasz. Domyślnie Django nie wie nic o "domyślnej" domenie tylko dlatego, że czegoś takiego nie ma - możesz użyć 'https' i' http', obsługiwać wiele domen (być może nawet z subdomenami) i tak dalej. Zgadzam się, że jest to nieco mylące, ale jest to cena elastyczności, którą Django oferuje natychmiast po uruchomieniu. –

Powiązane problemy