Changeset 8273
- Timestamp:
- 08/09/08 15:52:40 (1 year ago)
- Files:
-
- django/trunk/django/contrib/admin/options.py (modified) (7 diffs)
- django/trunk/docs/admin.txt (modified) (1 diff)
- django/trunk/tests/regressiontests/admin_views/models.py (modified) (2 diffs)
- django/trunk/tests/regressiontests/admin_views/tests.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/contrib/admin/options.py
r8266 r8273 453 453 request.user.message_set.create(message=message) 454 454 455 def save_ model(self, request, form, change):456 """ 457 Save and return a model given a ModelForm. ``change`` is True if the458 object is being changed, and False if it's being added.459 """ 460 return form.save(commit= True)455 def save_form(self, request, form, change): 456 """ 457 Given a ModelForm return an unsaved instance. ``change`` is True if 458 the object is being changed, and False if it's being added. 459 """ 460 return form.save(commit=False) 461 461 462 462 def save_formset(self, request, form, formset, change): 463 463 """ 464 Save an inline formset attached to the object. 465 """ 466 formset.save() 467 468 def save_add(self, request, form, formsets, post_url_continue): 469 """ 470 Saves the object in the "add" stage and returns an HttpResponseRedirect. 471 472 `form` is a bound Form instance that's verified to be valid. 473 """ 474 opts = self.model._meta 475 476 new_object = self.save_model(request, form, change=False) 477 if formsets: 478 for formset in formsets: 479 formset.instance = new_object 480 self.save_formset(request, form, formset, change=False) 481 482 pk_value = new_object._get_pk_val() 483 self.log_addition(request, new_object) 484 485 msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(new_object)} 486 # Here, we distinguish between different save types by checking for 487 # the presence of keys in request.POST. 488 if request.POST.has_key("_continue"): 489 self.message_user(request, msg + ' ' + _("You may edit it again below.")) 490 if request.POST.has_key("_popup"): 491 post_url_continue += "?_popup=1" 492 return HttpResponseRedirect(post_url_continue % pk_value) 493 494 if request.POST.has_key("_popup"): 495 return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \ 496 # escape() calls force_unicode. 497 (escape(pk_value), escape(new_object))) 498 elif request.POST.has_key("_addanother"): 499 self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name))) 500 return HttpResponseRedirect(request.path) 501 else: 502 self.message_user(request, msg) 503 504 # Figure out where to redirect. If the user has change permission, 505 # redirect to the change-list page for this object. Otherwise, 506 # redirect to the admin index. 507 if self.has_change_permission(request, None): 508 post_url = '../' 509 else: 510 post_url = '../../../' 511 return HttpResponseRedirect(post_url) 512 save_add = transaction.commit_on_success(save_add) 513 514 def save_change(self, request, form, formsets=None): 515 """ 516 Saves the object in the "change" stage and returns an HttpResponseRedirect. 517 518 `form` is a bound Form instance that's verified to be valid. 519 520 `formsets` is a sequence of InlineFormSet instances that are verified to be valid. 521 """ 522 opts = self.model._meta 523 new_object = self.save_model(request, form, change=True) 524 pk_value = new_object._get_pk_val() 525 526 if formsets: 527 for formset in formsets: 528 self.save_formset(request, form, formset, change=True) 529 530 change_message = self.construct_change_message(request, form, formsets) 531 self.log_change(request, new_object, change_message) 532 533 msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(new_object)} 534 if request.POST.has_key("_continue"): 535 self.message_user(request, msg + ' ' + _("You may edit it again below.")) 536 if request.REQUEST.has_key('_popup'): 537 return HttpResponseRedirect(request.path + "?_popup=1") 538 else: 539 return HttpResponseRedirect(request.path) 540 elif request.POST.has_key("_saveasnew"): 541 msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(opts.verbose_name), 'obj': new_object} 542 self.message_user(request, msg) 543 return HttpResponseRedirect("../%s/" % pk_value) 544 elif request.POST.has_key("_addanother"): 545 self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name))) 546 return HttpResponseRedirect("../add/") 547 else: 548 self.message_user(request, msg) 549 return HttpResponseRedirect("../") 550 save_change = transaction.commit_on_success(save_change) 464 Given an inline formset return unsaved instances. 465 """ 466 return formset.save(commit=False) 551 467 552 468 def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): … … 575 491 "admin/change_form.html" 576 492 ], context, context_instance=template.RequestContext(request)) 493 494 def response_add(self, request, obj, post_url_continue='../%s/'): 495 """ 496 Determines the HttpResponse for the add_view stage. 497 """ 498 opts = obj._meta 499 pk_value = obj._get_pk_val() 500 501 msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj)} 502 # Here, we distinguish between different save types by checking for 503 # the presence of keys in request.POST. 504 if request.POST.has_key("_continue"): 505 self.message_user(request, msg + ' ' + _("You may edit it again below.")) 506 if request.POST.has_key("_popup"): 507 post_url_continue += "?_popup=1" 508 return HttpResponseRedirect(post_url_continue % pk_value) 509 510 if request.POST.has_key("_popup"): 511 return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \ 512 # escape() calls force_unicode. 513 (escape(pk_value), escape(obj))) 514 elif request.POST.has_key("_addanother"): 515 self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name))) 516 return HttpResponseRedirect(request.path) 517 else: 518 self.message_user(request, msg) 519 520 # Figure out where to redirect. If the user has change permission, 521 # redirect to the change-list page for this object. Otherwise, 522 # redirect to the admin index. 523 if self.has_change_permission(request, None): 524 post_url = '../' 525 else: 526 post_url = '../../../' 527 return HttpResponseRedirect(post_url) 528 529 def response_change(self, request, obj): 530 """ 531 Determines the HttpResponse for the change_view stage. 532 """ 533 opts = obj._meta 534 pk_value = obj._get_pk_val() 535 536 msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj)} 537 if request.POST.has_key("_continue"): 538 self.message_user(request, msg + ' ' + _("You may edit it again below.")) 539 if request.REQUEST.has_key('_popup'): 540 return HttpResponseRedirect(request.path + "?_popup=1") 541 else: 542 return HttpResponseRedirect(request.path) 543 elif request.POST.has_key("_saveasnew"): 544 msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(opts.verbose_name), 'obj': obj} 545 self.message_user(request, msg) 546 return HttpResponseRedirect("../%s/" % pk_value) 547 elif request.POST.has_key("_addanother"): 548 self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name))) 549 return HttpResponseRedirect("../add/") 550 else: 551 self.message_user(request, msg) 552 return HttpResponseRedirect("../") 577 553 578 554 def add_view(self, request, form_url='', extra_context=None): … … 593 569 594 570 ModelForm = self.get_form(request) 595 inline_formsets = [] 596 obj = self.model() 571 formsets = [] 597 572 if request.method == 'POST': 598 573 form = ModelForm(request.POST, request.FILES) 574 if form.is_valid(): 575 form_validated = True 576 new_object = self.save_form(request, form, change=False) 577 else: 578 form_validated = False 579 new_object = self.model() 599 580 for FormSet in self.get_formsets(request): 600 inline_formset = FormSet(data=request.POST, files=request.FILES, 601 instance=obj, save_as_new=request.POST.has_key("_saveasnew")) 602 inline_formsets.append(inline_formset) 603 if all_valid(inline_formsets) and form.is_valid(): 604 return self.save_add(request, form, inline_formsets, '../%s/') 581 formset = FormSet(data=request.POST, files=request.FILES, 582 instance=new_object, 583 save_as_new=request.POST.has_key("_saveasnew")) 584 formsets.append(formset) 585 if all_valid(formsets) and form_validated: 586 new_object.save() 587 form.save_m2m() 588 for formset in formsets: 589 instances = self.save_formset(request, form, formset, change=False) 590 for instance in instances: 591 instance.save() 592 formset.save_m2m() 593 594 self.log_addition(request, new_object) 595 return self.response_add(request, new_object) 605 596 else: 606 597 form = ModelForm(initial=dict(request.GET.items())) 607 598 for FormSet in self.get_formsets(request): 608 inline_formset = FormSet(instance=obj)609 inline_formsets.append(inline_formset)599 formset = FormSet(instance=self.model()) 600 formsets.append(formset) 610 601 611 602 adminForm = AdminForm(form, list(self.get_fieldsets(request)), self.prepopulated_fields) 612 603 media = self.media + adminForm.media 613 for f s in inline_formsets:614 media = media + f s.media604 for formset in formsets: 605 media = media + formset.media 615 606 616 607 inline_admin_formsets = [] 617 for inline, formset in zip(self.inline_instances, inline_formsets):608 for inline, formset in zip(self.inline_instances, formsets): 618 609 fieldsets = list(inline.get_fieldsets(request)) 619 610 inline_admin_formset = InlineAdminFormSet(inline, formset, fieldsets) … … 627 618 'media': mark_safe(media), 628 619 'inline_admin_formsets': inline_admin_formsets, 629 'errors': AdminErrorList(form, inline_formsets),620 'errors': AdminErrorList(form, formsets), 630 621 'root_path': self.admin_site.root_path, 631 622 } 632 623 context.update(extra_context or {}) 633 624 return self.render_change_form(request, context, add=True) 625 add_view = transaction.commit_on_success(add_view) 634 626 635 627 def change_view(self, request, object_id, extra_context=None): … … 657 649 658 650 ModelForm = self.get_form(request, obj) 659 inline_formsets = []651 formsets = [] 660 652 if request.method == 'POST': 661 653 form = ModelForm(request.POST, request.FILES, instance=obj) 662 for FormSet in self.get_formsets(request, obj): 663 inline_formset = FormSet(request.POST, request.FILES, instance=obj) 664 inline_formsets.append(inline_formset) 665 666 if all_valid(inline_formsets) and form.is_valid(): 667 return self.save_change(request, form, inline_formsets) 654 if form.is_valid(): 655 form_validated = True 656 new_object = self.save_form(request, form, change=True) 657 else: 658 form_validated = False 659 new_object = obj 660 for FormSet in self.get_formsets(request, new_object): 661 formset = FormSet(request.POST, request.FILES, 662 instance=new_object) 663 formsets.append(formset) 664 665 if all_valid(formsets) and form_validated: 666 new_object.save() 667 form.save_m2m() 668 for formset in formsets: 669 instances = self.save_formset(request, form, formset, change=True) 670 for instance in instances: 671 instance.save() 672 formset.save_m2m() 673 674 change_message = self.construct_change_message(request, form, formsets) 675 self.log_change(request, new_object, change_message) 676 return self.response_change(request, new_object) 668 677 else: 669 678 form = ModelForm(instance=obj) 670 679 for FormSet in self.get_formsets(request, obj): 671 inline_formset = FormSet(instance=obj)672 inline_formsets.append(inline_formset)680 formset = FormSet(instance=obj) 681 formsets.append(formset) 673 682 674 683 adminForm = AdminForm(form, self.get_fieldsets(request, obj), self.prepopulated_fields) … … 676 685 677 686 inline_admin_formsets = [] 678 for inline, formset in zip(self.inline_instances, inline_formsets):687 for inline, formset in zip(self.inline_instances, formsets): 679 688 fieldsets = list(inline.get_fieldsets(request, obj)) 680 689 inline_admin_formset = InlineAdminFormSet(inline, formset, fieldsets) … … 690 699 'media': mark_safe(media), 691 700 'inline_admin_formsets': inline_admin_formsets, 692 'errors': AdminErrorList(form, inline_formsets),701 'errors': AdminErrorList(form, formsets), 693 702 'root_path': self.admin_site.root_path, 694 703 } 695 704 context.update(extra_context or {}) 696 705 return self.render_change_form(request, context, change=True, obj=obj) 706 change_view = transaction.commit_on_success(change_view) 697 707 698 708 def changelist_view(self, request, extra_context=None): django/trunk/docs/admin.txt
r8243 r8273 522 522 an index. Currently this is only available for MySQL. 523 523 524 ``ModelAdmin`` methods 525 ---------------------- 526 527 ``save_form(self, request, form, change)`` 528 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 529 530 The ``save_form`` method is given the ``HttpRequest``, a ``ModelForm`` 531 instance and a boolean value based on whether it is adding or changing the 532 object. 533 534 This method should return an unsaved instance. For example to attach 535 ``request.user`` to the object prior to saving:: 536 537 class ArticleAdmin(admin.ModelAdmin): 538 def save_form(self, request, form, change): 539 instance = form.save(commit=False) 540 instance.user = request.user 541 return instance 542 543 ``save_formset(self, request, form, formset, change)`` 544 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 545 546 The ``save_formset`` method is given the ``HttpRequest``, the parent 547 ``ModelForm`` instance and a boolean value baesed on whether it is adding or 548 changing the parent object. 549 550 This method should return unsaved instances. These instances will later be 551 saved to the database. By default the formset will only return instances that 552 have changed. For example to attach ``request.user`` to each changed formset 553 model instance:: 554 555 class ArticleAdmin(admin.ModelAdmin): 556 def save_formset(self, request, form, formset, change): 557 instances = formset.save(commit=False) 558 for instance in instances: 559 instance.user = request.user 560 return instances 561 524 562 ``ModelAdmin`` media definitions 525 563 -------------------------------- django/trunk/tests/regressiontests/admin_views/models.py
r8236 r8273 20 20 def __unicode__(self): 21 21 return self.title 22 23 class ArticleInline(admin.TabularInline): 24 model = Article 22 25 23 26 class ArticleAdmin(admin.ModelAdmin): … … 62 65 admin.site.register(Article, ArticleAdmin) 63 66 admin.site.register(CustomArticle, CustomArticleAdmin) 64 admin.site.register(Section )67 admin.site.register(Section, inlines=[ArticleInline]) 65 68 admin.site.register(ModelWithStringPrimaryKey) django/trunk/tests/regressiontests/admin_views/tests.py
r8271 r8273 12 12 from models import Article, CustomArticle, Section, ModelWithStringPrimaryKey 13 13 14 class AdminViewBasicTest(TestCase): 15 fixtures = ['admin-views-users.xml'] 16 17 def setUp(self): 18 self.client.login(username='super', password='secret') 19 20 def tearDown(self): 21 self.client.logout() 22 23 def testTrailingSlashRequired(self): 24 """ 25 If you leave off the trailing slash, app should redirect and add it. 26 """ 27 request = self.client.get('/test_admin/admin/admin_views/article/add') 28 self.assertRedirects(request, 29 '/test_admin/admin/admin_views/article/add/' 30 ) 31 32 def testBasicAddGet(self): 33 """ 34 A smoke test to ensure GET on the add_view works. 35 """ 36 response = self.client.get('/test_admin/admin/admin_views/section/add/') 37 self.failUnlessEqual(response.status_code, 200) 38 39 def testBasicEditGet(self): 40 """ 41 A smoke test to ensureGET on the change_view works. 42 """ 43 response = self.client.get('/test_admin/admin/admin_views/section/1/') 44 self.failUnlessEqual(response.status_code, 200) 45 46 def testBasicAddPost(self): 47 """ 48 A smoke test to ensure POST on add_view works. 49 """ 50 post_data = { 51 "name": u"Another Section", 52 # inline data 53 "article_set-TOTAL_FORMS": u"3", 54 "article_set-INITIAL_FORMS": u"0", 55 } 56 response = self.client.post('/test_admin/admin/admin_views/section/add/', post_data) 57 self.failUnlessEqual(response.status_code, 302) # redirect somewhere 58 59 def testBasicEditPost(self): 60 """ 61 A smoke test to ensure POST on edit_view works. 62 """ 63 post_data = { 64 "name": u"Test section", 65 # inline data 66 "article_set-TOTAL_FORMS": u"4", 67 "article_set-INITIAL_FORMS": u"1", 68 "article_set-0-id": u"1", 69 # there is no title in database, give one here or formset 70 # will fail. 71 "article_set-0-title": u"Need a title.", 72 "article_set-0-content": u"<p>test content</p>", 73 "article_set-0-date_0": u"2008-03-18", 74 "article_set-0-date_1": u"11:54:58", 75 "article_set-1-id": u"", 76 "article_set-1-title": u"", 77 "article_set-1-content": u"", 78 "article_set-1-date_0": u"", 79 "article_set-1-date_1": u"", 80 "article_set-2-id": u"", 81 "article_set-2-title": u"", 82 "article_set-2-content": u"", 83 "article_set-2-date_0": u"", 84 "article_set-2-date_1": u"", 85 "article_set-3-id": u"", 86 "article_set-3-title": u"", 87 "article_set-3-content": u"", 88 "article_set-3-date_0": u"", 89 "article_set-3-date_1": u"", 90 } 91 response = self.client.post('/test_admin/admin/admin_views/section/1/', post_data) 92 self.failUnlessEqual(response.status_code, 302) # redirect somewhere 93 14 94 def get_perm(Model, perm): 15 95 """Return the permission object, for the Model""" 16 96 ct = ContentType.objects.get_for_model(Model) 17 return Permission.objects.get(content_type=ct, codename=perm)97 return Permission.objects.get(content_type=ct, codename=perm) 18 98 19 99 class AdminViewPermissionsTest(TestCase): … … 77 157 'username': 'joepublic', 78 158 'password': 'secret'} 79 80 def testTrailingSlashRequired(self):81 """82 If you leave off the trailing slash, app should redirect and add it.83 """84 self.client.post('/test_admin/admin/', self.super_login)85 86 request = self.client.get(87 '/test_admin/admin/admin_views/article/add'88 )89 self.assertRedirects(request,90 '/test_admin/admin/admin_views/article/add/'91 )92 159 93 160 def testLogin(self):
