Ticket #13165: ticket13165_20111004.diff
File ticket13165_20111004.diff, 29.2 KB (added by , 13 years ago) |
---|
-
django/contrib/admin/helpers.py
diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py index 04a3492..98efe5a 100644
a b 1 1 from django import forms 2 from django.core.urlresolvers import reverse 2 3 from django.contrib.admin.util import (flatten_fieldsets, lookup_field, 3 4 display_for_field, label_for_field, help_text_for_field) 4 5 from django.contrib.admin.templatetags.admin_static import static … … class AdminReadonlyField(object): 189 190 result_repr = display_for_field(value, f) 190 191 return conditional_escape(result_repr) 191 192 193 192 194 class InlineAdminFormSet(object): 193 195 """ 194 196 A wrapper around an inline formset for use in the admin system. … … class InlineAdminForm(AdminForm): 251 253 self.formset = formset 252 254 self.model_admin = model_admin 253 255 self.original = original 256 self.admin_url = None 254 257 if original is not None: 255 258 self.original_content_type_id = ContentType.objects.get_for_model(original).pk 256 self.show_url = original and hasattr(original, 'get_absolute_url') 259 self.show_url = hasattr(original, 'get_absolute_url') 260 if (model_admin is not None and 261 original.__class__ in model_admin.admin_site._registry): 262 info = (original._meta.app_label, original._meta.object_name.lower()) 263 self.admin_url = reverse('admin:%s_%s_change' % info, args=(original.pk,), 264 current_app=model_admin.admin_site.name) 265 257 266 super(InlineAdminForm, self).__init__(form, fieldsets, prepopulated_fields, 258 267 readonly_fields, model_admin) 259 268 -
django/contrib/admin/static/admin/js/actions.js
diff --git a/django/contrib/admin/static/admin/js/actions.js b/django/contrib/admin/static/admin/js/actions.js index 94aa6db..80d2d91 100644
a b 136 136 allToggle: "#action-toggle", 137 137 selectedClass: "selected" 138 138 } 139 140 $(function(){ 141 /* Change the edit link next to foreign key selects 142 according to the selected value */ 143 $("a.change-related").click(function(e){ 144 e.preventDefault(); 145 window.open($(this).attr("href")); 146 }); 147 $("a.change-related").each( 148 function(i, el){ 149 var elem = $(el), 150 defaultHref = elem.attr("href"), 151 selectId = elem.attr("id").split("_").slice(1).join("_"); 152 $("#"+selectId).change(function(){ 153 var val = $(this).val(); 154 if (val === ""){ 155 elem.hide(); 156 return; 157 } 158 elem.show(); 159 var newHref = defaultHref.replace(/\/\d+\/$/, "/" + val + "/"); 160 elem.attr("href", newHref); 161 }); 162 } 163 ); 164 }); 139 165 })(django.jQuery); -
django/contrib/admin/static/admin/js/actions.min.js
diff --git a/django/contrib/admin/static/admin/js/actions.min.js b/django/contrib/admin/static/admin/js/actions.min.js index 21f00cd..5689fcc 100644
a b 1 (function(a){a.fn.actions=function( h){var b=a.extend({},a.fn.actions.defaults,h),e=a(this),f=false;checker=function(c){c?showQuestion():reset();a(e).attr("checked",c).parent().parent().toggleClass(b.selectedClass,c)};updateCounter=function(){var c=a(e).filter(":checked").length;a(b.counterContainer).html(interpolate(ngettext("%(sel)s of %(cnt)s selected","%(sel)s of %(cnt)s selected",c),{sel:c,cnt:_actions_icnt},true));a(b.allToggle).attr("checked",function(){if(c==e.length){value=true;showQuestion()}else{value=2 false;clearAcross()}return value})};showQuestion=function(){a(b.acrossClears).hide();a(b.acrossQuestions).show();a(b.allContainer).hide()};showClear=function(){a(b.acrossClears).show();a(b.acrossQuestions).hide();a(b.actionContainer).toggleClass(b.selectedClass);a(b.allContainer).show();a(b.counterContainer).hide()};reset=function(){a(b.acrossClears).hide();a(b.acrossQuestions).hide();a(b.allContainer).hide();a(b.counterContainer).show()};clearAcross=function(){reset();a(b.acrossInput).val(0);a(b.actionContainer).removeClass(b.selectedClass)};3 a(b.counterContainer).show();a(this).filter(":checked").each(function(){a(this).parent().parent().toggleClass(b.selectedClass);updateCounter();a(b.acrossInput).val()==1&&showClear()});a(b.allToggle).show().click(function(){checker(a(this).attr("checked"));updateCounter()});a("div.actions span.question a").click(function(c){c.preventDefault();a(b.acrossInput).val(1);showClear()});a("div.actions span.clear a").click(function(c){c.preventDefault();a(b.allToggle).attr("checked", false);clearAcross();checker(0);4 updateCounter()});lastChecked=null;a( e).click(function(c){if(!c)c=window.event;var d=c.target?c.target:c.srcElement;if(lastChecked&&a.data(lastChecked)!=a.data(d)&&c.shiftKey==true){var g=false;a(lastChecked).attr("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked);a(e).each(function(){if(a.data(this)==a.data(lastChecked)||a.data(this)==a.data(d))g=g?false:true;g&&a(this).attr("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked)})}a(d).parent().parent().toggleClass(b.selectedClass,5 d.checked);lastChecked=d;updateCounter()});a("form#changelist-form table#result_list tr").find("td:gt(0) :input").change(function(){f=true});a('form#changelist-form button[name="index"]').click(function(){if(f)return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."))});a('form#changelist-form input[name="_save"]').click(function(){var c=false;a("div.actions select option:selected").each(function(){if(a(this).val())c= 6 true});if(c)return f?confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action.")):confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button."))})};a.fn.actions.defaults={actionContainer:"div.actions",counterContainer:"span.action-counter",allContainer:"div.actions span.all",acrossInput:"div.actions input.select-across",7 acrossQuestions:"div.actions span.question",acrossClears:"div.actions span.clear",allToggle:"#action-toggle",selectedClass:"selected"} })(django.jQuery);1 (function(a){a.fn.actions=function(g){var b=a.extend({},a.fn.actions.defaults,g),d=a(this),e=!1;checker=function(c){c?showQuestion():reset();a(d).attr("checked",c).parent().parent().toggleClass(b.selectedClass,c)};updateCounter=function(){var c=a(d).filter(":checked").length;a(b.counterContainer).html(interpolate(ngettext("%(sel)s of %(cnt)s selected","%(sel)s of %(cnt)s selected",c),{sel:c,cnt:_actions_icnt},!0));a(b.allToggle).attr("checked",function(){c==d.length?(value=!0,showQuestion()):(value= 2 !1,clearAcross());return value})};showQuestion=function(){a(b.acrossClears).hide();a(b.acrossQuestions).show();a(b.allContainer).hide()};showClear=function(){a(b.acrossClears).show();a(b.acrossQuestions).hide();a(b.actionContainer).toggleClass(b.selectedClass);a(b.allContainer).show();a(b.counterContainer).hide()};reset=function(){a(b.acrossClears).hide();a(b.acrossQuestions).hide();a(b.allContainer).hide();a(b.counterContainer).show()};clearAcross=function(){reset();a(b.acrossInput).val(0);a(b.actionContainer).removeClass(b.selectedClass)}; 3 a(b.counterContainer).show();a(this).filter(":checked").each(function(){a(this).parent().parent().toggleClass(b.selectedClass);updateCounter();a(b.acrossInput).val()==1&&showClear()});a(b.allToggle).show().click(function(){checker(a(this).attr("checked"));updateCounter()});a("div.actions span.question a").click(function(c){c.preventDefault();a(b.acrossInput).val(1);showClear()});a("div.actions span.clear a").click(function(c){c.preventDefault();a(b.allToggle).attr("checked",!1);clearAcross();checker(0); 4 updateCounter()});lastChecked=null;a(d).click(function(c){if(!c)c=window.event;var f=c.target?c.target:c.srcElement;if(lastChecked&&a.data(lastChecked)!=a.data(f)&&c.shiftKey==!0){var e=!1;a(lastChecked).attr("checked",f.checked).parent().parent().toggleClass(b.selectedClass,f.checked);a(d).each(function(){if(a.data(this)==a.data(lastChecked)||a.data(this)==a.data(f))e=e?!1:!0;e&&a(this).attr("checked",f.checked).parent().parent().toggleClass(b.selectedClass,f.checked)})}a(f).parent().parent().toggleClass(b.selectedClass, 5 f.checked);lastChecked=f;updateCounter()});a("form#changelist-form table#result_list tr").find("td:gt(0) :input").change(function(){e=!0});a('form#changelist-form button[name="index"]').click(function(){if(e)return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."))});a('form#changelist-form input[name="_save"]').click(function(){var b=!1;a("div.actions select option:selected").each(function(){a(this).val()&&(b=!0)}); 6 if(b)return e?confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action.")):confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button."))})};a.fn.actions.defaults={actionContainer:"div.actions",counterContainer:"span.action-counter",allContainer:"div.actions span.all",acrossInput:"div.actions input.select-across", 7 acrossQuestions:"div.actions span.question",acrossClears:"div.actions span.clear",allToggle:"#action-toggle",selectedClass:"selected"};a(function(){a("a.change-related").click(function(g){g.preventDefault();window.open(a(this).attr("href"))});a("a.change-related").each(function(g,b){var d=a(b),e=d.attr("href"),c=d.attr("id").split("_").slice(1).join("_");a("#"+c).change(function(){var b=a(this).val();b===""?d.hide():(d.show(),b=e.replace(/\/\d+\/$/,"/"+b+"/"),d.attr("href",b))})})})})(django.jQuery); -
django/contrib/admin/templates/admin/edit_inline/stacked.html
diff --git a/django/contrib/admin/templates/admin/edit_inline/stacked.html b/django/contrib/admin/templates/admin/edit_inline/stacked.html index 476e261..cf6723b 100644
a b 6 6 7 7 {% for inline_admin_form in inline_admin_formset %}<div class="inline-related{% if forloop.last %} empty-form last-related{% endif %}" id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}"> 8 8 <h3><b>{{ inline_admin_formset.opts.verbose_name|title }}:</b> <span class="inline_label">{% if inline_admin_form.original %}{{ inline_admin_form.original }}{% else %}#{{ forloop.counter }}{% endif %}</span> 9 {% if inline_admin_form.admin_url %}<a href="{{ inline_admin_form.admin_url }}" class="inline-changelink changelink">{% trans "edit separately" %}</a> {% endif %} 9 10 {% if inline_admin_form.show_url %}<a href="../../../r/{{ inline_admin_form.original_content_type_id }}/{{ inline_admin_form.original.id }}/">{% trans "View on site" %}</a>{% endif %} 10 11 {% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}<span class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}</span>{% endif %} 11 12 </h3> -
django/contrib/admin/templates/admin/edit_inline/tabular.html
diff --git a/django/contrib/admin/templates/admin/edit_inline/tabular.html b/django/contrib/admin/templates/admin/edit_inline/tabular.html index 71b097e..4cc9a55 100644
a b 27 27 <td class="original"> 28 28 {% if inline_admin_form.original or inline_admin_form.show_url %}<p> 29 29 {% if inline_admin_form.original %} {{ inline_admin_form.original }}{% endif %} 30 {% if inline_admin_form.admin_url %}<a href="{{ inline_admin_form.admin_url }}" class="inline-changelink changelink">{% trans "edit separately" %}</a> {% endif %} 30 31 {% if inline_admin_form.show_url %}<a href="../../../r/{{ inline_admin_form.original_content_type_id }}/{{ inline_admin_form.original.id }}/">{% trans "View on site" %}</a>{% endif %} 31 32 </p>{% endif %} 32 33 {% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %} -
django/contrib/admin/widgets.py
diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index 0d1f2a9..4ce30ae 100644
a b class ManyToManyRawIdWidget(ForeignKeyRawIdWidget): 217 217 218 218 class RelatedFieldWidgetWrapper(forms.Widget): 219 219 """ 220 This class is a wrapper to a given widget to add the add icon forthe221 admin interface.220 This class is a wrapper to a given widget to add the add icon and the 221 change icon for the admin interface. 222 222 """ 223 223 def __init__(self, widget, rel, admin_site, can_add_related=None): 224 224 self.is_hidden = widget.is_hidden … … class RelatedFieldWidgetWrapper(forms.Widget): 259 259 % (related_url, name)) 260 260 output.append(u'<img src="%s" width="10" height="10" alt="%s"/></a>' 261 261 % (static('admin/img/icon_addlink.gif'), _('Add Another'))) 262 263 if not self.widget.allow_multiple_selected: 264 if value is None: 265 val = 0 266 display = ' style="display: none"' 267 else: 268 val = value 269 display = '' 270 related_change_url = reverse('admin:%s_%s_change' % info, args=(val,), 271 current_app=self.admin_site.name) 272 output.append(u'<a href="%s" class="change-related" id="change_id_%s"%s>' 273 % (related_change_url, name, display)) 274 output.append(u'<img src="%s" width="10" height="10" alt="%s"/></a>' 275 % (static('admin/img/icon_changelink.gif'), _('Change'))) 276 262 277 return mark_safe(u''.join(output)) 263 278 264 279 def build_attrs(self, extra_attrs=None, **kwargs): -
tests/regressiontests/admin_inlines/admin.py
diff --git a/tests/regressiontests/admin_inlines/admin.py b/tests/regressiontests/admin_inlines/admin.py index 4edd361..43d7232 100644
a b class SottoCapoInline(admin.TabularInline): 109 109 model = SottoCapo 110 110 111 111 112 class IndividualInline(admin.StackedInline): 113 model = Individual 114 extra = 1 115 116 117 class PhoneInline(admin.StackedInline): 118 model = Phone 119 extra = 1 120 121 122 class EmailInline(admin.TabularInline): 123 model = Email 124 extra = 1 125 126 112 127 site.register(TitleCollection, inlines=[TitleInline]) 113 128 # Test bug #12561 and #12778 114 129 # only ModelAdmin media … … site.register(Fashionista, inlines=[InlineWeakness]) 124 139 site.register(Holder4, Holder4Admin) 125 140 site.register(Author, AuthorAdmin) 126 141 site.register(CapoFamiglia, inlines=[ConsigliereInline, SottoCapoInline]) 142 143 site.register(Household, inlines=[IndividualInline, PhoneInline]) 144 site.register(Individual, inlines=[EmailInline]) 145 site.register(Email) 146 # (Phone not registered) -
tests/regressiontests/admin_inlines/models.py
diff --git a/tests/regressiontests/admin_inlines/models.py b/tests/regressiontests/admin_inlines/models.py index 748280d..896b3d0 100644
a b class Consigliere(models.Model): 136 136 class SottoCapo(models.Model): 137 137 name = models.CharField(max_length=100) 138 138 capo_famiglia = models.ForeignKey(CapoFamiglia, related_name='+') 139 140 141 # Test InlineAdminForm.admin_url: 142 143 class Household(models.Model): 144 pass 145 146 147 class Individual(models.Model): 148 household = models.ForeignKey(Household) 149 150 151 class Phone(models.Model): 152 household = models.ForeignKey(Household) 153 number = models.CharField(max_length=64) 154 155 156 class Email(models.Model): 157 individual = models.ForeignKey(Individual) 158 email = models.EmailField() -
tests/regressiontests/admin_inlines/tests.py
diff --git a/tests/regressiontests/admin_inlines/tests.py b/tests/regressiontests/admin_inlines/tests.py index 955d620..02c8442 100644
a b 1 from django.core import urlresolvers 1 2 from django.contrib.admin.helpers import InlineAdminForm 2 3 from django.contrib.contenttypes.models import ContentType 3 4 from django.test import TestCase … … from django.test import TestCase 5 6 # local test models 6 7 from models import (Holder, Inner, Holder2, Inner2, Holder3, 7 8 Inner3, Person, OutfitItem, Fashionista, Teacher, Parent, Child, 8 CapoFamiglia, Consigliere, SottoCapo )9 from admin import InnerInline9 CapoFamiglia, Consigliere, SottoCapo, Household, Individual, Phone, Email) 10 from admin import site, InnerInline 10 11 11 12 12 13 class TestInline(TestCase): … … class TestInlineAdminForm(TestCase): 196 197 iaf = InlineAdminForm(None, None, {}, {}, joe) 197 198 parent_ct = ContentType.objects.get_for_model(Parent) 198 199 self.assertEqual(iaf.original.content_type, parent_ct) 200 201 202 class TestAdminURL(TestCase): 203 urls = "regressiontests.admin_inlines.urls" 204 fixtures = ['admin-views-users.xml'] 205 206 def get_admin_url(self, obj_or_class, add=False): 207 params = [site.name, obj_or_class._meta.app_label, 208 obj_or_class._meta.module_name] 209 if add: 210 params.append("add") 211 args = () 212 else: 213 params.append("change") 214 args = (obj_or_class.pk,) 215 return urlresolvers.reverse('%s:%s_%s_%s' % tuple(params), args=args) 216 217 def setUp(self): 218 self.household = Household.objects.create() 219 self.individual = Individual.objects.create(household=self.household) 220 self.phone = Phone.objects.create(household=self.household, 221 number='1234567890') 222 self.email = Email.objects.create(individual=self.individual, 223 email='me@example.com') 224 225 result = self.client.login(username='super', password='secret') 226 self.assertEqual(result, True) 227 228 def tearDown(self): 229 self.client.logout() 230 231 def test_admin_url(self): 232 """ 233 admin_url should be set for admin-registered inline models only. 234 235 Also check to ensure URLs look correct and only set on bound forms. 236 """ 237 admin_url = self.get_admin_url(self.household) 238 response = self.client.get(admin_url) 239 for inline_admin_fset in response.context[-1]['inline_admin_formsets']: 240 for inline_admin_form in inline_admin_fset: 241 if inline_admin_form.form._meta.model != Individual: 242 self.assertFalse( 243 getattr(inline_admin_form, 'admin_url', None), 244 'admin_url set with unregistered model') 245 elif not inline_admin_form.original: 246 self.assertFalse( 247 getattr(inline_admin_form, 'admin_url', None), 248 'admin_url set on unbound form!') 249 else: 250 self.assertTrue(inline_admin_form.admin_url, 251 'admin_url not set') 252 self.assertEqual( 253 inline_admin_form.original, self.individual, 254 'original is not expected object') 255 self.assertEqual( 256 inline_admin_form.admin_url, 257 self.get_admin_url(inline_admin_form.original), 258 'admin_url appears incorrect') 259 260 def test_link_rendering(self): 261 """ Confirm links are displayed where appropriate. """ 262 LINK_CSS_CLASS = 'inline-changelink' 263 LINK_TEXT = 'edit separately' 264 265 # test StackedInline rendering 266 response = self.client.get(self.get_admin_url(Household, 'add')) 267 self.assertNotContains(response, LINK_CSS_CLASS) 268 self.assertNotContains(response, LINK_TEXT) 269 270 response = self.client.get(self.get_admin_url(self.household)) 271 self.assertContains(response, LINK_CSS_CLASS) 272 self.assertContains(response, LINK_TEXT) 273 274 # test TabularInline rendering 275 276 response = self.client.get(self.get_admin_url(Individual, 'add')) 277 self.assertNotContains(response, LINK_CSS_CLASS) 278 self.assertNotContains(response, LINK_TEXT) 279 280 response = self.client.get(self.get_admin_url(self.individual)) 281 self.assertContains(response, LINK_CSS_CLASS) 282 self.assertContains(response, LINK_TEXT) -
tests/regressiontests/admin_views/admin.py
diff --git a/tests/regressiontests/admin_views/admin.py b/tests/regressiontests/admin_views/admin.py index e4aae4f..3d47ab6 100644
a b class PizzaAdmin(admin.ModelAdmin): 385 385 readonly_fields = ('toppings',) 386 386 387 387 388 class DonutOrderAdmin(admin.ModelAdmin): 389 raw_id_fields = ('donut',) 390 391 392 class PizzaOrderAdmin(admin.ModelAdmin): 393 readonly_fields = ('pizza',) 394 395 388 396 class WorkHourAdmin(admin.ModelAdmin): 389 397 list_display = ('datum', 'employee') 390 398 list_filter = ('employee',) … … site.register(Post, PostAdmin) 486 494 site.register(Gadget, GadgetAdmin) 487 495 site.register(Villain) 488 496 site.register(SuperVillain) 497 site.register(Ambush) 489 498 site.register(Plot) 490 499 site.register(PlotDetails) 491 500 site.register(CyclicOne) … … site.register(Book, inlines=[ChapterInline]) 512 521 site.register(Promo) 513 522 site.register(ChapterXtra1, ChapterXtra1Admin) 514 523 site.register(Pizza, PizzaAdmin) 524 site.register(PizzaOrder, PizzaOrderAdmin) 515 525 site.register(Topping) 526 site.register(Donut) 527 site.register(DonutOrder, DonutOrderAdmin) 516 528 site.register(Album, AlbumAdmin) 517 529 site.register(Question) 518 530 site.register(Answer) -
tests/regressiontests/admin_views/models.py
diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py index bb8d026..f04dfea 100644
a b class SuperSecretHideout(models.Model): 433 433 return self.location 434 434 435 435 436 class Ambush(models.Model): 437 hideout = models.ForeignKey(SecretHideout) 438 when = models.DateTimeField() 439 440 def __unicode__(self): 441 return u'Ambush %s at %s' % (self.hideout, self.when) 442 443 436 444 class CyclicOne(models.Model): 437 445 name = models.CharField(max_length=25) 438 446 two = models.ForeignKey('CyclicTwo') … … class Pizza(models.Model): 458 466 toppings = models.ManyToManyField('Topping') 459 467 460 468 469 class Donut(models.Model): 470 name = models.CharField(max_length=20) 471 toppings = models.ManyToManyField('Topping') 472 473 def __unicode__(self): 474 return self.name 475 476 477 class DonutOrder(models.Model): 478 donut = models.ForeignKey(Donut) 479 quantity = models.IntegerField() 480 481 def __unicode__(self): 482 return '%s x %d' % (self.donut, self.quantity) 483 484 485 class PizzaOrder(models.Model): 486 pizza = models.ForeignKey(Pizza) 487 quantity = models.IntegerField() 488 489 def __unicode__(self): 490 return '%s x %d' % (self.pizza, self.quantity) 491 492 461 493 class Album(models.Model): 462 494 owner = models.ForeignKey(User) 463 495 title = models.CharField(max_length=30) -
tests/regressiontests/admin_views/tests.py
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py index b6e7b9e..7ce9e61 100644
a b from models import (Article, BarAccount, CustomArticle, EmptyModel, 38 38 Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee, 39 39 Question, Answer, Inquisition, Actor, FoodDelivery, 40 40 RowLevelChangePermissionModel, Paper, CoverLetter, Story, OtherStory, 41 ComplexSortedPerson, Parent, Child) 41 ComplexSortedPerson, Parent, Child, PlotDetails, Villain, SecretHideout, 42 Ambush, Pizza, PizzaOrder, Topping, Donut, DonutOrder) 43 42 44 43 45 ERROR_MESSAGE = "Please enter the correct username and password \ 44 46 for a staff account. Note that both fields are case-sensitive." … … class AdminCustomSaveRelatedTests(TestCase): 3255 3257 3256 3258 self.assertEqual('Josh Stone', Parent.objects.latest('id').name) 3257 3259 self.assertEqual([u'Catherine Stone', u'Paul Stone'], children_names) 3260 3261 3262 class RelatedLinksTest(TestCase): 3263 urls = "regressiontests.admin_views.urls" 3264 fixtures = ['admin-views-users.xml'] 3265 3266 def setUp(self): 3267 self.client.login(username='super', password='secret') 3268 self.RELATED_LINK_CSS_CLASS = 'change-related' 3269 self.READONLY_LINK_CSS_CLASS = 'readonly-changelink' 3270 self.black_knight = Villain.objects.create(name='Black Knight') 3271 self.plot = Plot.objects.create(name='None shall <pass>', 3272 team_leader=self.black_knight, 3273 contact=self.black_knight) 3274 self.plot_details = PlotDetails.objects.create( 3275 plot=self.plot, details="I'll bite your legs off!") 3276 self.hideout = SecretHideout.objects.create(villain=self.black_knight, 3277 location='forest') 3278 self.ambush = Ambush.objects.create(hideout=self.hideout, 3279 when=datetime.datetime.now()) 3280 3281 self.pizza = Pizza.objects.create(name='Wafer-thin pizza') 3282 self.topping = Topping.objects.create(name='Mint') 3283 self.pizza.toppings.add(self.topping) 3284 self.donut = Donut.objects.create(name='Wafer-thin donut') 3285 self.donut.toppings.add(self.topping) 3286 self.donut_order = DonutOrder.objects.create(donut=self.donut, 3287 quantity=1000000) 3288 self.pizza_order = PizzaOrder.objects.create(pizza=self.pizza, 3289 quantity=50) 3290 3291 def tearDown(self): 3292 self.client.logout() 3293 3294 def test_foreignkey(self): 3295 """ Confirm changelink appears in ForeignKey fields """ 3296 response = self.client.get('/test_admin/admin/admin_views/plot/add/') 3297 self.assertContains(response, self.RELATED_LINK_CSS_CLASS) 3298 self.assertContains(response, '/0/"') 3299 response = self.client.get('/test_admin/admin/admin_views/plot/%d/' % 3300 self.plot.pk) 3301 self.assertContains(response, self.RELATED_LINK_CSS_CLASS) 3302 3303 def test_onetoone(self): 3304 """ Confirm changelink appears in populated OneToOne fields """ 3305 response = self.client.get( 3306 '/test_admin/admin/admin_views/plotdetails/add/') 3307 self.assertContains(response, self.RELATED_LINK_CSS_CLASS) 3308 response = self.client.get( 3309 '/test_admin/admin/admin_views/plotdetails/%d/' % 3310 self.plot_details.pk) 3311 self.assertContains(response, self.RELATED_LINK_CSS_CLASS) 3312 3313 def test_unregistered(self): 3314 """ Confirm changelink does *not* appear for unregistered fields """ 3315 response = self.client.get( 3316 '/test_admin/admin/admin_views/ambush/add/') 3317 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3318 response = self.client.get( 3319 '/test_admin/admin/admin_views/ambush/%d/' % 3320 self.ambush.pk) 3321 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3322 3323 def test_readonly(self): 3324 """ Confirm changelink does not appear for populated readonly fields """ 3325 response = self.client.get( 3326 '/test_admin/admin/admin_views/pizzaorder/add/') 3327 self.assertNotContains(response, self.READONLY_LINK_CSS_CLASS) 3328 response = self.client.get( 3329 '/test_admin/admin/admin_views/pizzaorder/%d/' % 3330 self.pizza_order.pk) 3331 self.assertNotContains(response, self.READONLY_LINK_CSS_CLASS) 3332 3333 def test_manytomany(self): 3334 """ Confirm changelinks do *not* appear for ManyToMany fields """ 3335 MULTIPLE_SELECT_STRING = '<select multiple="multiple"' 3336 3337 response = self.client.get( 3338 '/test_admin/admin/admin_views/pizza/add/') 3339 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3340 self.assertNotContains(response, MULTIPLE_SELECT_STRING) 3341 response = self.client.get( 3342 '/test_admin/admin/admin_views/pizza/%d/' % self.pizza.pk) 3343 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3344 self.assertNotContains(response, MULTIPLE_SELECT_STRING) 3345 3346 # try non-readonly ManyToMany 3347 response = self.client.get( 3348 '/test_admin/admin/admin_views/donut/add/') 3349 self.assertContains(response, MULTIPLE_SELECT_STRING) 3350 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3351 response = self.client.get( 3352 '/test_admin/admin/admin_views/donut/%d/' % self.donut.pk) 3353 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3354 self.assertContains(response, MULTIPLE_SELECT_STRING) 3355 3356 def test_raw_id(self): 3357 """ Confirm links do not appear for populated raw_id_fields """ 3358 response = self.client.get( 3359 '/test_admin/admin/admin_views/donutorder/add/') 3360 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3361 response = self.client.get( 3362 '/test_admin/admin/admin_views/donutorder/%d/' % 3363 self.donut_order.pk) 3364 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3365 No newline at end of file