{"id":194,"date":"2012-08-24T16:20:56","date_gmt":"2012-08-24T16:20:56","guid":{"rendered":"http:\/\/blogs.law.harvard.edu\/rprasad\/?p=194"},"modified":"2012-08-24T16:58:22","modified_gmt":"2012-08-24T16:58:22","slug":"using-django-admin-to-copy-an-object","status":"publish","type":"post","link":"https:\/\/archive.blogs.harvard.edu\/rprasad\/2012\/08\/24\/using-django-admin-to-copy-an-object\/","title":{"rendered":"using the Django admin to copy an object"},"content":{"rendered":"<p>I just ran across this snippet from a hasty project last year.\u00a0 For a course database, an administrator needed an easy way to copy semester details via the admin.<\/p>\n<p>Ideally, the user would:<\/p>\n<p style=\"padding-left: 30px;\">(1) Check selected semester objects<br \/>\n(2) Choose &#8220;copy semester&#8221; from the dropdown menu at the top<\/p>\n<p>These options are displayed in the image below.<\/p>\n<p><a href=\"http:\/\/blogs.law.harvard.edu\/rprasad\/files\/2012\/08\/copy_semester2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-large wp-image-196\" title=\"copy_semester2\" src=\"http:\/\/blogs.law.harvard.edu\/rprasad\/files\/2012\/08\/copy_semester2-1024x434.png\" alt=\"\" width=\"584\" height=\"247\" srcset=\"https:\/\/archive.blogs.harvard.edu\/rprasad\/files\/2012\/08\/copy_semester2-1024x434.png 1024w, https:\/\/archive.blogs.harvard.edu\/rprasad\/files\/2012\/08\/copy_semester2-300x127.png 300w, https:\/\/archive.blogs.harvard.edu\/rprasad\/files\/2012\/08\/copy_semester2-500x212.png 500w, https:\/\/archive.blogs.harvard.edu\/rprasad\/files\/2012\/08\/copy_semester2.png 1027w\" sizes=\"auto, (max-width: 584px) 100vw, 584px\" \/><\/a><\/p>\n<p>The basics of admin actions are well described in the <a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/ref\/contrib\/admin\/actions\/\">Django documentation<\/a>.<\/p>\n<p>For the screen shot above, here is the code used to copy the object, including ForeignKey and ManyToMany relationships.\u00a0 (Notes about the code follow.)<\/p>\n<p>Location: admin.py<\/p>\n<pre>from django.contrib import admin\r\nfrom course_tracker.course.models import SemesterDetails\r\nimport copy  # (1) use python copy\r\n\r\ndef copy_semester(modeladmin, request, queryset):\r\n    # sd is an instance of SemesterDetails\r\n    for sd in queryset:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 sd_copy = copy.copy(sd) # (2) django copy object\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 sd_copy.id = None   # (3) set 'id' to None to create new object\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 sd_copy.save()\u00a0\u00a0 \u00a0# initial save\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 # (4) copy M2M relationship: instructors\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 for instructor in sd.instructors.all():\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 sd_copy.instructors.add(instructor)\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 # (5) copy M2M relationship: requirements_met\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 for req in sd.requirements_met.all():\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 sd_copy.requirements_met.add(req)\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 # zero out enrollment numbers.  \r\n        # (6) Use __dict__ to access \"regular\" attributes (not FK or M2M)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 for attr_name in ['enrollments_entered', 'undergrads_enrolled', 'grads_enrolled', 'employees_enrolled', 'cross_registered', 'withdrawals']:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 sd_copy.__dict__.update({ attr_name : 0})\r\n\u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 sd_copy.save()  # (7) save the copy to the database for M2M relations\r\n\r\n\u00a0\u00a0\u00a0 copy_semester.short_description = \"Make a Copy of Semester Details\"<\/pre>\n<p>Below are several notes regarding the code:<\/p>\n<p>(1) Import python&#8217;s <a href=\"http:\/\/docs.python.org\/library\/copy.html\">&#8216;copy&#8217;<\/a> to make a shallow copy of the object<\/p>\n<p>(2) Make the copy.\u00a0 Note this will copy &#8220;regular&#8221; attributes: CharField, IntegerField, etc.\u00a0 In addition, it will copy ForeignKey attributes.<\/p>\n<p>**(3) Set the object id to None.\u00a0 This is important.\u00a0 When the object is saved, a new row (or rows) will be added to the database.<\/p>\n<p>(4), (5) For ManyToMany fields, the data must be added separately.<\/p>\n<p>(6) For the new semester details object, the enrollment fields are set to zero.<\/p>\n<p>To hook this up to the admin, it looks something like this:<\/p>\n<p>Note &#8220;copy_semester&#8221; is added to the &#8220;actions&#8221; list.<\/p>\n<pre>class SemesterDetailsAdmin(admin.ModelAdmin):\r\n\u00a0\u00a0\u00a0 actions = [copy_semester]   #  HERE IT IS!\r\n    save_on_top = True\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0 inlines = (SemesterInstructorQScoreAdminInline, SemesterInstructorCreditAdminInline, CourseDevelopmentCreditAdminInline )\r\n\u00a0\u00a0\u00a0 readonly_fields = ['course_link','instructors_list', 'course_title', 'instructor_history', 'budget_history', 'enrollment_history', 'q_score_history', 'created', 'last_update']\r\n\u00a0\u00a0\u00a0 list_display = ( 'course', 'year', 'term','time_sort','instructors_list', 'last_update','meeting_date', 'meeting_time', 'room', 'number_of_sections',\u00a0 'last_update')\r\n\u00a0\u00a0\u00a0 list_filter = (\u00a0 'year', 'term', 'meeting_type', 'course__department__name', 'instructors' )\r\n\u00a0\u00a0\u00a0 search_fields = ('course__title', 'course__course_id', 'instructors__last_name', 'instructors__first_name')\r\n\u00a0\u00a0\u00a0 filter_horizontal = ('instructors', 'teaching_assistants', 'requirements_met', )\r\nadmin.site.register(SemesterDetails, SemesterDetailsAdmin)<\/pre>\n<p>And that&#8217;s it!<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I just ran across this snippet from a hasty project last year.\u00a0 For a course database, an administrator needed an easy way to copy semester details via the admin. Ideally, the user would: (1) Check selected semester objects (2) Choose &#8220;copy semester&#8221; from the dropdown menu at the top These options are displayed in the &hellip; <a href=\"https:\/\/archive.blogs.harvard.edu\/rprasad\/2012\/08\/24\/using-django-admin-to-copy-an-object\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">using the Django admin to copy an object<\/span><\/a><\/p>\n","protected":false},"author":3875,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[1],"tags":[],"class_list":["post-194","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p4JC3p-38","_links":{"self":[{"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/posts\/194","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/users\/3875"}],"replies":[{"embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/comments?post=194"}],"version-history":[{"count":12,"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/posts\/194\/revisions"}],"predecessor-version":[{"id":201,"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/posts\/194\/revisions\/201"}],"wp:attachment":[{"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/media?parent=194"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/categories?post=194"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/tags?post=194"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}