You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

116 lines
3.7 KiB

  1. from __future__ import unicode_literals
  2. import string
  3. from django.core.exceptions import ImproperlyConfigured, ValidationError
  4. from django.db import models
  5. from django.db.models.signals import pre_delete, pre_save
  6. from django.http.request import split_domain_port
  7. from django.utils.encoding import python_2_unicode_compatible
  8. from django.utils.translation import ugettext_lazy as _
  9. SITE_CACHE = {}
  10. def _simple_domain_name_validator(value):
  11. """
  12. Validates that the given value contains no whitespaces to prevent common
  13. typos.
  14. """
  15. if not value:
  16. return
  17. checks = ((s in value) for s in string.whitespace)
  18. if any(checks):
  19. raise ValidationError(
  20. _("The domain name cannot contain any spaces or tabs."),
  21. code='invalid',
  22. )
  23. class SiteManager(models.Manager):
  24. use_in_migrations = True
  25. def _get_site_by_id(self, site_id):
  26. if site_id not in SITE_CACHE:
  27. site = self.get(pk=site_id)
  28. SITE_CACHE[site_id] = site
  29. return SITE_CACHE[site_id]
  30. def _get_site_by_request(self, request):
  31. host = request.get_host()
  32. try:
  33. # First attempt to look up the site by host with or without port.
  34. if host not in SITE_CACHE:
  35. SITE_CACHE[host] = self.get(domain__iexact=host)
  36. return SITE_CACHE[host]
  37. except Site.DoesNotExist:
  38. # Fallback to looking up site after stripping port from the host.
  39. domain, port = split_domain_port(host)
  40. if not port:
  41. raise
  42. if domain not in SITE_CACHE:
  43. SITE_CACHE[domain] = self.get(domain__iexact=domain)
  44. return SITE_CACHE[domain]
  45. def get_current(self, request=None):
  46. """
  47. Returns the current Site based on the SITE_ID in the project's settings.
  48. If SITE_ID isn't defined, it returns the site with domain matching
  49. request.get_host(). The ``Site`` object is cached the first time it's
  50. retrieved from the database.
  51. """
  52. from django.conf import settings
  53. if getattr(settings, 'SITE_ID', ''):
  54. site_id = settings.SITE_ID
  55. return self._get_site_by_id(site_id)
  56. elif request:
  57. return self._get_site_by_request(request)
  58. raise ImproperlyConfigured(
  59. "You're using the Django \"sites framework\" without having "
  60. "set the SITE_ID setting. Create a site in your database and "
  61. "set the SITE_ID setting or pass a request to "
  62. "Site.objects.get_current() to fix this error."
  63. )
  64. def clear_cache(self):
  65. """Clears the ``Site`` object cache."""
  66. global SITE_CACHE
  67. SITE_CACHE = {}
  68. @python_2_unicode_compatible
  69. class Site(models.Model):
  70. domain = models.CharField(_('domain name'), max_length=100,
  71. validators=[_simple_domain_name_validator], unique=True)
  72. name = models.CharField(_('display name'), max_length=50)
  73. objects = SiteManager()
  74. class Meta:
  75. db_table = 'django_site'
  76. verbose_name = _('site')
  77. verbose_name_plural = _('sites')
  78. ordering = ('domain',)
  79. def __str__(self):
  80. return self.domain
  81. def clear_site_cache(sender, **kwargs):
  82. """
  83. Clears the cache (if primed) each time a site is saved or deleted
  84. """
  85. instance = kwargs['instance']
  86. using = kwargs['using']
  87. try:
  88. del SITE_CACHE[instance.pk]
  89. except KeyError:
  90. pass
  91. try:
  92. del SITE_CACHE[Site.objects.using(using).get(pk=instance.pk).domain]
  93. except (KeyError, Site.DoesNotExist):
  94. pass
  95. pre_save.connect(clear_site_cache, sender=Site)
  96. pre_delete.connect(clear_site_cache, sender=Site)