Fixed #20777 -- Admin proxy model deletion regression
Added proxy_models tests by Harm Geerts <github@geertswei.nl>.
This commit is contained in:
parent
4668c142dc
commit
3844089edc
|
@ -155,9 +155,6 @@ class NestedObjects(Collector):
|
||||||
if source_attr:
|
if source_attr:
|
||||||
self.add_edge(getattr(obj, source_attr), obj)
|
self.add_edge(getattr(obj, source_attr), obj)
|
||||||
else:
|
else:
|
||||||
if obj._meta.proxy:
|
|
||||||
# Take concrete model's instance to avoid mismatch in edges
|
|
||||||
obj = obj._meta.concrete_model(pk=obj.pk)
|
|
||||||
self.add_edge(None, obj)
|
self.add_edge(None, obj)
|
||||||
try:
|
try:
|
||||||
return super(NestedObjects, self).collect(objs, source_attr=source_attr, **kwargs)
|
return super(NestedObjects, self).collect(objs, source_attr=source_attr, **kwargs)
|
||||||
|
|
|
@ -500,9 +500,9 @@ using ``__str__()`` like this::
|
||||||
.. method:: Model.__eq__()
|
.. method:: Model.__eq__()
|
||||||
|
|
||||||
The equality method is defined such that instances with the same primary
|
The equality method is defined such that instances with the same primary
|
||||||
key value and the same concrete class are considered equal. The term
|
key value and the same concrete class are considered equal. For proxy
|
||||||
concrete class means proxy model's first non-proxy parent or the class
|
models, concrete class is defined as the model's first non-proxy parent;
|
||||||
itself if it isn't a proxy class.
|
for all other models it is simply the model's class.
|
||||||
|
|
||||||
For example::
|
For example::
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from .models import TrackerUser, ProxyTrackerUser
|
||||||
|
|
||||||
|
admin.site.register(TrackerUser)
|
||||||
|
admin.site.register(ProxyTrackerUser)
|
|
@ -1,4 +1,22 @@
|
||||||
[
|
[
|
||||||
|
{
|
||||||
|
"pk": 100,
|
||||||
|
"model": "auth.user",
|
||||||
|
"fields": {
|
||||||
|
"username": "super",
|
||||||
|
"first_name": "Super",
|
||||||
|
"last_name": "User",
|
||||||
|
"is_active": true,
|
||||||
|
"is_superuser": true,
|
||||||
|
"is_staff": true,
|
||||||
|
"last_login": "2007-05-30 13:20:10",
|
||||||
|
"groups": [],
|
||||||
|
"user_permissions": [],
|
||||||
|
"password": "sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158",
|
||||||
|
"email": "super@example.com",
|
||||||
|
"date_joined": "2007-05-30 13:20:10"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"pk": 100,
|
"pk": 100,
|
||||||
"model": "proxy_models.BaseUser",
|
"model": "proxy_models.BaseUser",
|
||||||
|
@ -21,4 +39,4 @@
|
||||||
"assignee": 100
|
"assignee": 100
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -117,9 +117,13 @@ class StateProxy(State):
|
||||||
|
|
||||||
# Proxy models still works with filters (on related fields)
|
# Proxy models still works with filters (on related fields)
|
||||||
# and select_related, even when mixed with model inheritance
|
# and select_related, even when mixed with model inheritance
|
||||||
|
@python_2_unicode_compatible
|
||||||
class BaseUser(models.Model):
|
class BaseUser(models.Model):
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return ':'.join((self.__class__.__name__, self.name,))
|
||||||
|
|
||||||
class TrackerUser(BaseUser):
|
class TrackerUser(BaseUser):
|
||||||
status = models.CharField(max_length=50)
|
status = models.CharField(max_length=50)
|
||||||
|
|
||||||
|
@ -134,7 +138,7 @@ class Issue(models.Model):
|
||||||
assignee = models.ForeignKey(TrackerUser)
|
assignee = models.ForeignKey(TrackerUser)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return ':'.join((self.__class__.__name__,self.summary,))
|
return ':'.join((self.__class__.__name__, self.summary,))
|
||||||
|
|
||||||
class Bug(Issue):
|
class Bug(Issue):
|
||||||
version = models.CharField(max_length=50)
|
version = models.CharField(max_length=50)
|
||||||
|
|
|
@ -10,12 +10,14 @@ from django.db import models, DEFAULT_DB_ALIAS
|
||||||
from django.db.models import signals
|
from django.db.models import signals
|
||||||
from django.db.models.loading import cache
|
from django.db.models.loading import cache
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
|
|
||||||
from .models import (MyPerson, Person, StatusPerson, LowerStatusPerson,
|
from .models import (MyPerson, Person, StatusPerson, LowerStatusPerson,
|
||||||
MyPersonProxy, Abstract, OtherPerson, User, UserProxy, UserProxyProxy,
|
MyPersonProxy, Abstract, OtherPerson, User, UserProxy, UserProxyProxy,
|
||||||
Country, State, StateProxy, TrackerUser, BaseUser, Bug, ProxyTrackerUser,
|
Country, State, StateProxy, TrackerUser, BaseUser, Bug, ProxyTrackerUser,
|
||||||
Improvement, ProxyProxyBug, ProxyBug, ProxyImprovement, Issue)
|
Improvement, ProxyProxyBug, ProxyBug, ProxyImprovement, Issue)
|
||||||
|
from .admin import admin as force_admin_model_registration
|
||||||
|
|
||||||
|
|
||||||
class ProxyModelTests(TestCase):
|
class ProxyModelTests(TestCase):
|
||||||
|
@ -366,8 +368,10 @@ class ProxyModelTests(TestCase):
|
||||||
self.assertEqual(MyPerson(id=100), Person(id=100))
|
self.assertEqual(MyPerson(id=100), Person(id=100))
|
||||||
|
|
||||||
|
|
||||||
|
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
|
||||||
class ProxyModelAdminTests(TestCase):
|
class ProxyModelAdminTests(TestCase):
|
||||||
fixtures = ['myhorses']
|
fixtures = ['myhorses']
|
||||||
|
urls = 'proxy_models.urls'
|
||||||
|
|
||||||
def test_cascade_delete_proxy_model_admin_warning(self):
|
def test_cascade_delete_proxy_model_admin_warning(self):
|
||||||
"""
|
"""
|
||||||
|
@ -383,3 +387,26 @@ class ProxyModelAdminTests(TestCase):
|
||||||
self.assertTrue(tracker_user in collector.edges.get(None, ()))
|
self.assertTrue(tracker_user in collector.edges.get(None, ()))
|
||||||
self.assertTrue(base_user in collector.edges.get(None, ()))
|
self.assertTrue(base_user in collector.edges.get(None, ()))
|
||||||
self.assertTrue(issue in collector.edges.get(tracker_user, ()))
|
self.assertTrue(issue in collector.edges.get(tracker_user, ()))
|
||||||
|
|
||||||
|
def test_delete_str_in_model_admin(self):
|
||||||
|
"""
|
||||||
|
Test if the admin delete page shows the correct string representation
|
||||||
|
for a proxy model.
|
||||||
|
"""
|
||||||
|
user = TrackerUser.objects.get(name='Django Pony')
|
||||||
|
proxy = ProxyTrackerUser.objects.get(name='Django Pony')
|
||||||
|
|
||||||
|
user_str = (
|
||||||
|
'Tracker user: <a href="/admin/proxy_models/trackeruser/%s/">%s</a>' % (user.pk, user))
|
||||||
|
proxy_str = (
|
||||||
|
'Proxy tracker user: <a href="/admin/proxy_models/proxytrackeruser/%s/">%s</a>' %
|
||||||
|
(proxy.pk, proxy))
|
||||||
|
|
||||||
|
self.client.login(username='super', password='secret')
|
||||||
|
response = self.client.get('/admin/proxy_models/trackeruser/%s/delete/' % (user.pk,))
|
||||||
|
delete_str = response.context['deleted_objects'][0]
|
||||||
|
self.assertEqual(delete_str, user_str)
|
||||||
|
response = self.client.get('/admin/proxy_models/proxytrackeruser/%s/delete/' % (proxy.pk,))
|
||||||
|
delete_str = response.context['deleted_objects'][0]
|
||||||
|
self.assertEqual(delete_str, proxy_str)
|
||||||
|
self.client.logout()
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
from django.conf.urls import patterns, include
|
||||||
|
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
(r'^admin/', include(admin.site.urls)),
|
||||||
|
)
|
Loading…
Reference in New Issue