Ticket #13165: ticket13165_20111005.diff
File ticket13165_20111005.diff, 36.4 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/options.py
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index f05b5cb..b2c8411 100644
a b class BaseModelAdmin(object): 155 155 Get a form Field for a ForeignKey. 156 156 """ 157 157 db = kwargs.get('using') 158 related_modeladmin = self.admin_site._registry.get( 159 db_field.rel.to) 160 can_change_related = bool(related_modeladmin and 161 related_modeladmin.has_change_permission(request)) 158 162 if db_field.name in self.raw_id_fields: 159 163 kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, 160 164 self.admin_site, using=db) 161 165 elif db_field.name in self.radio_fields: 162 kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 163 'class': get_ul_class(self.radio_fields[db_field.name]), 164 }) 166 kwargs['widget'] = widgets.AdminRadioSelect(db_field.rel, 167 self.admin_site, can_change_related=can_change_related, 168 attrs={ 169 'class': get_ul_class(self.radio_fields[db_field.name]), 170 }) 165 171 kwargs['empty_label'] = db_field.blank and _('None') or None 166 172 else: 173 kwargs['widget'] = widgets.AdminSelect(db_field.rel, 174 self.admin_site, can_change_related=can_change_related) 167 175 return db_field.formfield(**kwargs) 168 176 169 177 def formfield_for_manytomany(self, db_field, request=None, **kwargs): … … class ModelAdmin(BaseModelAdmin): 357 365 def media(self): 358 366 js = [ 359 367 'core.js', 360 'admin/RelatedObjectLookups.js',361 368 'jquery.min.js', 362 'jquery.init.js' 369 'jquery.init.js', 370 'admin/RelatedObjectLookups.js' 363 371 ] 364 372 if self.actions is not None: 365 373 js.append('actions.min.js') -
django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js
diff --git a/django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js b/django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js index 1bc78f8..90f746a 100644
a b function dismissAddAnotherPopup(win, newId, newRepr) { 94 94 } 95 95 win.close(); 96 96 } 97 98 (function($){ 99 $(function(){ 100 /* Open change related links in new tab by default */ 101 var openInNewTab = function(e){ 102 e.preventDefault(); 103 window.open($(this).attr("href")); 104 }; 105 $("a.change-related").click(openInNewTab); 106 $("a.change-related-radio").click(openInNewTab); 107 108 /* Adapt the change link next to foreign key selects 109 and raw id text fields according to the selected value */ 110 $("a.change-related").each( 111 function(i, el){ 112 var elem = $(el), 113 defaultHref = elem.attr("href"), 114 selectId = elem.attr("id").split("_").slice(1).join("_"); 115 // TODO: bind to more than one 116 $("#"+selectId).bind("change keyup", function(){ 117 var val = $(this).val(); 118 if (!(/^\d+$/.test(val))){ 119 elem.css("visibility", "hidden"); 120 return; 121 } 122 elem.css("visibility", "visible"); 123 var newHref = defaultHref.replace(/\/\d+\/$/, "/" + val + "/"); 124 elem.attr("href", newHref); 125 }); 126 } 127 ); 128 }); 129 }(django.jQuery)); 130 No newline at end of file -
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..a3e6190 100644
a b class AdminSplitDateTime(forms.SplitDateTimeWidget): 80 80 return mark_safe(u'<p class="datetime">%s %s<br />%s %s</p>' % \ 81 81 (_('Date:'), rendered_widgets[0], _('Time:'), rendered_widgets[1])) 82 82 83 def render_change_related_link(rel_to, admin_site, name, value, 84 class_name=u"change-related", id_postfix=u"%s", extra=None): 85 """ 86 Renders change related links by reversing the admin url 87 and generating some html according to the widget's needs. 88 """ 89 template = u'<a href="%s" class="%s" id="change_id_%s"%s><img src="%s" width="10" height="10" alt="%s"/></a>' 90 info = (rel_to._meta.app_label, rel_to._meta.object_name.lower()) 91 change_related_url = reverse('admin:%s_%s_change' % info, 92 args=(0 if value is None else value,), 93 current_app=admin_site.name) 94 id_postfix = id_postfix % name 95 if extra is None and not value: 96 extra = u' style="visibility:hidden"' 97 else: 98 extra = u'' 99 return mark_safe(template % (change_related_url, class_name, id_postfix, 100 extra, static('admin/img/icon_changelink.gif'), _('Change'))) 101 102 class AdminSelect(forms.Select): 103 def __init__(self, rel, admin_site, can_change_related=None, attrs=None): 104 self.rel = rel 105 self.admin_site = admin_site 106 # Backwards compatible check for whether a user can change related 107 # objects. 108 if can_change_related is None: 109 can_change_related = rel.to in admin_site._registry 110 self.can_change_related = can_change_related 111 super(AdminSelect, self).__init__(attrs) 112 113 def render(self, name, value, attrs=None, choices=()): 114 output = [super(AdminSelect, self).render(name, value, 115 attrs=attrs, choices=choices)] 116 if self.can_change_related: 117 output.append(render_change_related_link(self.rel.to, 118 self.admin_site,name, value)) 119 return mark_safe(u''.join(output)) 120 83 121 class AdminRadioFieldRenderer(RadioFieldRenderer): 84 def render(self): 122 123 def render(self, rel_to=None, admin_site=None): 85 124 """Outputs a <ul> for this set of radio fields.""" 86 return mark_safe(u'<ul%s>\n%s\n</ul>' % ( 87 flatatt(self.attrs), 88 u'\n'.join([u'<li>%s</li>' % force_unicode(w) for w in self])) 89 ) 125 if rel_to and admin_site: 126 link = lambda w: render_change_related_link(rel_to, 127 admin_site, w.name, w.choice_value, 128 class_name=u'change-related-radio', 129 id_postfix=u"%%s_%s" % w.index) 130 else: 131 link = lambda w: u"" 132 return mark_safe(u'<ul%s>\n%s\n</ul>' % (flatatt(self.attrs), 133 u'\n'.join([u'<li>%s%s</li>' % ( 134 force_unicode(w), link(w)) for w in self]))) 90 135 91 136 class AdminRadioSelect(forms.RadioSelect): 92 137 renderer = AdminRadioFieldRenderer 93 138 139 def __init__(self, rel=None, admin_site=None, **kwargs): 140 self.rel = rel 141 self.admin_site = admin_site 142 # Backwards compatible check for whether a user can change related 143 # objects. 144 can_change_related = kwargs.pop('can_change_related', None) 145 if can_change_related is None and rel and admin_site: 146 can_change_related = rel.to in admin_site._registry 147 self.can_change_related = can_change_related 148 super(AdminRadioSelect, self).__init__(**kwargs) 149 150 def render(self, name, value, attrs=None, choices=()): 151 renderer = self.get_renderer(name, value, attrs, choices) 152 if self.can_change_related: 153 return renderer.render(self.rel.to, self.admin_site) 154 return renderer.render() 155 94 156 class AdminFileWidget(forms.ClearableFileInput): 95 157 template_with_initial = (u'<p class="file-upload">%s</p>' 96 158 % forms.ClearableFileInput.template_with_initial) … … class ForeignKeyRawIdWidget(forms.TextInput): 122 184 A Widget for displaying ForeignKeys in the "raw_id" interface rather than 123 185 in a <select> box. 124 186 """ 125 def __init__(self, rel, admin_site, attrs=None, using=None): 187 188 allow_multiple_selected = False 189 190 def __init__(self, rel, admin_site, attrs=None, can_change_related=None, 191 using=None): 126 192 self.rel = rel 127 193 self.admin_site = admin_site 128 194 self.db = using 195 # Backwards compatible check for whether a user can change related 196 # objects. 197 if can_change_related is None: 198 can_change_related = rel.to in admin_site._registry 199 self.can_change_related = can_change_related 129 200 super(ForeignKeyRawIdWidget, self).__init__(attrs) 130 201 131 202 def render(self, name, value, attrs=None): … … class ForeignKeyRawIdWidget(forms.TextInput): 134 205 attrs = {} 135 206 extra = [] 136 207 if rel_to in self.admin_site._registry: 208 if self.can_change_related and not self.allow_multiple_selected: 209 extra.append(render_change_related_link(rel_to, self.admin_site, 210 name, value)) 137 211 # The related object is registered with the same AdminSite 138 212 related_url = reverse('admin:%s_%s_changelist' % 139 213 (rel_to._meta.app_label, … … class ManyToManyRawIdWidget(ForeignKeyRawIdWidget): 180 254 A Widget for displaying ManyToMany ids in the "raw_id" interface rather than 181 255 in a <select multiple> box. 182 256 """ 257 258 allow_multiple_selected = True 259 183 260 def render(self, name, value, attrs=None): 184 261 if attrs is None: 185 262 attrs = {} … … class ManyToManyRawIdWidget(ForeignKeyRawIdWidget): 217 294 218 295 class RelatedFieldWidgetWrapper(forms.Widget): 219 296 """ 220 This class is a wrapper to a given widget to add the add icon forthe221 admin interface.297 This class is a wrapper to a given widget to add the add icon and the 298 change icon for the admin interface. 222 299 """ 223 300 def __init__(self, widget, rel, admin_site, can_add_related=None): 224 301 self.is_hidden = widget.is_hidden -
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..c07ee8a 100644
a b class PizzaAdmin(admin.ModelAdmin): 385 385 readonly_fields = ('toppings',) 386 386 387 387 388 class PizzaOrderAdmin(admin.ModelAdmin): 389 readonly_fields = ('pizza',) 390 391 392 class DonutOrderAdmin(admin.ModelAdmin): 393 raw_id_fields = ('donut',) 394 395 396 class KebapAdmin(admin.ModelAdmin): 397 raw_id_fields = ('toppings',) 398 399 400 class KebapOrderAdmin(admin.ModelAdmin): 401 radio_fields = {'kebap': admin.VERTICAL} 402 403 388 404 class WorkHourAdmin(admin.ModelAdmin): 389 405 list_display = ('datum', 'employee') 390 406 list_filter = ('employee',) … … site.register(Post, PostAdmin) 486 502 site.register(Gadget, GadgetAdmin) 487 503 site.register(Villain) 488 504 site.register(SuperVillain) 505 site.register(Ambush) 489 506 site.register(Plot) 490 507 site.register(PlotDetails) 491 508 site.register(CyclicOne) … … site.register(Book, inlines=[ChapterInline]) 512 529 site.register(Promo) 513 530 site.register(ChapterXtra1, ChapterXtra1Admin) 514 531 site.register(Pizza, PizzaAdmin) 532 site.register(PizzaOrder, PizzaOrderAdmin) 515 533 site.register(Topping) 534 site.register(Donut) 535 site.register(DonutOrder, DonutOrderAdmin) 536 site.register(Kebap, KebapAdmin) 537 site.register(KebapOrder, KebapOrderAdmin) 516 538 site.register(Album, AlbumAdmin) 517 539 site.register(Question) 518 540 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..49defd8 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 PizzaOrder(models.Model): 470 pizza = models.ForeignKey(Pizza) 471 quantity = models.IntegerField() 472 473 def __unicode__(self): 474 return '%s x %d' % (self.pizza, self.quantity) 475 476 477 class Donut(models.Model): 478 name = models.CharField(max_length=20) 479 toppings = models.ManyToManyField('Topping') 480 481 def __unicode__(self): 482 return self.name 483 484 485 class DonutOrder(models.Model): 486 donut = models.ForeignKey(Donut) 487 quantity = models.IntegerField() 488 489 def __unicode__(self): 490 return '%s x %d' % (self.donut, self.quantity) 491 492 493 class Kebap(models.Model): 494 name = models.CharField(max_length=20) 495 toppings = models.ManyToManyField('Topping') 496 497 def __unicode__(self): 498 return self.name 499 500 501 class KebapOrder(models.Model): 502 kebap = models.ForeignKey(Kebap) 503 quantity = models.IntegerField() 504 505 def __unicode__(self): 506 return '%s x %d' % (self.kebap, self.quantity) 507 508 461 509 class Album(models.Model): 462 510 owner = models.ForeignKey(User) 463 511 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..588b4f9 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, Kebap, KebapOrder) 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.RELATED_LINK_CSS_CLASS_RADIO = 'change-related-radio' 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 self.kebap = Kebap.objects.create(name='Wafer-thin kebap') 3291 self.kebap.toppings.add(self.topping) 3292 self.kebap_order = KebapOrder.objects.create(kebap=self.kebap, 3293 quantity=42) 3294 3295 def tearDown(self): 3296 self.client.logout() 3297 3298 def test_foreignkey(self): 3299 """ Confirm changelink appears in ForeignKey fields """ 3300 response = self.client.get('/test_admin/admin/admin_views/plot/add/') 3301 self.assertContains(response, self.RELATED_LINK_CSS_CLASS) 3302 self.assertContains(response, '/0/"') 3303 response = self.client.get('/test_admin/admin/admin_views/plot/%d/' % 3304 self.plot.pk) 3305 self.assertContains(response, self.RELATED_LINK_CSS_CLASS) 3306 3307 def test_onetoone(self): 3308 """ Confirm changelink appears in populated OneToOne fields """ 3309 response = self.client.get( 3310 '/test_admin/admin/admin_views/plotdetails/add/') 3311 self.assertContains(response, self.RELATED_LINK_CSS_CLASS) 3312 response = self.client.get( 3313 '/test_admin/admin/admin_views/plotdetails/%d/' % 3314 self.plot_details.pk) 3315 self.assertContains(response, self.RELATED_LINK_CSS_CLASS) 3316 3317 def test_unregistered(self): 3318 """ Confirm changelink does *not* appear for unregistered fields """ 3319 response = self.client.get( 3320 '/test_admin/admin/admin_views/ambush/add/') 3321 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3322 response = self.client.get( 3323 '/test_admin/admin/admin_views/ambush/%d/' % 3324 self.ambush.pk) 3325 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3326 3327 def test_readonly(self): 3328 """ Confirm changelink does not appear for populated readonly fields """ 3329 response = self.client.get( 3330 '/test_admin/admin/admin_views/pizzaorder/add/') 3331 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3332 response = self.client.get( 3333 '/test_admin/admin/admin_views/pizzaorder/%d/' % 3334 self.pizza_order.pk) 3335 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3336 3337 def test_manytomany(self): 3338 """ Confirm changelinks do *not* appear for ManyToMany fields """ 3339 MULTIPLE_SELECT_STRING = '<select multiple="multiple"' 3340 3341 response = self.client.get( 3342 '/test_admin/admin/admin_views/pizza/add/') 3343 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3344 self.assertNotContains(response, MULTIPLE_SELECT_STRING) 3345 response = self.client.get( 3346 '/test_admin/admin/admin_views/pizza/%d/' % self.pizza.pk) 3347 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3348 self.assertNotContains(response, MULTIPLE_SELECT_STRING) 3349 3350 # try non-readonly ManyToMany 3351 response = self.client.get( 3352 '/test_admin/admin/admin_views/donut/add/') 3353 self.assertContains(response, MULTIPLE_SELECT_STRING) 3354 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3355 response = self.client.get( 3356 '/test_admin/admin/admin_views/donut/%d/' % self.donut.pk) 3357 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3358 self.assertContains(response, MULTIPLE_SELECT_STRING) 3359 3360 def test_raw_id(self): 3361 """ Confirm links do not appear for populated raw_id_fields """ 3362 response = self.client.get( 3363 '/test_admin/admin/admin_views/donutorder/add/') 3364 self.assertContains(response, self.RELATED_LINK_CSS_CLASS) 3365 response = self.client.get( 3366 '/test_admin/admin/admin_views/donutorder/%d/' % 3367 self.donut_order.pk) 3368 self.assertContains(response, self.RELATED_LINK_CSS_CLASS) 3369 3370 def test_radio_fields(self): 3371 """ Confirm links appear for foreign keyradio fields """ 3372 response = self.client.get( 3373 '/test_admin/admin/admin_views/kebaporder/add/') 3374 self.assertContains(response, self.RELATED_LINK_CSS_CLASS_RADIO) 3375 response = self.client.get( 3376 '/test_admin/admin/admin_views/kebaporder/%d/' % 3377 self.kebap_order.pk) 3378 self.assertContains(response, self.RELATED_LINK_CSS_CLASS_RADIO) 3379 3380 def test_raw_id_manytomany(self): 3381 """ Confirm links do not appear for populated raw_id_fields """ 3382 response = self.client.get( 3383 '/test_admin/admin/admin_views/kebap/add/') 3384 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3385 response = self.client.get( 3386 '/test_admin/admin/admin_views/kebap/%d/' % 3387 self.kebap.pk) 3388 self.assertNotContains(response, self.RELATED_LINK_CSS_CLASS) 3389 No newline at end of file -
tests/regressiontests/admin_widgets/tests.py
diff --git a/tests/regressiontests/admin_widgets/tests.py b/tests/regressiontests/admin_widgets/tests.py index a7bfe55..48055fc 100644
a b class ForeignKeyRawIdWidgetTest(DjangoTestCase): 255 255 w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) 256 256 self.assertEqual( 257 257 conditional_escape(w.render('test', band.pk, attrs={})), 258 '<input type="text" name="test" value="%(bandpk)s" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/band/ ?t=id" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong>Linkin Park</strong>' % dict(admin_media_prefix(), bandpk=band.pk)258 '<input type="text" name="test" value="%(bandpk)s" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/band/1/" class="change-related" id="change_id_test"><img src="/static/admin/img/icon_changelink.gif" width="10" height="10" alt="Change"/></a><a href="/widget_admin/admin_widgets/band/?t=id" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong>Linkin Park</strong>' % dict(admin_media_prefix(), bandpk=band.pk) 259 259 ) 260 260 261 261 def test_relations_to_non_primary_key(self): … … class ForeignKeyRawIdWidgetTest(DjangoTestCase): 270 270 w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) 271 271 self.assertEqual( 272 272 w.render('test', core.parent_id, attrs={}), 273 '<input type="text" name="test" value="86" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/inventory/ ?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong>Apple</strong>' % admin_media_prefix()273 '<input type="text" name="test" value="86" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/inventory/86/" class="change-related" id="change_id_test"><img src="/static/admin/img/icon_changelink.gif" width="10" height="10" alt="Change"/></a><a href="/widget_admin/admin_widgets/inventory/?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong>Apple</strong>' % admin_media_prefix() 274 274 ) 275 275 276 276 def test_fk_related_model_not_in_admin(self): … … class ForeignKeyRawIdWidgetTest(DjangoTestCase): 312 312 ) 313 313 self.assertEqual( 314 314 w.render('test', child_of_hidden.parent_id, attrs={}), 315 '<input type="text" name="test" value="93" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/inventory/ ?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong>Hidden</strong>' % admin_media_prefix()315 '<input type="text" name="test" value="93" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/inventory/93/" class="change-related" id="change_id_test"><img src="/static/admin/img/icon_changelink.gif" width="10" height="10" alt="Change"/></a><a href="/widget_admin/admin_widgets/inventory/?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong>Hidden</strong>' % admin_media_prefix() 316 316 ) 317 317 318 318 -
tests/regressiontests/modeladmin/tests.py
diff --git a/tests/regressiontests/modeladmin/tests.py b/tests/regressiontests/modeladmin/tests.py index 872fb0c..c6f1929 100644
a b from django.contrib.admin.options import (ModelAdmin, TabularInline, 6 6 HORIZONTAL, VERTICAL) 7 7 from django.contrib.admin.sites import AdminSite 8 8 from django.contrib.admin.validation import validate 9 from django.contrib.admin.widgets import AdminDateWidget, AdminRadioSelect 9 from django.contrib.admin.widgets import (AdminDateWidget, AdminSelect, 10 AdminRadioSelect) 10 11 from django.contrib.admin import (SimpleListFilter, 11 12 BooleanFieldListFilter) 12 13 from django.core.exceptions import ImproperlyConfigured … … class ModelAdminTests(TestCase): 375 376 cmafa = cma.get_form(request) 376 377 377 378 self.assertEqual(type(cmafa.base_fields['main_band'].widget.widget), 378 Select)379 AdminSelect) 379 380 self.assertEqual( 380 381 list(cmafa.base_fields['main_band'].widget.choices), 381 382 [(u'', u'---------'), (self.band.id, u'The Doors')]) 382 383 383 384 self.assertEqual( 384 type(cmafa.base_fields['opening_band'].widget.widget), Select)385 type(cmafa.base_fields['opening_band'].widget.widget), AdminSelect) 385 386 self.assertEqual( 386 387 list(cmafa.base_fields['opening_band'].widget.choices), 387 388 [(u'', u'---------'), (self.band.id, u'The Doors')])