Ticket #14386: 14386.diff

File 14386.diff, 21.6 KB (added by gabrielhurley, 5 years ago)

Updated to fix #14377 as well. Uses get_current_site() in contrib.auth.views.logout to make site accessible to logout template as in login view.

  • django/contrib/auth/forms.py

     
    11from django.contrib.auth.models import User
    22from django.contrib.auth import authenticate
    33from django.contrib.auth.tokens import default_token_generator
    4 from django.contrib.sites.models import Site
     4from django.contrib.sites.models import get_current_site
    55from django.template import Context, loader
    66from django import forms
    77from django.utils.translation import ugettext_lazy as _
     
    117117        return email
    118118
    119119    def save(self, domain_override=None, email_template_name='registration/password_reset_email.html',
    120              use_https=False, token_generator=default_token_generator, from_email=None):
     120             use_https=False, token_generator=default_token_generator, from_email=None, request=None):
    121121        """
    122122        Generates a one-use only link for resetting password and sends to the user
    123123        """
    124124        from django.core.mail import send_mail
    125125        for user in self.users_cache:
    126126            if not domain_override:
    127                 current_site = Site.objects.get_current()
     127                current_site = get_current_site(request)
    128128                site_name = current_site.name
    129129                domain = current_site.domain
    130130            else:
  • django/contrib/auth/views.py

     
    1010from django.views.decorators.csrf import csrf_protect
    1111from django.core.urlresolvers import reverse
    1212from django.shortcuts import render_to_response, get_object_or_404
    13 from django.contrib.sites.models import Site, RequestSite
     13from django.contrib.sites.models import Site, RequestSite, get_current_site
    1414from django.http import HttpResponseRedirect, Http404
    1515from django.template import RequestContext
    1616from django.utils.http import urlquote, base36_to_int
     
    5454   
    5555    request.session.set_test_cookie()
    5656   
    57     if Site._meta.installed:
    58         current_site = Site.objects.get_current()
    59     else:
    60         current_site = RequestSite(request)
     57    current_site = get_current_site(request)
    6158   
    6259    return render_to_response(template_name, {
    6360        'form': form,
     
    7572        if redirect_to:
    7673            return HttpResponseRedirect(redirect_to)
    7774        else:
     75            current_site = get_current_site(request)
    7876            return render_to_response(template_name, {
     77                'site': current_site,
     78                'site_name': current_site.name,
    7979                'title': _('Logged out')
    8080            }, context_instance=RequestContext(request))
    8181    else:
     
    115115            opts['use_https'] = request.is_secure()
    116116            opts['token_generator'] = token_generator
    117117            opts['from_email'] = from_email
     118            opts['email_template_name'] = email_template_name
     119            opts['request'] = request
    118120            if is_admin_site:
    119121                opts['domain_override'] = request.META['HTTP_HOST']
    120             else:
    121                 opts['email_template_name'] = email_template_name
    122                 if not Site._meta.installed:
    123                     opts['domain_override'] = RequestSite(request).domain
    124122            form.save(**opts)
    125123            return HttpResponseRedirect(post_reset_redirect)
    126124    else:
  • django/contrib/contenttypes/tests.py

     
    1 """
    2 Make sure that the content type cache (see ContentTypeManager) works correctly.
    3 Lookups for a particular content type -- by model or by ID -- should hit the
    4 database only on the first lookup.
     1from django import db
     2from django.conf import settings
     3from django.contrib.contenttypes.models import ContentType
     4from django.contrib.sites.models import Site, get_current_site
     5from django.contrib.contenttypes.views import shortcut
     6from django.core.exceptions import ObjectDoesNotExist
     7from django.http import HttpRequest
     8from django.test import TestCase
    59
    6 First, let's make sure we're dealing with a blank slate (and that DEBUG is on so
    7 that queries get logged)::
    8 
    9     >>> from django.conf import settings
    10     >>> settings.DEBUG = True
    11 
    12     >>> from django.contrib.contenttypes.models import ContentType
    13     >>> ContentType.objects.clear_cache()
    14 
    15     >>> from django import db
    16     >>> db.reset_queries()
     10class ContentTypesTests(TestCase):
     11    def setUp(self):
     12        # First, let's make sure we're dealing with a blank slate (and that
     13        # DEBUG is on so that queries get logged)
     14        settings.DEBUG = True
     15        ContentType.objects.clear_cache()
     16        db.reset_queries()
    1717   
    18 At this point, a lookup for a ContentType should hit the DB::
    19 
    20     >>> ContentType.objects.get_for_model(ContentType)
    21     <ContentType: content type>
     18    def test_lookup_cache(self):
     19        """Make sure that the content type cache (see ContentTypeManager)
     20        works correctly. Lookups for a particular content type -- by model or
     21        by ID -- should hit the database only on the first lookup."""
     22       
     23        #At this point, a lookup for a ContentType should hit the DB
     24        ContentType.objects.get_for_model(ContentType)
     25        self.assertEqual(1, len(db.connection.queries))
     26       
     27        #A second hit, though, won't hit the DB, nor will a lookup by ID
     28        ct = ContentType.objects.get_for_model(ContentType)
     29        self.assertEqual(1, len(db.connection.queries))
     30        ContentType.objects.get_for_id(ct.id)
     31        self.assertEqual(1, len(db.connection.queries))
     32       
     33        #Once we clear the cache, another lookup will again hit the DB
     34        ContentType.objects.clear_cache()
     35        ContentType.objects.get_for_model(ContentType)
     36        len(db.connection.queries)
     37        self.assertEqual(2, len(db.connection.queries))
    2238   
    23     >>> len(db.connection.queries)
    24     1
    25 
    26 A second hit, though, won't hit the DB, nor will a lookup by ID::
    27 
    28     >>> ct = ContentType.objects.get_for_model(ContentType)
    29     >>> len(db.connection.queries)
    30     1
    31     >>> ContentType.objects.get_for_id(ct.id)
    32     <ContentType: content type>
    33     >>> len(db.connection.queries)
    34     1
    35 
    36 Once we clear the cache, another lookup will again hit the DB::
    37 
    38     >>> ContentType.objects.clear_cache()
    39     >>> ContentType.objects.get_for_model(ContentType)
    40     <ContentType: content type>
    41     >>> len(db.connection.queries)
    42     2
    43 
    44 Don't forget to reset DEBUG!
    45 
    46     >>> settings.DEBUG = False
    47 """
    48  No newline at end of file
     39    def test_shortcut_view(self):
     40        ''' Check that the shortcut view (used for the admin "view on site"
     41        functionality) returns a complete URL regardless of whether the sites
     42        framework is installed'''
     43       
     44        request = HttpRequest()
     45        request.META = {
     46            "SERVER_NAME": "Example.com",
     47            "SERVER_PORT": "80",
     48        }
     49        from django.contrib.auth.models import User
     50        user_ct = ContentType.objects.get_for_model(User)
     51        obj = User.objects.create(username="john")
     52        response = shortcut(request, user_ct.id, obj.id)
     53        self.assertEqual("http://example.com/users/john/", response._headers.get("location")[1])
     54        Site._meta.installed=False
     55        response = shortcut(request, user_ct.id, obj.id)
     56        self.assertEqual("http://Example.com/users/john/", response._headers.get("location")[1])
     57        Site._meta.installed=True
     58   
     59    def tearDown(self):
     60        settings.DEBUG = False
     61 No newline at end of file
  • django/contrib/contenttypes/views.py

     
    11from django import http
    22from django.contrib.contenttypes.models import ContentType
    3 from django.contrib.sites.models import Site
     3from django.contrib.sites.models import Site, get_current_site
    44from django.core.exceptions import ObjectDoesNotExist
    55
    66def shortcut(request, content_type_id, object_id):
     
    2626    # Otherwise, we need to introspect the object's relationships for a
    2727    # relation to the Site object
    2828    object_domain = None
    29     opts = obj._meta
     29   
     30    if Site._meta.installed:
     31        opts = obj._meta
    3032
    31     # First, look for an many-to-many relationship to Site.
    32     for field in opts.many_to_many:
    33         if field.rel.to is Site:
    34             try:
    35                 # Caveat: In the case of multiple related Sites, this just
    36                 # selects the *first* one, which is arbitrary.
    37                 object_domain = getattr(obj, field.name).all()[0].domain
    38             except IndexError:
    39                 pass
    40             if object_domain is not None:
    41                 break
    42 
    43     # Next, look for a many-to-one relationship to Site.
    44     if object_domain is None:
    45         for field in obj._meta.fields:
    46             if field.rel and field.rel.to is Site:
     33        # First, look for an many-to-many relationship to Site.
     34        for field in opts.many_to_many:
     35            if field.rel.to is Site:
    4736                try:
    48                     object_domain = getattr(obj, field.name).domain
    49                 except Site.DoesNotExist:
     37                    # Caveat: In the case of multiple related Sites, this just
     38                    # selects the *first* one, which is arbitrary.
     39                    object_domain = getattr(obj, field.name).all()[0].domain
     40                except IndexError:
    5041                    pass
    5142                if object_domain is not None:
    5243                    break
    5344
     45        # Next, look for a many-to-one relationship to Site.
     46        if object_domain is None:
     47            for field in obj._meta.fields:
     48                if field.rel and field.rel.to is Site:
     49                    try:
     50                        object_domain = getattr(obj, field.name).domain
     51                    except Site.DoesNotExist:
     52                        pass
     53                    if object_domain is not None:
     54                        break
     55
    5456    # Fall back to the current site (if possible).
    5557    if object_domain is None:
    5658        try:
    57             object_domain = Site.objects.get_current().domain
     59            object_domain = get_current_site(request).domain
    5860        except Site.DoesNotExist:
    5961            pass
    6062
  • django/contrib/gis/sitemaps/views.py

     
    11from django.http import HttpResponse, Http404
    22from django.template import loader
    3 from django.contrib.sites.models import Site
     3from django.contrib.sites.models import get_current_site
    44from django.core import urlresolvers
    55from django.core.paginator import EmptyPage, PageNotAnInteger
    66from django.contrib.gis.db.models.fields import GeometryField
     
    1515    This view generates a sitemap index that uses the proper view
    1616    for resolving geographic section sitemap URLs.
    1717    """
    18     current_site = Site.objects.get_current()
     18    current_site = get_current_site(request)
    1919    sites = []
    2020    protocol = request.is_secure() and 'https' or 'http'
    2121    for section, site in sitemaps.items():
  • django/contrib/sitemaps/__init__.py

     
     1from django.contrib.sites.models import get_current_site
    12from django.core import urlresolvers, paginator
    23import urllib
    34
     
    6061    paginator = property(_get_paginator)
    6162
    6263    def get_urls(self, page=1):
    63         from django.contrib.sites.models import Site
    64         current_site = Site.objects.get_current()
     64        current_site = get_current_site(self.request)
    6565        urls = []
    6666        for item in self.paginator.page(page).object_list:
    6767            loc = "http://%s%s" % (current_site.domain, self.__get('location', item))
     
    7777
    7878class FlatPageSitemap(Sitemap):
    7979    def items(self):
    80         from django.contrib.sites.models import Site
    81         current_site = Site.objects.get_current()
    82         return current_site.flatpage_set.filter(registration_required=False)
     80        from django.contrib.sites.models import get_current_site
     81        current_site = get_current_site(self.request)
     82        if hasattr(current_site, "flatpage_set"):
     83            return current_site.flatpage_set.filter(registration_required=False)
     84        else:
     85            return ()
    8386
    8487class GenericSitemap(Sitemap):
    8588    priority = None
  • django/contrib/sitemaps/tests/basic.py

     
    22from django.conf import settings
    33from django.contrib.auth.models import User
    44from django.contrib.flatpages.models import FlatPage
     5from django.contrib.sites.models import Site
    56from django.test import TestCase
    67from django.utils.formats import localize
    78from django.utils.translation import activate
     
    7475        self.assertContains(response, '<loc>http://example.com%s</loc>' % public.url)
    7576        # Private flatpage should not be in the sitemap
    7677        self.assertNotContains(response, '<loc>http://example.com%s</loc>' % private.url)
     78   
     79    def test_requestsite_sitemap(self):
     80        # Make sure hitting the flatpages sitemap without the sites framework
     81        # installed doesn't raise an exception
     82        Site._meta.installed = False
     83        response = self.client.get('/flatpages/sitemap.xml')
     84        # Retrieve the sitemap.
     85        response = self.client.get('/simple/sitemap.xml')
     86        # Check for all the important bits:
     87        self.assertEquals(response.content, """<?xml version="1.0" encoding="UTF-8"?>
     88<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
     89<url><loc>http://testserver/location/</loc><lastmod>%s</lastmod><changefreq>never</changefreq><priority>0.5</priority></url>
     90</urlset>
     91""" % date.today().strftime('%Y-%m-%d'))
     92        Site._meta.installed = True
     93       
    7794
  • django/contrib/sitemaps/views.py

     
    11from django.http import HttpResponse, Http404
    22from django.template import loader
    3 from django.contrib.sites.models import Site
     3from django.contrib.sites.models import get_current_site
    44from django.core import urlresolvers
    55from django.utils.encoding import smart_str
    66from django.core.paginator import EmptyPage, PageNotAnInteger
    77
    88def index(request, sitemaps):
    9     current_site = Site.objects.get_current()
     9    current_site = get_current_site(request)
    1010    sites = []
    1111    protocol = request.is_secure() and 'https' or 'http'
    1212    for section, site in sitemaps.items():
     13        site.request = request
    1314        if callable(site):
    1415            pages = site().paginator.num_pages
    1516        else:
     
    3233        maps = sitemaps.values()
    3334    page = request.GET.get("p", 1)
    3435    for site in maps:
     36        site.request = request
    3537        try:
    3638            if callable(site):
    3739                urls.extend(site().get_urls(page))
  • django/contrib/sites/models.py

     
    7575
    7676    def delete(self):
    7777        raise NotImplementedError('RequestSite cannot be deleted.')
     78
     79def get_current_site(request):
     80    """
     81    Checks if contrib.sites is installed and returns either the current
     82    ``Site`` object or a ``RequestSite`` object based on the request.
     83    """
     84    if Site._meta.installed:
     85        current_site = Site.objects.get_current()
     86    else:
     87        current_site = RequestSite(request)
     88    return current_site
  • django/contrib/sites/tests.py

     
    1 """
    2 >>> from django.contrib.sites.models import Site
    3 >>> from django.conf import settings
    4 >>> Site(id=settings.SITE_ID, domain="example.com", name="example.com").save()
     1from django.conf import settings
     2from django.contrib.sites.models import Site, RequestSite, get_current_site
     3from django.core.exceptions import ObjectDoesNotExist
     4from django.http import HttpRequest
     5from django.test import TestCase
    56
    6 # Make sure that get_current() does not return a deleted Site object.
    7 >>> s = Site.objects.get_current()
    8 >>> isinstance(s, Site)
    9 True
    10 
    11 >>> s.delete()
    12 >>> Site.objects.get_current()
    13 Traceback (most recent call last):
    14 ...
    15 DoesNotExist: Site matching query does not exist.
    16 
    17 # After updating a Site object (e.g. via the admin), we shouldn't return a
    18 # bogus value from the SITE_CACHE.
    19 >>> _ = Site.objects.create(id=settings.SITE_ID, domain="example.com", name="example.com")
    20 >>> site = Site.objects.get_current()
    21 >>> site.name
    22 u"example.com"
    23 >>> s2 = Site.objects.get(id=settings.SITE_ID)
    24 >>> s2.name = "Example site"
    25 >>> s2.save()
    26 >>> site = Site.objects.get_current()
    27 >>> site.name
    28 u"Example site"
    29 """
     7class SitesFrameworkTests(TestCase):
     8    def setUp(self):
     9        Site(id=settings.SITE_ID, domain="example.com", name="example.com").save()
     10       
     11    def test_site_manager(self):
     12        # Make sure that get_current() does not return a deleted Site object.
     13        s = Site.objects.get_current()
     14        self.assert_(isinstance(s, Site))
     15        s.delete()
     16        self.assertRaises(ObjectDoesNotExist, Site.objects.get_current)
     17       
     18    def test_site_cache(self):
     19        # After updating a Site object (e.g. via the admin), we shouldn't return a
     20        # bogus value from the SITE_CACHE.
     21        site = Site.objects.get_current()
     22        self.assertEqual(u"example.com", site.name)
     23        s2 = Site.objects.get(id=settings.SITE_ID)
     24        s2.name = "Example site"
     25        s2.save()
     26        site = Site.objects.get_current()
     27        self.assertEqual(u"Example site", site.name)
     28   
     29    def test_get_current(self):
     30        # Test that the correct Site object is returned
     31        request = HttpRequest()
     32        request.META = {
     33            "SERVER_NAME": "example.com",
     34            "SERVER_PORT": "80",
     35        }
     36        site = get_current_site(request)
     37        self.assert_(isinstance(site, Site))
     38        self.assertEqual(site.id, settings.SITE_ID)
     39       
     40        # Test that an exception is raised if the sites framework is installed
     41        # but there is no matching Site
     42        site.delete()
     43        self.assertRaises(ObjectDoesNotExist, get_current_site, request)
     44       
     45        # A RequestSite is returned if the sites framework is not installed
     46        Site._meta.installed = False
     47        site = get_current_site(request)
     48        self.assert_(isinstance(site, RequestSite))
     49        self.assertEqual(site.name, u"example.com")
     50        Site._meta.installed = True
     51       
  • django/contrib/syndication/views.py

     
    11import datetime
    22from django.conf import settings
    3 from django.contrib.sites.models import Site, RequestSite
     3from django.contrib.sites.models import get_current_site
    44from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
    55from django.http import HttpResponse, Http404
    66from django.template import loader, Template, TemplateDoesNotExist, RequestContext
     
    9191        Returns a feedgenerator.DefaultFeed object, fully populated, for
    9292        this feed. Raises FeedDoesNotExist for invalid parameters.
    9393        """
    94         if Site._meta.installed:
    95             current_site = Site.objects.get_current()
    96         else:
    97             current_site = RequestSite(request)
     94        current_site = get_current_site(request)
    9895
    9996        link = self.__get_dynamic_attr('link', obj)
    10097        link = add_domain(current_site.domain, link)
  • docs/ref/contrib/sites.txt

     
    107107Hooking into the current site from views
    108108----------------------------------------
    109109
    110 On a lower level, you can use the sites framework in your Django views to do
     110You can use the sites framework in your Django views to do
    111111particular things based on the site in which the view is being called.
    112112For example::
    113113
     
    148148        else:
    149149            # Do something else.
    150150
     151.. versionchanged:: 1.3
     152
     153For code which relies on getting the current domain but cannot be certain
     154that the sites framework will be installed for any given project, there is a
     155utility function :func:`~django.contrib.sites.models.get_current_site` that
     156takes a request object as an argument and returns either a Site instance (if 
     157the sites framework is installed) or a RequestSite instance (if it is not).
     158This allows loose coupling with the sites framework and provides a usable
     159fallback for cases where it is not installed.
     160
    151161Getting the current domain for display
    152162--------------------------------------
    153163
Back to Top