models.py 3.8 KB

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