mirror of
https://github.com/django/django.git
synced 2025-07-04 17:59:13 +00:00
[soc2009/admin-ui] Merging up to trunk svn:r11382 into my branch
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/admin-ui@11383 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
242e8177bf
commit
98fc6a1b68
@ -80,4 +80,43 @@ Traceback (most recent call last):
|
|||||||
...
|
...
|
||||||
FieldError: Joined field references are not permitted in this query
|
FieldError: Joined field references are not permitted in this query
|
||||||
|
|
||||||
|
# F expressions can be used to update attributes on single objects
|
||||||
|
>>> test_gmbh = Company.objects.get(name='Test GmbH')
|
||||||
|
>>> test_gmbh.num_employees
|
||||||
|
32
|
||||||
|
>>> test_gmbh.num_employees = F('num_employees') + 4
|
||||||
|
>>> test_gmbh.save()
|
||||||
|
>>> test_gmbh = Company.objects.get(pk=test_gmbh.pk)
|
||||||
|
>>> test_gmbh.num_employees
|
||||||
|
36
|
||||||
|
|
||||||
|
# F expressions cannot be used to update attributes which are foreign keys, or
|
||||||
|
# attributes which involve joins.
|
||||||
|
>>> test_gmbh.point_of_contact = None
|
||||||
|
>>> test_gmbh.save()
|
||||||
|
>>> test_gmbh.point_of_contact is None
|
||||||
|
True
|
||||||
|
>>> test_gmbh.point_of_contact = F('ceo')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValueError: Cannot assign "<django.db.models.expressions.F object at ...>": "Company.point_of_contact" must be a "Employee" instance.
|
||||||
|
|
||||||
|
>>> test_gmbh.point_of_contact = test_gmbh.ceo
|
||||||
|
>>> test_gmbh.save()
|
||||||
|
>>> test_gmbh.name = F('ceo__last_name')
|
||||||
|
>>> test_gmbh.save()
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
FieldError: Joined field references are not permitted in this query
|
||||||
|
|
||||||
|
# F expressions cannot be used to update attributes on objects which do not yet
|
||||||
|
# exist in the database
|
||||||
|
>>> acme = Company(name='The Acme Widget Co.', num_employees=12, num_chairs=5,
|
||||||
|
... ceo=test_gmbh.ceo)
|
||||||
|
>>> acme.num_employees = F('num_employees') + 16
|
||||||
|
>>> acme.save()
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
TypeError: int() argument must be a string or a number, not 'ExpressionNode'
|
||||||
|
|
||||||
"""}
|
"""}
|
||||||
|
@ -326,7 +326,6 @@ class GalleryAdmin(admin.ModelAdmin):
|
|||||||
class PictureAdmin(admin.ModelAdmin):
|
class PictureAdmin(admin.ModelAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Language(models.Model):
|
class Language(models.Model):
|
||||||
iso = models.CharField(max_length=5, primary_key=True)
|
iso = models.CharField(max_length=5, primary_key=True)
|
||||||
name = models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
@ -401,8 +400,25 @@ class WhatsitInline(admin.StackedInline):
|
|||||||
class FancyDoodadInline(admin.StackedInline):
|
class FancyDoodadInline(admin.StackedInline):
|
||||||
model = FancyDoodad
|
model = FancyDoodad
|
||||||
|
|
||||||
|
class Category(models.Model):
|
||||||
|
collector = models.ForeignKey(Collector)
|
||||||
|
order = models.PositiveIntegerField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ('order',)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return u'%s:o%s' % (self.id, self.order)
|
||||||
|
|
||||||
|
class CategoryAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('id', 'collector', 'order')
|
||||||
|
list_editable = ('order',)
|
||||||
|
|
||||||
|
class CategoryInline(admin.StackedInline):
|
||||||
|
model = Category
|
||||||
|
|
||||||
class CollectorAdmin(admin.ModelAdmin):
|
class CollectorAdmin(admin.ModelAdmin):
|
||||||
inlines = [WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline, FancyDoodadInline]
|
inlines = [WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline, FancyDoodadInline, CategoryInline]
|
||||||
|
|
||||||
admin.site.register(Article, ArticleAdmin)
|
admin.site.register(Article, ArticleAdmin)
|
||||||
admin.site.register(CustomArticle, CustomArticleAdmin)
|
admin.site.register(CustomArticle, CustomArticleAdmin)
|
||||||
@ -426,6 +442,7 @@ admin.site.register(Language, LanguageAdmin)
|
|||||||
admin.site.register(Recommendation, RecommendationAdmin)
|
admin.site.register(Recommendation, RecommendationAdmin)
|
||||||
admin.site.register(Recommender)
|
admin.site.register(Recommender)
|
||||||
admin.site.register(Collector, CollectorAdmin)
|
admin.site.register(Collector, CollectorAdmin)
|
||||||
|
admin.site.register(Category, CategoryAdmin)
|
||||||
|
|
||||||
# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
|
# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
|
||||||
# That way we cover all four cases:
|
# That way we cover all four cases:
|
||||||
|
@ -10,13 +10,15 @@ from django.contrib.admin.models import LogEntry, DELETION
|
|||||||
from django.contrib.admin.sites import LOGIN_FORM_KEY
|
from django.contrib.admin.sites import LOGIN_FORM_KEY
|
||||||
from django.contrib.admin.util import quote
|
from django.contrib.admin.util import quote
|
||||||
from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
|
from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
|
||||||
|
from django.utils.cache import get_max_age
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
|
|
||||||
# local test models
|
# local test models
|
||||||
from models import Article, BarAccount, CustomArticle, EmptyModel, \
|
from models import Article, BarAccount, CustomArticle, EmptyModel, \
|
||||||
ExternalSubscriber, FooAccount, Gallery, ModelWithStringPrimaryKey, \
|
ExternalSubscriber, FooAccount, Gallery, ModelWithStringPrimaryKey, \
|
||||||
Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast, \
|
Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast, \
|
||||||
Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit
|
Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit, \
|
||||||
|
Category
|
||||||
|
|
||||||
try:
|
try:
|
||||||
set
|
set
|
||||||
@ -203,6 +205,11 @@ class AdminViewBasicTest(TestCase):
|
|||||||
response = self.client.get('/test_admin/%s/admin_views/thing/' % self.urlbit, {'color__id__exact': 'StringNotInteger!'})
|
response = self.client.get('/test_admin/%s/admin_views/thing/' % self.urlbit, {'color__id__exact': 'StringNotInteger!'})
|
||||||
self.assertRedirects(response, '/test_admin/%s/admin_views/thing/?e=1' % self.urlbit)
|
self.assertRedirects(response, '/test_admin/%s/admin_views/thing/?e=1' % self.urlbit)
|
||||||
|
|
||||||
|
def testLogoutAndPasswordChangeURLs(self):
|
||||||
|
response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit)
|
||||||
|
self.failIf('<a href="/test_admin/%s/logout/">' % self.urlbit not in response.content)
|
||||||
|
self.failIf('<a href="/test_admin/%s/password_change/">' % self.urlbit not in response.content)
|
||||||
|
|
||||||
def testNamedGroupFieldChoicesChangeList(self):
|
def testNamedGroupFieldChoicesChangeList(self):
|
||||||
"""
|
"""
|
||||||
Ensures the admin changelist shows correct values in the relevant column
|
Ensures the admin changelist shows correct values in the relevant column
|
||||||
@ -921,6 +928,45 @@ class AdminViewListEditable(TestCase):
|
|||||||
|
|
||||||
self.failUnlessEqual(Person.objects.get(name="John Mauchly").alive, False)
|
self.failUnlessEqual(Person.objects.get(name="John Mauchly").alive, False)
|
||||||
|
|
||||||
|
def test_list_editable_ordering(self):
|
||||||
|
collector = Collector.objects.create(id=1, name="Frederick Clegg")
|
||||||
|
|
||||||
|
Category.objects.create(id=1, order=1, collector=collector)
|
||||||
|
Category.objects.create(id=2, order=2, collector=collector)
|
||||||
|
Category.objects.create(id=3, order=0, collector=collector)
|
||||||
|
Category.objects.create(id=4, order=0, collector=collector)
|
||||||
|
|
||||||
|
# NB: The order values must be changed so that the items are reordered.
|
||||||
|
data = {
|
||||||
|
"form-TOTAL_FORMS": "4",
|
||||||
|
"form-INITIAL_FORMS": "4",
|
||||||
|
|
||||||
|
"form-0-order": "14",
|
||||||
|
"form-0-id": "1",
|
||||||
|
"form-0-collector": "1",
|
||||||
|
|
||||||
|
"form-1-order": "13",
|
||||||
|
"form-1-id": "2",
|
||||||
|
"form-1-collector": "1",
|
||||||
|
|
||||||
|
"form-2-order": "1",
|
||||||
|
"form-2-id": "3",
|
||||||
|
"form-2-collector": "1",
|
||||||
|
|
||||||
|
"form-3-order": "0",
|
||||||
|
"form-3-id": "4",
|
||||||
|
"form-3-collector": "1",
|
||||||
|
}
|
||||||
|
response = self.client.post('/test_admin/admin/admin_views/category/', data)
|
||||||
|
# Successful post will redirect
|
||||||
|
self.failUnlessEqual(response.status_code, 302)
|
||||||
|
|
||||||
|
# Check that the order values have been applied to the right objects
|
||||||
|
self.failUnlessEqual(Category.objects.get(id=1).order, 14)
|
||||||
|
self.failUnlessEqual(Category.objects.get(id=2).order, 13)
|
||||||
|
self.failUnlessEqual(Category.objects.get(id=3).order, 1)
|
||||||
|
self.failUnlessEqual(Category.objects.get(id=4).order, 0)
|
||||||
|
|
||||||
class AdminSearchTest(TestCase):
|
class AdminSearchTest(TestCase):
|
||||||
fixtures = ['admin-views-users','multiple-child-classes']
|
fixtures = ['admin-views-users','multiple-child-classes']
|
||||||
|
|
||||||
@ -1254,11 +1300,24 @@ class AdminInlineTests(TestCase):
|
|||||||
"fancydoodad_set-2-owner": "1",
|
"fancydoodad_set-2-owner": "1",
|
||||||
"fancydoodad_set-2-name": "",
|
"fancydoodad_set-2-name": "",
|
||||||
"fancydoodad_set-2-expensive": "on",
|
"fancydoodad_set-2-expensive": "on",
|
||||||
|
|
||||||
|
"category_set-TOTAL_FORMS": "3",
|
||||||
|
"category_set-INITIAL_FORMS": "0",
|
||||||
|
"category_set-0-order": "",
|
||||||
|
"category_set-0-id": "",
|
||||||
|
"category_set-0-collector": "1",
|
||||||
|
"category_set-1-order": "",
|
||||||
|
"category_set-1-id": "",
|
||||||
|
"category_set-1-collector": "1",
|
||||||
|
"category_set-2-order": "",
|
||||||
|
"category_set-2-id": "",
|
||||||
|
"category_set-2-collector": "1",
|
||||||
}
|
}
|
||||||
|
|
||||||
result = self.client.login(username='super', password='secret')
|
result = self.client.login(username='super', password='secret')
|
||||||
self.failUnlessEqual(result, True)
|
self.failUnlessEqual(result, True)
|
||||||
Collector(pk=1,name='John Fowles').save()
|
self.collector = Collector(pk=1,name='John Fowles')
|
||||||
|
self.collector.save()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.client.logout()
|
self.client.logout()
|
||||||
@ -1419,3 +1478,131 @@ class AdminInlineTests(TestCase):
|
|||||||
self.failUnlessEqual(response.status_code, 302)
|
self.failUnlessEqual(response.status_code, 302)
|
||||||
self.failUnlessEqual(FancyDoodad.objects.count(), 1)
|
self.failUnlessEqual(FancyDoodad.objects.count(), 1)
|
||||||
self.failUnlessEqual(FancyDoodad.objects.all()[0].name, "Fancy Doodad 1 Updated")
|
self.failUnlessEqual(FancyDoodad.objects.all()[0].name, "Fancy Doodad 1 Updated")
|
||||||
|
|
||||||
|
def test_ordered_inline(self):
|
||||||
|
"""Check that an inline with an editable ordering fields is
|
||||||
|
updated correctly. Regression for #10922"""
|
||||||
|
# Create some objects with an initial ordering
|
||||||
|
Category.objects.create(id=1, order=1, collector=self.collector)
|
||||||
|
Category.objects.create(id=2, order=2, collector=self.collector)
|
||||||
|
Category.objects.create(id=3, order=0, collector=self.collector)
|
||||||
|
Category.objects.create(id=4, order=0, collector=self.collector)
|
||||||
|
|
||||||
|
# NB: The order values must be changed so that the items are reordered.
|
||||||
|
self.post_data.update({
|
||||||
|
"name": "Frederick Clegg",
|
||||||
|
|
||||||
|
"category_set-TOTAL_FORMS": "7",
|
||||||
|
"category_set-INITIAL_FORMS": "4",
|
||||||
|
|
||||||
|
"category_set-0-order": "14",
|
||||||
|
"category_set-0-id": "1",
|
||||||
|
"category_set-0-collector": "1",
|
||||||
|
|
||||||
|
"category_set-1-order": "13",
|
||||||
|
"category_set-1-id": "2",
|
||||||
|
"category_set-1-collector": "1",
|
||||||
|
|
||||||
|
"category_set-2-order": "1",
|
||||||
|
"category_set-2-id": "3",
|
||||||
|
"category_set-2-collector": "1",
|
||||||
|
|
||||||
|
"category_set-3-order": "0",
|
||||||
|
"category_set-3-id": "4",
|
||||||
|
"category_set-3-collector": "1",
|
||||||
|
|
||||||
|
"category_set-4-order": "",
|
||||||
|
"category_set-4-id": "",
|
||||||
|
"category_set-4-collector": "1",
|
||||||
|
|
||||||
|
"category_set-5-order": "",
|
||||||
|
"category_set-5-id": "",
|
||||||
|
"category_set-5-collector": "1",
|
||||||
|
|
||||||
|
"category_set-6-order": "",
|
||||||
|
"category_set-6-id": "",
|
||||||
|
"category_set-6-collector": "1",
|
||||||
|
})
|
||||||
|
response = self.client.post('/test_admin/admin/admin_views/collector/1/', self.post_data)
|
||||||
|
# Successful post will redirect
|
||||||
|
self.failUnlessEqual(response.status_code, 302)
|
||||||
|
|
||||||
|
# Check that the order values have been applied to the right objects
|
||||||
|
self.failUnlessEqual(self.collector.category_set.count(), 4)
|
||||||
|
self.failUnlessEqual(Category.objects.get(id=1).order, 14)
|
||||||
|
self.failUnlessEqual(Category.objects.get(id=2).order, 13)
|
||||||
|
self.failUnlessEqual(Category.objects.get(id=3).order, 1)
|
||||||
|
self.failUnlessEqual(Category.objects.get(id=4).order, 0)
|
||||||
|
|
||||||
|
|
||||||
|
class NeverCacheTests(TestCase):
|
||||||
|
fixtures = ['admin-views-users.xml', 'admin-views-colors.xml', 'admin-views-fabrics.xml']
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.client.login(username='super', password='secret')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
def testAdminIndex(self):
|
||||||
|
"Check the never-cache status of the main index"
|
||||||
|
response = self.client.get('/test_admin/admin/')
|
||||||
|
self.failUnlessEqual(get_max_age(response), 0)
|
||||||
|
|
||||||
|
def testAppIndex(self):
|
||||||
|
"Check the never-cache status of an application index"
|
||||||
|
response = self.client.get('/test_admin/admin/admin_views/')
|
||||||
|
self.failUnlessEqual(get_max_age(response), 0)
|
||||||
|
|
||||||
|
def testModelIndex(self):
|
||||||
|
"Check the never-cache status of a model index"
|
||||||
|
response = self.client.get('/test_admin/admin/admin_views/fabric/')
|
||||||
|
self.failUnlessEqual(get_max_age(response), 0)
|
||||||
|
|
||||||
|
def testModelAdd(self):
|
||||||
|
"Check the never-cache status of a model add page"
|
||||||
|
response = self.client.get('/test_admin/admin/admin_views/fabric/add/')
|
||||||
|
self.failUnlessEqual(get_max_age(response), 0)
|
||||||
|
|
||||||
|
def testModelView(self):
|
||||||
|
"Check the never-cache status of a model edit page"
|
||||||
|
response = self.client.get('/test_admin/admin/admin_views/section/1/')
|
||||||
|
self.failUnlessEqual(get_max_age(response), 0)
|
||||||
|
|
||||||
|
def testModelHistory(self):
|
||||||
|
"Check the never-cache status of a model history page"
|
||||||
|
response = self.client.get('/test_admin/admin/admin_views/section/1/history/')
|
||||||
|
self.failUnlessEqual(get_max_age(response), 0)
|
||||||
|
|
||||||
|
def testModelDelete(self):
|
||||||
|
"Check the never-cache status of a model delete page"
|
||||||
|
response = self.client.get('/test_admin/admin/admin_views/section/1/delete/')
|
||||||
|
self.failUnlessEqual(get_max_age(response), 0)
|
||||||
|
|
||||||
|
def testLogin(self):
|
||||||
|
"Check the never-cache status of login views"
|
||||||
|
self.client.logout()
|
||||||
|
response = self.client.get('/test_admin/admin/')
|
||||||
|
self.failUnlessEqual(get_max_age(response), 0)
|
||||||
|
|
||||||
|
def testLogout(self):
|
||||||
|
"Check the never-cache status of logout view"
|
||||||
|
response = self.client.get('/test_admin/admin/logout/')
|
||||||
|
self.failUnlessEqual(get_max_age(response), 0)
|
||||||
|
|
||||||
|
def testPasswordChange(self):
|
||||||
|
"Check the never-cache status of the password change view"
|
||||||
|
self.client.logout()
|
||||||
|
response = self.client.get('/test_admin/password_change/')
|
||||||
|
self.failUnlessEqual(get_max_age(response), None)
|
||||||
|
|
||||||
|
def testPasswordChangeDone(self):
|
||||||
|
"Check the never-cache status of the password change done view"
|
||||||
|
response = self.client.get('/test_admin/admin/password_change/done/')
|
||||||
|
self.failUnlessEqual(get_max_age(response), None)
|
||||||
|
|
||||||
|
def testJsi18n(self):
|
||||||
|
"Check the never-cache status of the Javascript i18n view"
|
||||||
|
response = self.client.get('/test_admin/jsi18n/')
|
||||||
|
self.failUnlessEqual(get_max_age(response), None)
|
||||||
|
|
||||||
|
@ -115,6 +115,7 @@ class AdminFormfieldForDBFieldWithRequestTests(DjangoTestCase):
|
|||||||
|
|
||||||
class AdminForeignKeyWidgetChangeList(DjangoTestCase):
|
class AdminForeignKeyWidgetChangeList(DjangoTestCase):
|
||||||
fixtures = ["admin-widgets-users.xml"]
|
fixtures = ["admin-widgets-users.xml"]
|
||||||
|
admin_root = '/widget_admin'
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.client.login(username="super", password="secret")
|
self.client.login(username="super", password="secret")
|
||||||
@ -123,5 +124,9 @@ class AdminForeignKeyWidgetChangeList(DjangoTestCase):
|
|||||||
self.client.logout()
|
self.client.logout()
|
||||||
|
|
||||||
def test_changelist_foreignkey(self):
|
def test_changelist_foreignkey(self):
|
||||||
response = self.client.get('/widget_admin/admin_widgets/car/')
|
response = self.client.get('%s/admin_widgets/car/' % self.admin_root)
|
||||||
self.failUnless('/widget_admin/auth/user/add/' in response.content)
|
self.failUnless('%s/auth/user/add/' % self.admin_root in response.content)
|
||||||
|
|
||||||
|
class OldAdminForeignKeyWidgetChangeList(AdminForeignKeyWidgetChangeList):
|
||||||
|
urls = 'regressiontests.admin_widgets.urls2'
|
||||||
|
admin_root = '/deep/down/admin'
|
||||||
|
7
tests/regressiontests/admin_widgets/urls2.py
Normal file
7
tests/regressiontests/admin_widgets/urls2.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
from django.conf.urls.defaults import *
|
||||||
|
import widgetadmin
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
(r'^deep/down/admin/(.*)', widgetadmin.site.root),
|
||||||
|
)
|
@ -19,7 +19,7 @@ class CarTireAdmin(admin.ModelAdmin):
|
|||||||
return db_field.formfield(**kwargs)
|
return db_field.formfield(**kwargs)
|
||||||
return super(CarTireAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
|
return super(CarTireAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
|
||||||
|
|
||||||
site = WidgetAdmin()
|
site = WidgetAdmin(name='widget-admin')
|
||||||
|
|
||||||
site.register(models.User)
|
site.register(models.User)
|
||||||
site.register(models.Car, CarAdmin)
|
site.register(models.Car, CarAdmin)
|
||||||
|
@ -18,6 +18,21 @@ class Callproc(unittest.TestCase):
|
|||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
class LongString(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_long_string(self):
|
||||||
|
# If the backend is Oracle, test that we can save a text longer
|
||||||
|
# than 4000 chars and read it properly
|
||||||
|
if settings.DATABASE_ENGINE == 'oracle':
|
||||||
|
c = connection.cursor()
|
||||||
|
c.execute('CREATE TABLE ltext ("TEXT" NCLOB)')
|
||||||
|
long_str = ''.join([unicode(x) for x in xrange(4000)])
|
||||||
|
c.execute('INSERT INTO ltext VALUES (%s)',[long_str])
|
||||||
|
c.execute('SELECT text FROM ltext')
|
||||||
|
row = c.fetchone()
|
||||||
|
c.execute('DROP TABLE ltext')
|
||||||
|
self.assertEquals(long_str, row[0].read())
|
||||||
|
|
||||||
def connection_created_test(sender, **kwargs):
|
def connection_created_test(sender, **kwargs):
|
||||||
print 'connection_created signal'
|
print 'connection_created signal'
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ class Parent(models.Model):
|
|||||||
class Child(Parent):
|
class Child(Parent):
|
||||||
data = models.CharField(max_length=10)
|
data = models.CharField(max_length=10)
|
||||||
|
|
||||||
# Models to regresison check #7572
|
# Models to regression test #7572
|
||||||
class Channel(models.Model):
|
class Channel(models.Model):
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
|
|
||||||
@ -65,6 +65,14 @@ class Article(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('id',)
|
ordering = ('id',)
|
||||||
|
|
||||||
|
# Models to regression test #11428
|
||||||
|
class Widget(models.Model):
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
|
||||||
|
class WidgetProxy(Widget):
|
||||||
|
class Meta:
|
||||||
|
proxy = True
|
||||||
|
|
||||||
__test__ = {'API_TESTS':"""
|
__test__ = {'API_TESTS':"""
|
||||||
>>> from django.core import management
|
>>> from django.core import management
|
||||||
|
|
||||||
@ -170,4 +178,18 @@ Weight = 1.2 (<type 'float'>)
|
|||||||
>>> management.call_command('dumpdata', 'fixtures_regress.animal', format='json')
|
>>> management.call_command('dumpdata', 'fixtures_regress.animal', format='json')
|
||||||
[{"pk": 1, "model": "fixtures_regress.animal", "fields": {"count": 3, "weight": 1.2, "name": "Lion", "latin_name": "Panthera leo"}}, {"pk": 2, "model": "fixtures_regress.animal", "fields": {"count": 2, "weight": 2.29..., "name": "Platypus", "latin_name": "Ornithorhynchus anatinus"}}, {"pk": 10, "model": "fixtures_regress.animal", "fields": {"count": 42, "weight": 1.2, "name": "Emu", "latin_name": "Dromaius novaehollandiae"}}]
|
[{"pk": 1, "model": "fixtures_regress.animal", "fields": {"count": 3, "weight": 1.2, "name": "Lion", "latin_name": "Panthera leo"}}, {"pk": 2, "model": "fixtures_regress.animal", "fields": {"count": 2, "weight": 2.29..., "name": "Platypus", "latin_name": "Ornithorhynchus anatinus"}}, {"pk": 10, "model": "fixtures_regress.animal", "fields": {"count": 42, "weight": 1.2, "name": "Emu", "latin_name": "Dromaius novaehollandiae"}}]
|
||||||
|
|
||||||
|
###############################################
|
||||||
|
# Regression for #11428 - Proxy models aren't included
|
||||||
|
# when you run dumpdata over an entire app
|
||||||
|
|
||||||
|
# Flush out the database first
|
||||||
|
>>> management.call_command('reset', 'fixtures_regress', interactive=False, verbosity=0)
|
||||||
|
|
||||||
|
# Create an instance of the concrete class
|
||||||
|
>>> Widget(name='grommet').save()
|
||||||
|
|
||||||
|
# Dump data for the entire app. The proxy class shouldn't be included
|
||||||
|
>>> management.call_command('dumpdata', 'fixtures_regress', format='json')
|
||||||
|
[{"pk": 1, "model": "fixtures_regress.widget", "fields": {"name": "grommet"}}]
|
||||||
|
|
||||||
"""}
|
"""}
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"pk": "1",
|
||||||
|
"model": "m2m_through_regress.person",
|
||||||
|
"fields": {
|
||||||
|
"name": "Guido"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": "1",
|
||||||
|
"model": "auth.user",
|
||||||
|
"fields": {
|
||||||
|
"username": "Guido",
|
||||||
|
"email": "bdfl@python.org",
|
||||||
|
"password": "abcde"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": "1",
|
||||||
|
"model": "m2m_through_regress.group",
|
||||||
|
"fields": {
|
||||||
|
"name": "Python Core Group"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": "1",
|
||||||
|
"model": "m2m_through_regress.usermembership",
|
||||||
|
"fields": {
|
||||||
|
"user": "1",
|
||||||
|
"group": "1",
|
||||||
|
"price": "100"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
@ -12,7 +12,9 @@ class Membership(models.Model):
|
|||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return "%s is a member of %s" % (self.person.name, self.group.name)
|
return "%s is a member of %s" % (self.person.name, self.group.name)
|
||||||
|
|
||||||
|
# using custom id column to test ticket #11107
|
||||||
class UserMembership(models.Model):
|
class UserMembership(models.Model):
|
||||||
|
id = models.AutoField(db_column='usermembership_id', primary_key=True)
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User)
|
||||||
group = models.ForeignKey('Group')
|
group = models.ForeignKey('Group')
|
||||||
price = models.IntegerField(default=100)
|
price = models.IntegerField(default=100)
|
||||||
@ -196,4 +198,12 @@ doing a join.
|
|||||||
# Flush the database, just to make sure we can.
|
# Flush the database, just to make sure we can.
|
||||||
>>> management.call_command('flush', verbosity=0, interactive=False)
|
>>> management.call_command('flush', verbosity=0, interactive=False)
|
||||||
|
|
||||||
|
## Regression test for #11107
|
||||||
|
Ensure that sequences on m2m_through tables are being created for the through
|
||||||
|
model, not for a phantom auto-generated m2m table.
|
||||||
|
|
||||||
|
>>> management.call_command('loaddata', 'm2m_through', verbosity=0)
|
||||||
|
>>> management.call_command('dumpdata', 'm2m_through_regress', format='json')
|
||||||
|
[{"pk": 1, "model": "m2m_through_regress.usermembership", "fields": {"price": 100, "group": 1, "user": 1}}, {"pk": 1, "model": "m2m_through_regress.person", "fields": {"name": "Guido"}}, {"pk": 1, "model": "m2m_through_regress.group", "fields": {"name": "Python Core Group"}}]
|
||||||
|
|
||||||
"""}
|
"""}
|
||||||
|
@ -115,8 +115,7 @@ To: to@example.com
|
|||||||
Date: Fri, 09 Nov 2001 01:08:47 -0000
|
Date: Fri, 09 Nov 2001 01:08:47 -0000
|
||||||
Message-ID: foo
|
Message-ID: foo
|
||||||
...
|
...
|
||||||
Content-Type: multipart/alternative; boundary="..."
|
Content-Type: multipart/alternative;...
|
||||||
MIME-Version: 1.0
|
|
||||||
...
|
...
|
||||||
Content-Type: text/plain; charset="utf-8"
|
Content-Type: text/plain; charset="utf-8"
|
||||||
MIME-Version: 1.0
|
MIME-Version: 1.0
|
||||||
|
0
tests/regressiontests/servers/__init__.py
Normal file
0
tests/regressiontests/servers/__init__.py
Normal file
0
tests/regressiontests/servers/models.py
Normal file
0
tests/regressiontests/servers/models.py
Normal file
67
tests/regressiontests/servers/tests.py
Normal file
67
tests/regressiontests/servers/tests.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
"""
|
||||||
|
Tests for django.core.servers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
import django
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.core.handlers.wsgi import WSGIHandler
|
||||||
|
from django.core.servers.basehttp import AdminMediaHandler
|
||||||
|
|
||||||
|
|
||||||
|
class AdminMediaHandlerTests(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.admin_media_file_path = \
|
||||||
|
os.path.join(django.__path__[0], 'contrib', 'admin', 'media')
|
||||||
|
self.handler = AdminMediaHandler(WSGIHandler())
|
||||||
|
|
||||||
|
def test_media_urls(self):
|
||||||
|
"""
|
||||||
|
Tests that URLs that look like absolute file paths after the
|
||||||
|
settings.ADMIN_MEDIA_PREFIX don't turn into absolute file paths.
|
||||||
|
"""
|
||||||
|
# Cases that should work on all platforms.
|
||||||
|
data = (
|
||||||
|
('/media/css/base.css', ('css', 'base.css')),
|
||||||
|
)
|
||||||
|
# Cases that should raise an exception.
|
||||||
|
bad_data = ()
|
||||||
|
|
||||||
|
# Add platform-specific cases.
|
||||||
|
if os.sep == '/':
|
||||||
|
data += (
|
||||||
|
# URL, tuple of relative path parts.
|
||||||
|
('/media/\\css/base.css', ('\\css', 'base.css')),
|
||||||
|
)
|
||||||
|
bad_data += (
|
||||||
|
'/media//css/base.css',
|
||||||
|
'/media////css/base.css',
|
||||||
|
'/media/../css/base.css',
|
||||||
|
)
|
||||||
|
elif os.sep == '\\':
|
||||||
|
bad_data += (
|
||||||
|
'/media/C:\css/base.css',
|
||||||
|
'/media//\\css/base.css',
|
||||||
|
'/media/\\css/base.css',
|
||||||
|
'/media/\\\\css/base.css'
|
||||||
|
)
|
||||||
|
for url, path_tuple in data:
|
||||||
|
try:
|
||||||
|
output = self.handler.file_path(url)
|
||||||
|
except ValueError:
|
||||||
|
self.fail("Got a ValueError exception, but wasn't expecting"
|
||||||
|
" one. URL was: %s" % url)
|
||||||
|
rel_path = os.path.join(*path_tuple)
|
||||||
|
desired = os.path.normcase(
|
||||||
|
os.path.join(self.admin_media_file_path, rel_path))
|
||||||
|
self.assertEqual(output, desired,
|
||||||
|
"Got: %s, Expected: %s, URL was: %s" % (output, desired, url))
|
||||||
|
for url in bad_data:
|
||||||
|
try:
|
||||||
|
output = self.handler.file_path(url)
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
self.fail('URL: %s should have caused a ValueError exception.'
|
||||||
|
% url)
|
@ -0,0 +1,13 @@
|
|||||||
|
from django.conf.urls.defaults import *
|
||||||
|
from namespace_urls import URLObject
|
||||||
|
|
||||||
|
testobj3 = URLObject('testapp', 'test-ns3')
|
||||||
|
|
||||||
|
urlpatterns = patterns('regressiontests.urlpatterns_reverse.views',
|
||||||
|
url(r'^normal/$', 'empty_view', name='inc-normal-view'),
|
||||||
|
url(r'^normal/(?P<arg1>\d+)/(?P<arg2>\d+)/$', 'empty_view', name='inc-normal-view'),
|
||||||
|
|
||||||
|
(r'^test3/', include(testobj3.urls)),
|
||||||
|
(r'^ns-included3/', include('regressiontests.urlpatterns_reverse.included_urls', namespace='inc-ns3')),
|
||||||
|
)
|
||||||
|
|
38
tests/regressiontests/urlpatterns_reverse/namespace_urls.py
Normal file
38
tests/regressiontests/urlpatterns_reverse/namespace_urls.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
from django.conf.urls.defaults import *
|
||||||
|
|
||||||
|
class URLObject(object):
|
||||||
|
def __init__(self, app_name, namespace):
|
||||||
|
self.app_name = app_name
|
||||||
|
self.namespace = namespace
|
||||||
|
|
||||||
|
def urls(self):
|
||||||
|
return patterns('',
|
||||||
|
url(r'^inner/$', 'empty_view', name='urlobject-view'),
|
||||||
|
url(r'^inner/(?P<arg1>\d+)/(?P<arg2>\d+)/$', 'empty_view', name='urlobject-view'),
|
||||||
|
), self.app_name, self.namespace
|
||||||
|
urls = property(urls)
|
||||||
|
|
||||||
|
testobj1 = URLObject('testapp', 'test-ns1')
|
||||||
|
testobj2 = URLObject('testapp', 'test-ns2')
|
||||||
|
default_testobj = URLObject('testapp', 'testapp')
|
||||||
|
|
||||||
|
otherobj1 = URLObject('nodefault', 'other-ns1')
|
||||||
|
otherobj2 = URLObject('nodefault', 'other-ns2')
|
||||||
|
|
||||||
|
urlpatterns = patterns('regressiontests.urlpatterns_reverse.views',
|
||||||
|
url(r'^normal/$', 'empty_view', name='normal-view'),
|
||||||
|
url(r'^normal/(?P<arg1>\d+)/(?P<arg2>\d+)/$', 'empty_view', name='normal-view'),
|
||||||
|
|
||||||
|
(r'^test1/', include(testobj1.urls)),
|
||||||
|
(r'^test2/', include(testobj2.urls)),
|
||||||
|
(r'^default/', include(default_testobj.urls)),
|
||||||
|
|
||||||
|
(r'^other1/', include(otherobj1.urls)),
|
||||||
|
(r'^other2/', include(otherobj2.urls)),
|
||||||
|
|
||||||
|
(r'^ns-included1/', include('regressiontests.urlpatterns_reverse.included_namespace_urls', namespace='inc-ns1')),
|
||||||
|
(r'^ns-included2/', include('regressiontests.urlpatterns_reverse.included_namespace_urls', namespace='inc-ns2')),
|
||||||
|
|
||||||
|
(r'^included/', include('regressiontests.urlpatterns_reverse.included_namespace_urls')),
|
||||||
|
|
||||||
|
)
|
@ -159,3 +159,83 @@ class ReverseShortcutTests(TestCase):
|
|||||||
self.assertEqual(res['Location'], '/foo/')
|
self.assertEqual(res['Location'], '/foo/')
|
||||||
res = redirect('http://example.com/')
|
res = redirect('http://example.com/')
|
||||||
self.assertEqual(res['Location'], 'http://example.com/')
|
self.assertEqual(res['Location'], 'http://example.com/')
|
||||||
|
|
||||||
|
|
||||||
|
class NamespaceTests(TestCase):
|
||||||
|
urls = 'regressiontests.urlpatterns_reverse.namespace_urls'
|
||||||
|
|
||||||
|
def test_ambiguous_object(self):
|
||||||
|
"Names deployed via dynamic URL objects that require namespaces can't be resolved"
|
||||||
|
self.assertRaises(NoReverseMatch, reverse, 'urlobject-view')
|
||||||
|
self.assertRaises(NoReverseMatch, reverse, 'urlobject-view', args=[37,42])
|
||||||
|
self.assertRaises(NoReverseMatch, reverse, 'urlobject-view', kwargs={'arg1':42, 'arg2':37})
|
||||||
|
|
||||||
|
def test_ambiguous_urlpattern(self):
|
||||||
|
"Names deployed via dynamic URL objects that require namespaces can't be resolved"
|
||||||
|
self.assertRaises(NoReverseMatch, reverse, 'inner-nothing')
|
||||||
|
self.assertRaises(NoReverseMatch, reverse, 'inner-nothing', args=[37,42])
|
||||||
|
self.assertRaises(NoReverseMatch, reverse, 'inner-nothing', kwargs={'arg1':42, 'arg2':37})
|
||||||
|
|
||||||
|
def test_non_existent_namespace(self):
|
||||||
|
"Non-existent namespaces raise errors"
|
||||||
|
self.assertRaises(NoReverseMatch, reverse, 'blahblah:urlobject-view')
|
||||||
|
self.assertRaises(NoReverseMatch, reverse, 'test-ns1:blahblah:urlobject-view')
|
||||||
|
|
||||||
|
def test_normal_name(self):
|
||||||
|
"Normal lookups work as expected"
|
||||||
|
self.assertEquals('/normal/', reverse('normal-view'))
|
||||||
|
self.assertEquals('/normal/37/42/', reverse('normal-view', args=[37,42]))
|
||||||
|
self.assertEquals('/normal/42/37/', reverse('normal-view', kwargs={'arg1':42, 'arg2':37}))
|
||||||
|
|
||||||
|
def test_simple_included_name(self):
|
||||||
|
"Normal lookups work on names included from other patterns"
|
||||||
|
self.assertEquals('/included/normal/', reverse('inc-normal-view'))
|
||||||
|
self.assertEquals('/included/normal/37/42/', reverse('inc-normal-view', args=[37,42]))
|
||||||
|
self.assertEquals('/included/normal/42/37/', reverse('inc-normal-view', kwargs={'arg1':42, 'arg2':37}))
|
||||||
|
|
||||||
|
def test_namespace_object(self):
|
||||||
|
"Dynamic URL objects can be found using a namespace"
|
||||||
|
self.assertEquals('/test1/inner/', reverse('test-ns1:urlobject-view'))
|
||||||
|
self.assertEquals('/test1/inner/37/42/', reverse('test-ns1:urlobject-view', args=[37,42]))
|
||||||
|
self.assertEquals('/test1/inner/42/37/', reverse('test-ns1:urlobject-view', kwargs={'arg1':42, 'arg2':37}))
|
||||||
|
|
||||||
|
def test_embedded_namespace_object(self):
|
||||||
|
"Namespaces can be installed anywhere in the URL pattern tree"
|
||||||
|
self.assertEquals('/included/test3/inner/', reverse('test-ns3:urlobject-view'))
|
||||||
|
self.assertEquals('/included/test3/inner/37/42/', reverse('test-ns3:urlobject-view', args=[37,42]))
|
||||||
|
self.assertEquals('/included/test3/inner/42/37/', reverse('test-ns3:urlobject-view', kwargs={'arg1':42, 'arg2':37}))
|
||||||
|
|
||||||
|
def test_namespace_pattern(self):
|
||||||
|
"Namespaces can be applied to include()'d urlpatterns"
|
||||||
|
self.assertEquals('/ns-included1/normal/', reverse('inc-ns1:inc-normal-view'))
|
||||||
|
self.assertEquals('/ns-included1/normal/37/42/', reverse('inc-ns1:inc-normal-view', args=[37,42]))
|
||||||
|
self.assertEquals('/ns-included1/normal/42/37/', reverse('inc-ns1:inc-normal-view', kwargs={'arg1':42, 'arg2':37}))
|
||||||
|
|
||||||
|
def test_multiple_namespace_pattern(self):
|
||||||
|
"Namespaces can be embedded"
|
||||||
|
self.assertEquals('/ns-included1/test3/inner/', reverse('inc-ns1:test-ns3:urlobject-view'))
|
||||||
|
self.assertEquals('/ns-included1/test3/inner/37/42/', reverse('inc-ns1:test-ns3:urlobject-view', args=[37,42]))
|
||||||
|
self.assertEquals('/ns-included1/test3/inner/42/37/', reverse('inc-ns1:test-ns3:urlobject-view', kwargs={'arg1':42, 'arg2':37}))
|
||||||
|
|
||||||
|
def test_app_lookup_object(self):
|
||||||
|
"A default application namespace can be used for lookup"
|
||||||
|
self.assertEquals('/default/inner/', reverse('testapp:urlobject-view'))
|
||||||
|
self.assertEquals('/default/inner/37/42/', reverse('testapp:urlobject-view', args=[37,42]))
|
||||||
|
self.assertEquals('/default/inner/42/37/', reverse('testapp:urlobject-view', kwargs={'arg1':42, 'arg2':37}))
|
||||||
|
|
||||||
|
def test_app_lookup_object_with_default(self):
|
||||||
|
"A default application namespace is sensitive to the 'current' app can be used for lookup"
|
||||||
|
self.assertEquals('/included/test3/inner/', reverse('testapp:urlobject-view', current_app='test-ns3'))
|
||||||
|
self.assertEquals('/included/test3/inner/37/42/', reverse('testapp:urlobject-view', args=[37,42], current_app='test-ns3'))
|
||||||
|
self.assertEquals('/included/test3/inner/42/37/', reverse('testapp:urlobject-view', kwargs={'arg1':42, 'arg2':37}, current_app='test-ns3'))
|
||||||
|
|
||||||
|
def test_app_lookup_object_without_default(self):
|
||||||
|
"An application namespace without a default is sensitive to the 'current' app can be used for lookup"
|
||||||
|
self.assertEquals('/other2/inner/', reverse('nodefault:urlobject-view'))
|
||||||
|
self.assertEquals('/other2/inner/37/42/', reverse('nodefault:urlobject-view', args=[37,42]))
|
||||||
|
self.assertEquals('/other2/inner/42/37/', reverse('nodefault:urlobject-view', kwargs={'arg1':42, 'arg2':37}))
|
||||||
|
|
||||||
|
self.assertEquals('/other1/inner/', reverse('nodefault:urlobject-view', current_app='other-ns1'))
|
||||||
|
self.assertEquals('/other1/inner/37/42/', reverse('nodefault:urlobject-view', args=[37,42], current_app='other-ns1'))
|
||||||
|
self.assertEquals('/other1/inner/42/37/', reverse('nodefault:urlobject-view', kwargs={'arg1':42, 'arg2':37}, current_app='other-ns1'))
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user