Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Ticket #18620: Prefer current Site when checking M2M in "shortcut"/"view_on_site" redirect #203

Closed
wants to merge 7 commits into from

6 participants

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 10, 2012
  1. @StefanKjartansson
Commits on Jul 11, 2012
  1. @adrianholovaty

    Merge pull request #199 from mitnk/master

    adrianholovaty authored
    Fixed a typo in the timezones document.
  2. @adrianholovaty

    Merge pull request #197 from StefanKjartansson/master

    adrianholovaty authored
    Fixed typo in docs
Commits on Jul 12, 2012
  1. @alex

    Remove some code that has been dead since newforms-admin was merged, …

    alex authored Alex Gaynor committed
    …many moons ago.
  2. @claudep
  3. @mtigas
  4. @mtigas
This page is out of date. Refresh to see the latest.
View
42 django/contrib/contenttypes/tests.py
@@ -8,6 +8,7 @@
from django.contrib.sites.models import Site
from django.http import HttpRequest, Http404
from django.test import TestCase
+from django.utils import unittest
from django.utils.encoding import smart_str
@@ -45,6 +46,13 @@ class FooWithBrokenAbsoluteUrl(FooWithoutUrl):
def get_absolute_url(self):
return "/users/%s/" % self.unknown_field
+if Site._meta.installed:
+ class FooWithSiteM2MAndUrl(FooWithUrl):
+ """
+ Fake model containing a `Site` many-to-many relationship.
+ """
+ sites = models.ManyToManyField(Site)
+
class ContentTypesTests(TestCase):
def setUp(self):
@@ -260,6 +268,40 @@ def test_shortcut_view_with_broken_get_absolute_url(self):
self.assertRaises(AttributeError, shortcut, request, user_ct.id, obj.id)
+ @unittest.skipIf(not Site._meta.installed,
+ "this tests against relationship behavior with the Sites framework")
+ def test_shortcut_view_m2m(self):
+ """
+ Check that the shortcut view (used for the admin "view on site"
+ functionality) returns a complete URL regardless of whether the sites
+ framework is installed
+ """
+ # Tests ticket #18620; prefer current_site rather than allowing
+ # M2M to select first domain via ABC order.
+ current_site = Site.objects.get_current() # example.com
+ other_site = Site(domain="a.example.com", name="a.example.com")
+ other_site.save()
+
+ # Build an object that belongs to both sites.
+ obj = FooWithSiteM2MAndUrl(name="john")
+ obj.save() # need saved object to set M2M relationship
+ obj.sites = [other_site, current_site]
+
+ # Check that shortcut view returns absolute URI for `current_site`
+ # and not `other_site`.
+ request = HttpRequest()
+ request.META = {
+ "SERVER_NAME": "Example.com",
+ "SERVER_PORT": "80",
+ }
+ user_ct = ContentType.objects.get_for_model(FooWithSiteM2MAndUrl)
+ response = shortcut(request, user_ct.id, obj.id)
+ self.assertEqual("http://%s/users/john/" % current_site.domain,
+ response._headers.get("location")[1])
+
+ obj.delete()
+ other_site.delete()
+
def test_missing_model(self):
"""
Ensures that displaying content types in admin (or anywhere) doesn't
View
33 django/contrib/contenttypes/views.py
@@ -38,6 +38,15 @@ def shortcut(request, content_type_id, object_id):
# Otherwise, we need to introspect the object's relationships for a
# relation to the Site object
object_domain = None
+ current_domain = None
+
+ # Get current site (if possible): this decides the preferred domain
+ # if this object has an M2M site field and provides a fallback if this
+ # object does not have a site FK or M2M field.
+ try:
+ current_domain = get_current_site(request).domain
+ except Site.DoesNotExist:
+ pass
if Site._meta.installed:
opts = obj._meta
@@ -45,10 +54,21 @@ def shortcut(request, content_type_id, object_id):
# First, look for an many-to-many relationship to Site.
for field in opts.many_to_many:
if field.rel.to is Site:
+ site_qs = getattr(obj, field.name).all()
+ try:
+ # If one of the sites this object belongs to is the current
+ # site, use it.
+ object_domain = site_qs.get(domain=current_domain).domain
+ except Site.DoesNotExist:
+ pass
+ if object_domain is not None:
+ break
try:
- # Caveat: In the case of multiple related Sites, this just
- # selects the *first* one, which is arbitrary.
- object_domain = getattr(obj, field.name).all()[0].domain
+ # Current site was not in the M2M relationship for this
+ # object. Caveat: This just selects the *first* one, which
+ # is arbitrary. (Generally based on Site model ordering,
+ # which is alphabetical by domain.)
+ object_domain = site_qs[0].domain
except IndexError:
pass
if object_domain is not None:
@@ -65,12 +85,9 @@ def shortcut(request, content_type_id, object_id):
if object_domain is not None:
break
- # Fall back to the current site (if possible).
+ # Fall back to the current site (if possible) or None (which is fine).
if object_domain is None:
- try:
- object_domain = get_current_site(request).domain
- except Site.DoesNotExist:
- pass
+ object_domain = current_domain
# If all that malarkey found an object domain, use it. Otherwise, fall back
# to whatever get_absolute_url() returned.
View
2  django/db/models/__init__.py
@@ -15,8 +15,6 @@
from django.db.models import signals
from django.utils.decorators import wraps
-# Admin stages.
-ADD, CHANGE, BOTH = 1, 2, 3
def permalink(func):
"""
View
50 docs/ref/contrib/gis/install.txt
@@ -1034,61 +1034,11 @@ Optional packages to consider:
do not plan on doing any database transformation of geometries to the
Google projection (900913).
-.. _heron:
-
-8.04 and lower
-~~~~~~~~~~~~~~
-
-The 8.04 (and lower) versions of Ubuntu use GEOS v2.2.3 in their binary packages,
-which is incompatible with GeoDjango. Thus, do *not* use the binary packages
-for GEOS or PostGIS and build some prerequisites from source, per the instructions
-in this document; however, it is okay to use the PostgreSQL binary packages.
-
-For more details, please see the Debian instructions for :ref:`etch` below.
-
.. _debian:
Debian
------
-.. _etch:
-
-4.0 (Etch)
-^^^^^^^^^^
-
-The situation here is the same as that of Ubuntu :ref:`heron` -- in other words,
-some packages must be built from source to work properly with GeoDjango.
-
-Binary packages
-~~~~~~~~~~~~~~~
-The following command will install acceptable binary packages, as well as
-the development tools necessary to build the rest of the requirements:
-
-.. code-block:: bash
-
- $ sudo apt-get install binutils bzip2 gcc g++ flex make postgresql-8.1 \
- postgresql-server-dev-8.1 python-ctypes python-psycopg2 python-setuptools
-
-Required package information:
-
-* ``binutils``: for ctypes to find libraries
-* ``bzip2``: for decompressing the source packages
-* ``gcc``, ``g++``, ``make``: GNU developer tools used to compile the libraries
-* ``flex``: required to build PostGIS
-* ``postgresql-8.1``
-* ``postgresql-server-dev-8.1``: for ``pg_config``
-* ``python-psycopg2``
-
-Optional packages:
-
-* ``libgeoip``: for :ref:`GeoIP <ref-geoip>` support
-
-Source packages
-~~~~~~~~~~~~~~~
-You will still have to install :ref:`geosbuild`, :ref:`proj4`,
-:ref:`postgis`, and :ref:`gdalbuild` from source. Please follow the
-directions carefully.
-
.. _lenny:
5.0 (Lenny)
View
2  docs/topics/python3.txt
@@ -181,7 +181,7 @@ xrange range xrange
=============================== ====================================== ======================
-Ouptut encoding now Unicode
+Output encoding now Unicode
===========================
If you want to catch stdout/stderr output, the output content is UTF-8 encoded
Something went wrong with that request. Please try again.