1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

[soc2009/multidb] Merged up to trunk r11917.

git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/multidb@11920 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Alex Gaynor 2009-12-19 18:03:58 +00:00
parent df2746b16c
commit 42c03cbeae
19 changed files with 284 additions and 15 deletions

View File

@ -353,6 +353,13 @@ class ModelAdmin(BaseModelAdmin):
defaults.update(kwargs) defaults.update(kwargs)
return modelform_factory(self.model, **defaults) return modelform_factory(self.model, **defaults)
def get_changelist(self, request, **kwargs):
"""
Returns the ChangeList class for use on the changelist page.
"""
from django.contrib.admin.views.main import ChangeList
return ChangeList
def get_changelist_form(self, request, **kwargs): def get_changelist_form(self, request, **kwargs):
""" """
Returns a Form class for use in the Formset on the changelist page. Returns a Form class for use in the Formset on the changelist page.
@ -896,7 +903,7 @@ class ModelAdmin(BaseModelAdmin):
@csrf_protect @csrf_protect
def changelist_view(self, request, extra_context=None): def changelist_view(self, request, extra_context=None):
"The 'change list' admin view for this model." "The 'change list' admin view for this model."
from django.contrib.admin.views.main import ChangeList, ERROR_FLAG from django.contrib.admin.views.main import ERROR_FLAG
opts = self.model._meta opts = self.model._meta
app_label = opts.app_label app_label = opts.app_label
if not self.has_change_permission(request, None): if not self.has_change_permission(request, None):
@ -913,6 +920,7 @@ class ModelAdmin(BaseModelAdmin):
except ValueError: except ValueError:
pass pass
ChangeList = self.get_changelist(request)
try: try:
cl = ChangeList(request, self.model, list_display, self.list_display_links, self.list_filter, cl = ChangeList(request, self.model, list_display, self.list_display_links, self.list_filter,
self.date_hierarchy, self.search_fields, self.list_select_related, self.list_per_page, self.list_editable, self) self.date_hierarchy, self.search_fields, self.list_select_related, self.list_per_page, self.list_editable, self)

View File

@ -9,7 +9,7 @@ def shortcut(request, content_type_id, object_id):
try: try:
content_type = ContentType.objects.get(pk=content_type_id) content_type = ContentType.objects.get(pk=content_type_id)
obj = content_type.get_object_for_this_type(pk=object_id) obj = content_type.get_object_for_this_type(pk=object_id)
except ObjectDoesNotExist: except (ObjectDoesNotExist, ValueError):
raise http.Http404("Content type %s object %s doesn't exist" % (content_type_id, object_id)) raise http.Http404("Content type %s object %s doesn't exist" % (content_type_id, object_id))
try: try:
absurl = obj.get_absolute_url() absurl = obj.get_absolute_url()

View File

@ -88,7 +88,17 @@ class Command(BaseCommand):
if has_bz2: if has_bz2:
compression_types['bz2'] = bz2.BZ2File compression_types['bz2'] = bz2.BZ2File
app_fixtures = [os.path.join(os.path.dirname(app.__file__), 'fixtures') for app in get_apps()] app_module_paths = []
for app in get_apps():
if hasattr(app, '__path__'):
# It's a 'models/' subpackage
for path in app.__path__:
app_module_paths.append(path)
else:
# It's a models.py module
app_module_paths.append(app.__file__)
app_fixtures = [os.path.join(os.path.dirname(path), 'fixtures') for path in app_module_paths]
for fixture_label in fixture_labels: for fixture_label in fixture_labels:
parts = fixture_label.split('.') parts = fixture_label.split('.')

View File

@ -34,3 +34,42 @@ class DatabaseCreation(BaseDatabaseCreation):
if self.connection.settings_dict['TEST_CHARSET']: if self.connection.settings_dict['TEST_CHARSET']:
return "WITH ENCODING '%s'" % self.connection.settings_dict['TEST_CHARSET'] return "WITH ENCODING '%s'" % self.connection.settings_dict['TEST_CHARSET']
return '' return ''
def sql_indexes_for_field(self, model, f, style):
if f.db_index and not f.unique:
qn = self.connection.ops.quote_name
db_table = model._meta.db_table
tablespace = f.db_tablespace or model._meta.db_tablespace
if tablespace:
sql = self.connection.ops.tablespace_sql(tablespace)
if sql:
tablespace_sql = ' ' + sql
else:
tablespace_sql = ''
else:
tablespace_sql = ''
def get_index_sql(index_name, opclass=''):
return (style.SQL_KEYWORD('CREATE INDEX') + ' ' +
style.SQL_TABLE(qn(index_name)) + ' ' +
style.SQL_KEYWORD('ON') + ' ' +
style.SQL_TABLE(qn(db_table)) + ' ' +
"(%s%s)" % (style.SQL_FIELD(qn(f.column)), opclass) +
"%s;" % tablespace_sql)
output = [get_index_sql('%s_%s' % (db_table, f.column))]
# Fields with database column types of `varchar` and `text` need
# a second index that specifies their operator class, which is
# needed when performing correct LIKE queries outside the
# C locale. See #12234.
db_type = f.db_type()
if db_type.startswith('varchar'):
output.append(get_index_sql('%s_%s_like' % (db_table, f.column),
' varchar_pattern_ops'))
elif db_type.startswith('text'):
output.append(get_index_sql('%s_%s_like' % (db_table, f.column),
' text_pattern_ops'))
else:
output = []
return output

View File

@ -328,6 +328,8 @@ class QuerySet(object):
keyword arguments. keyword arguments.
""" """
clone = self.filter(*args, **kwargs) clone = self.filter(*args, **kwargs)
if self.query.can_filter():
clone = clone.order_by()
num = len(clone) num = len(clone)
if num == 1: if num == 1:
return clone._result_cache[0] return clone._result_cache[0]
@ -394,7 +396,7 @@ class QuerySet(object):
""" """
assert self.query.can_filter(), \ assert self.query.can_filter(), \
"Cannot use 'limit' or 'offset' with in_bulk" "Cannot use 'limit' or 'offset' with in_bulk"
assert isinstance(id_list, (tuple, list)), \ assert isinstance(id_list, (tuple, list, set, frozenset)), \
"in_bulk() must be provided with a list of IDs." "in_bulk() must be provided with a list of IDs."
if not id_list: if not id_list:
return {} return {}

View File

@ -82,6 +82,21 @@ You should also audit your existing code for any instances of this behavior
before enabling this feature. It's faster, but it provides less automatic before enabling this feature. It's faster, but it provides less automatic
protection for multi-call operations. protection for multi-call operations.
Indexes for ``varchar`` and ``text`` columns
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 1.1.2
When specifying ``db_index=True`` on your model fields, Django typically
outputs a single ``CREATE INDEX`` statement. However, if the database type
for the field is either ``varchar`` or ``text`` (e.g., used by ``CharField``,
``FileField``, and ``TextField``), then Django will create
an additional index that uses an appropriate `PostgreSQL operator class`_
for the column. The extra index is necessary to correctly perfrom
lookups that use the ``LIKE`` operator in their SQL, as is done with the
``contains`` and ``startswith`` lookup types.
.. _PostgreSQL operator class: http://www.postgresql.org/docs/8.4/static/indexes-opclass.html
.. _mysql-notes: .. _mysql-notes:
MySQL notes MySQL notes

View File

@ -225,8 +225,9 @@ Methods
.. method:: models.User.has_perm(perm, obj=None) .. method:: models.User.has_perm(perm, obj=None)
Returns ``True`` if the user has the specified permission, where perm is Returns ``True`` if the user has the specified permission, where perm is
in the format ``"<app label>.<permission codename>"``. in the format ``"<app label>.<permission codename>"``. (see
If the user is inactive, this method will always return ``False``. `permissions`_ section below). If the user is inactive, this method will
always return ``False``.
.. versionadded:: 1.2 .. versionadded:: 1.2
@ -1122,6 +1123,8 @@ generic view itself. For example::
def limited_object_detail(*args, **kwargs): def limited_object_detail(*args, **kwargs):
return object_detail(*args, **kwargs) return object_detail(*args, **kwargs)
.. _permissions:
Permissions Permissions
=========== ===========
@ -1164,6 +1167,14 @@ models being installed at that time. Afterward, it will create default
permissions for new models each time you run :djadmin:`manage.py syncdb permissions for new models each time you run :djadmin:`manage.py syncdb
<syncdb>`. <syncdb>`.
Assuming you have an application with an
:attr:`~django.db.models.Options.app_label` ``foo`` and a model named ``Bar``,
to test for basic permissions you should use:
* add: ``user.has_perm('foo.add_bar')``
* change: ``user.has_perm('foo.change_bar')``
* delete: ``user.has_perm('foo.delete_bar')``
.. _custom-permissions: .. _custom-permissions:
Custom permissions Custom permissions

View File

@ -264,7 +264,7 @@ name::
class PersonManager(models.Manager): class PersonManager(models.Manager):
def get_by_natural_key(self, first_name, last_name): def get_by_natural_key(self, first_name, last_name):
return self.filter(first_name=first_name, last_name=last_name) return self.get(first_name=first_name, last_name=last_name)
class Person(models.Model): class Person(models.Model):
objects = PersonManager() objects = PersonManager()

View File

@ -0,0 +1,2 @@

View File

@ -0,0 +1,18 @@
[
{
"pk": "2",
"model": "fixtures_model_package.article",
"fields": {
"headline": "Poker has no place on ESPN",
"pub_date": "2006-06-16 12:00:00"
}
},
{
"pk": "3",
"model": "fixtures_model_package.article",
"fields": {
"headline": "Time to reform copyright",
"pub_date": "2006-06-16 13:00:00"
}
}
]

View File

@ -0,0 +1,18 @@
[
{
"pk": "3",
"model": "fixtures_model_package.article",
"fields": {
"headline": "Copyright is fine the way it is",
"pub_date": "2006-06-16 14:00:00"
}
},
{
"pk": "4",
"model": "fixtures_model_package.article",
"fields": {
"headline": "Django conquers world!",
"pub_date": "2006-06-16 15:00:00"
}
}
]

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
<object pk="2" model="fixtures_model_package.article">
<field type="CharField" name="headline">Poker on TV is great!</field>
<field type="DateTimeField" name="pub_date">2006-06-16 11:00:00</field>
</object>
<object pk="5" model="fixtures_model_package.article">
<field type="CharField" name="headline">XML identified as leading cause of cancer</field>
<field type="DateTimeField" name="pub_date">2006-06-16 16:00:00</field>
</object>
</django-objects>

View File

@ -0,0 +1,10 @@
[
{
"pk": "1",
"model": "fixtures_model_package.article",
"fields": {
"headline": "Python program becomes self aware",
"pub_date": "2006-06-16 11:00:00"
}
}
]

View File

@ -0,0 +1,54 @@
from django.db import models
from django.conf import settings
class Article(models.Model):
headline = models.CharField(max_length=100, default='Default headline')
pub_date = models.DateTimeField()
def __unicode__(self):
return self.headline
class Meta:
app_label = 'fixtures_model_package'
ordering = ('-pub_date', 'headline')
__test__ = {'API_TESTS': """
>>> from django.core import management
>>> from django.db.models import get_app
# Reset the database representation of this app.
# This will return the database to a clean initial state.
>>> management.call_command('flush', verbosity=0, interactive=False)
# Syncdb introduces 1 initial data object from initial_data.json.
>>> Article.objects.all()
[<Article: Python program becomes self aware>]
# Load fixture 1. Single JSON file, with two objects.
>>> management.call_command('loaddata', 'fixture1.json', verbosity=0)
>>> Article.objects.all()
[<Article: Time to reform copyright>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]
# Load fixture 2. JSON file imported by default. Overwrites some existing objects
>>> management.call_command('loaddata', 'fixture2.json', verbosity=0)
>>> Article.objects.all()
[<Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]
# Load a fixture that doesn't exist
>>> management.call_command('loaddata', 'unknown.json', verbosity=0)
# object list is unaffected
>>> Article.objects.all()
[<Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]
"""}
from django.test import TestCase
class SampleTestCase(TestCase):
fixtures = ['fixture1.json', 'fixture2.json']
def testClassFixtures(self):
"Check that test case has installed 4 fixture objects"
self.assertEqual(Article.objects.count(), 4)
self.assertEquals(str(Article.objects.all()), "[<Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]")

View File

@ -104,6 +104,12 @@ Article 4
<Article: Article 2> <Article: Article 2>
>>> Article.objects.in_bulk([3]) >>> Article.objects.in_bulk([3])
{3: <Article: Article 3>} {3: <Article: Article 3>}
>>> Article.objects.in_bulk(set([3]))
{3: <Article: Article 3>}
>>> Article.objects.in_bulk(frozenset([3]))
{3: <Article: Article 3>}
>>> Article.objects.in_bulk((3,))
{3: <Article: Article 3>}
>>> Article.objects.in_bulk([1000]) >>> Article.objects.in_bulk([1000])
{} {}
>>> Article.objects.in_bulk([]) >>> Article.objects.in_bulk([])

View File

@ -4,6 +4,7 @@ import os
from django.core.files.storage import FileSystemStorage from django.core.files.storage import FileSystemStorage
from django.db import models from django.db import models
from django.contrib import admin from django.contrib import admin
from django.contrib.admin.views.main import ChangeList
from django.core.mail import EmailMessage from django.core.mail import EmailMessage
class Section(models.Model): class Section(models.Model):
@ -420,6 +421,20 @@ class CategoryInline(admin.StackedInline):
class CollectorAdmin(admin.ModelAdmin): class CollectorAdmin(admin.ModelAdmin):
inlines = [WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline, FancyDoodadInline, CategoryInline] inlines = [WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline, FancyDoodadInline, CategoryInline]
class Gadget(models.Model):
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class CustomChangeList(ChangeList):
def get_query_set(self):
return self.root_query_set.filter(pk=9999) # Does not exist
class GadgetAdmin(admin.ModelAdmin):
def get_changelist(self, request, **kwargs):
return CustomChangeList
admin.site.register(Article, ArticleAdmin) admin.site.register(Article, ArticleAdmin)
admin.site.register(CustomArticle, CustomArticleAdmin) admin.site.register(CustomArticle, CustomArticleAdmin)
admin.site.register(Section, save_as=True, inlines=[ArticleInline]) admin.site.register(Section, save_as=True, inlines=[ArticleInline])
@ -443,6 +458,7 @@ 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) admin.site.register(Category, CategoryAdmin)
admin.site.register(Gadget, GadgetAdmin)
# 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:

View File

@ -1203,6 +1203,33 @@ class AdminActionsTest(TestCase):
self.failUnlessEqual(Subscriber.objects.count(), 2) self.failUnlessEqual(Subscriber.objects.count(), 2)
class TestCustomChangeList(TestCase):
fixtures = ['admin-views-users.xml']
urlbit = 'admin'
def setUp(self):
result = self.client.login(username='super', password='secret')
self.failUnlessEqual(result, True)
def tearDown(self):
self.client.logout()
def test_custom_changelist(self):
"""
Validate that a custom ChangeList class can be used (#9749)
"""
# Insert some data
post_data = {"name": u"First Gadget"}
response = self.client.post('/test_admin/%s/admin_views/gadget/add/' % self.urlbit, post_data)
self.failUnlessEqual(response.status_code, 302) # redirect somewhere
# Hit the page once to get messages out of the queue message list
response = self.client.get('/test_admin/%s/admin_views/gadget/' % self.urlbit)
# Ensure that that data is still not visible on the page
response = self.client.get('/test_admin/%s/admin_views/gadget/' % self.urlbit)
self.failUnlessEqual(response.status_code, 200)
self.assertNotContains(response, 'First Gadget')
class TestInlineNotEditable(TestCase): class TestInlineNotEditable(TestCase):
fixtures = ['admin-views-users.xml'] fixtures = ['admin-views-users.xml']

View File

@ -89,22 +89,22 @@ class GenericAdminViewTest(TestCase):
# Works with no queryset # Works with no queryset
formset = EpisodeMediaFormSet(instance=e) formset = EpisodeMediaFormSet(instance=e)
self.assertEquals(len(formset.forms), 5) self.assertEquals(len(formset.forms), 5)
self.assertEquals(formset.forms[0].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="text" name="generic_inline_admin-media-content_type-object_id-0-url" value="http://example.com/podcast.mp3" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" value="1" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>') self.assertEquals(formset.forms[0].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="text" name="generic_inline_admin-media-content_type-object_id-0-url" value="http://example.com/podcast.mp3" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>' % self.mp3_media_pk)
self.assertEquals(formset.forms[1].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" type="text" name="generic_inline_admin-media-content_type-object_id-1-url" value="http://example.com/logo.png" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" value="2" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>') self.assertEquals(formset.forms[1].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" type="text" name="generic_inline_admin-media-content_type-object_id-1-url" value="http://example.com/logo.png" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>' % self.png_media_pk)
self.assertEquals(formset.forms[2].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-2-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-2-url" type="text" name="generic_inline_admin-media-content_type-object_id-2-url" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-2-id" id="id_generic_inline_admin-media-content_type-object_id-2-id" /></p>') self.assertEquals(formset.forms[2].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-2-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-2-url" type="text" name="generic_inline_admin-media-content_type-object_id-2-url" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-2-id" id="id_generic_inline_admin-media-content_type-object_id-2-id" /></p>')
# A queryset can be used to alter display ordering # A queryset can be used to alter display ordering
formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.order_by('url')) formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.order_by('url'))
self.assertEquals(len(formset.forms), 5) self.assertEquals(len(formset.forms), 5)
self.assertEquals(formset.forms[0].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="text" name="generic_inline_admin-media-content_type-object_id-0-url" value="http://example.com/logo.png" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" value="2" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>') self.assertEquals(formset.forms[0].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="text" name="generic_inline_admin-media-content_type-object_id-0-url" value="http://example.com/logo.png" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>' % self.png_media_pk)
self.assertEquals(formset.forms[1].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" type="text" name="generic_inline_admin-media-content_type-object_id-1-url" value="http://example.com/podcast.mp3" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" value="1" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>') self.assertEquals(formset.forms[1].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" type="text" name="generic_inline_admin-media-content_type-object_id-1-url" value="http://example.com/podcast.mp3" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>' % self.mp3_media_pk)
self.assertEquals(formset.forms[2].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-2-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-2-url" type="text" name="generic_inline_admin-media-content_type-object_id-2-url" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-2-id" id="id_generic_inline_admin-media-content_type-object_id-2-id" /></p>') self.assertEquals(formset.forms[2].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-2-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-2-url" type="text" name="generic_inline_admin-media-content_type-object_id-2-url" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-2-id" id="id_generic_inline_admin-media-content_type-object_id-2-id" /></p>')
# Works with a queryset that omits items # Works with a queryset that omits items
formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.filter(url__endswith=".png")) formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.filter(url__endswith=".png"))
self.assertEquals(len(formset.forms), 4) self.assertEquals(len(formset.forms), 4)
self.assertEquals(formset.forms[0].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="text" name="generic_inline_admin-media-content_type-object_id-0-url" value="http://example.com/logo.png" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" value="2" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>') self.assertEquals(formset.forms[0].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="text" name="generic_inline_admin-media-content_type-object_id-0-url" value="http://example.com/logo.png" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>' % self.png_media_pk)
self.assertEquals(formset.forms[1].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" type="text" name="generic_inline_admin-media-content_type-object_id-1-url" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>') self.assertEquals(formset.forms[1].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" type="text" name="generic_inline_admin-media-content_type-object_id-1-url" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>')
def testGenericInlineFormsetFactory(self): def testGenericInlineFormsetFactory(self):

View File

@ -10,8 +10,8 @@ class DefaultsTests(TestCase):
"""Test django views in django/views/defaults.py""" """Test django views in django/views/defaults.py"""
fixtures = ['testdata.json'] fixtures = ['testdata.json']
def test_shorcut_with_absolute_url(self): def test_shortcut_with_absolute_url(self):
"Can view a shortcut an Author object that has with a get_absolute_url method" "Can view a shortcut for an Author object that has a get_absolute_url method"
for obj in Author.objects.all(): for obj in Author.objects.all():
short_url = '/views/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Author).id, obj.pk) short_url = '/views/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Author).id, obj.pk)
response = self.client.get(short_url) response = self.client.get(short_url)
@ -19,12 +19,34 @@ class DefaultsTests(TestCase):
status_code=302, target_status_code=404) status_code=302, target_status_code=404)
def test_shortcut_no_absolute_url(self): def test_shortcut_no_absolute_url(self):
"Shortcuts for an object that has with a get_absolute_url method raises 404" "Shortcuts for an object that has no get_absolute_url method raises 404"
for obj in Article.objects.all(): for obj in Article.objects.all():
short_url = '/views/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Article).id, obj.pk) short_url = '/views/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Article).id, obj.pk)
response = self.client.get(short_url) response = self.client.get(short_url)
self.assertEquals(response.status_code, 404) self.assertEquals(response.status_code, 404)
def test_wrong_type_pk(self):
short_url = '/views/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Author).id, 'nobody/expects')
response = self.client.get(short_url)
self.assertEquals(response.status_code, 404)
def test_shortcut_bad_pk(self):
short_url = '/views/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Author).id, '4242424242')
response = self.client.get(short_url)
self.assertEquals(response.status_code, 404)
def test_nonint_content_type(self):
an_author = Author.objects.all()[0]
short_url = '/views/shortcut/%s/%s/' % ('spam', an_author.pk)
response = self.client.get(short_url)
self.assertEquals(response.status_code, 404)
def test_bad_content_type(self):
an_author = Author.objects.all()[0]
short_url = '/views/shortcut/%s/%s/' % (4242424242, an_author.pk)
response = self.client.get(short_url)
self.assertEquals(response.status_code, 404)
def test_page_not_found(self): def test_page_not_found(self):
"A 404 status is returned by the page_not_found view" "A 404 status is returned by the page_not_found view"
non_existing_urls = ['/views/non_existing_url/', # this is in urls.py non_existing_urls = ['/views/non_existing_url/', # this is in urls.py