{"id":1,"date":"2011-08-30T13:55:41","date_gmt":"2011-08-30T13:55:41","guid":{"rendered":"http:\/\/blogs.law.harvard.edu\/rprasad\/?p=1"},"modified":"2011-08-31T14:15:01","modified_gmt":"2011-08-31T14:15:01","slug":"highcharts-django-admin","status":"publish","type":"post","link":"https:\/\/archive.blogs.harvard.edu\/rprasad\/2011\/08\/30\/highcharts-django-admin\/","title":{"rendered":"Highcharts in the Django Admin"},"content":{"rendered":"<p>(Note, this assumes that you have a Django project <a title=\"django 1.3 install docs\" href=\"https:\/\/docs.djangoproject.com\/en\/1.3\/intro\/install\/\">installed<\/a> and running. This example is for Django 1.3, the official version.)<strong><\/strong><\/p>\n<p>Below are some notes for adding <a href=\"http:\/\/www.highcharts.com\/\" target=\"_blank\">Highcharts<\/a> to a Django admin page. In this case, I want to chart the enrollment in a science class over time.<\/p>\n<p><a href=\"http:\/\/blogs.law.harvard.edu\/rprasad\/files\/2011\/08\/enrollment_chart1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-38\" src=\"http:\/\/blogs.law.harvard.edu\/rprasad\/files\/2011\/08\/enrollment_chart1-300x196.png\" alt=\"\" width=\"300\" height=\"196\" srcset=\"https:\/\/archive.blogs.harvard.edu\/rprasad\/files\/2011\/08\/enrollment_chart1-300x196.png 300w, https:\/\/archive.blogs.harvard.edu\/rprasad\/files\/2011\/08\/enrollment_chart1.png 939w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Specifically, I have a model name &#8220;Course&#8221; and I want to see the chart on the &#8220;Course&#8221; change form in the admin.<\/p>\n<p><strong>(1)<\/strong> Download <a href=\"http:\/\/www.highcharts.com\/\">Highcharts<\/a>, unzip it, and place in a directory under your Django MEDIA_ROOT directory, as specified in your Django settings.py.<\/p>\n<p style=\"text-align: left\"><strong>(2) <\/strong><strong><\/strong>Make a blank template file named &#8220;<strong>change_form.html<\/strong>&#8221; file as well as the appropriate directories for your model. In the case of my <strong>Course<\/strong> model, the location is:<\/p>\n<p style=\"padding-left: 30px\">..\/templates\/admin\/course\/course\/<strong>change_form.html<\/strong><\/p>\n<p>Notes on the path above:<\/p>\n<p style=\"padding-left: 30px\">&#8220;templates&#8221; &#8211; a directory specified in your django settings.py file<\/p>\n<p style=\"padding-left: 30px\">&#8220;admin&#8221; &#8211; indicates a template for the django admin<\/p>\n<p style=\"padding-left: 30px\">&#8221; course&#8221; &#8211; name of my app. (The <strong>Course<\/strong> model is defined in &#8216;..\/<strong>course<\/strong>\/models.py&#8217;)<\/p>\n<p style=\"padding-left: 30px\">&#8220;course&#8221; &#8211; name of the model, Course, in lowercase<\/p>\n<p style=\"padding-left: 30px\">&#8220;<strong>change_form.htm<\/strong>l&#8221; &#8211; name of an existing file in the django source code (\/django\/contrib\/admin\/templates\/admin\/change_form.html)<\/p>\n<p><strong>(2) <\/strong>Add the following lines of code to your<strong> change_form.html<\/strong> file.<\/p>\n<pre>{% extends \"admin\/change_form.html\" %}\r\n{% block extrahead %}{{ block.super }}\r\n{% url 'admin:jsi18n' as jsi18nurl %}\r\n&lt;script type=\"text\/javascript\" src=\"{{ jsi18nurl|default:\"..\/..\/..\/jsi18n\/\" }}\"&gt;&lt;\/script&gt;\r\n{{ media }}\r\n&lt;!-- start: two new lines for highcharts --&gt;\r\n&lt;script src=\"http:\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/1.6.1\/jquery.min.js\" type=\"text\/javascript\"&gt;&lt;\/script&gt;\r\n&lt;script src=\"{{ MEDIA_URL }}highcharts\/js\/highcharts.js\" type=\"text\/javascript\"&gt;&lt;\/script&gt;\r\n&lt;!-- end: two new lines for highcharts --&gt;\r\n{% endblock %}<\/pre>\n<p>Most of the code above is taken from the &#8220;extrahead&#8221; block in the original &#8220;<strong>change_form.html<\/strong>&#8221; file. Two new lines of javascript have been added, as indicated by the comments above.\u00a0 (Again, this is Django 1.3, the official version. If you&#8217;re using a different version, copy the appropriate code from the change_form.html template included with django.)<\/p>\n<p>The 1st line calls in the JQuery library and the 2nd line connects to highcharts.js.<\/p>\n<p><strong>(3) Test. <\/strong>Go to the the Django admin and attempt to add a new instance of your model, or edit an existing one. View the source in your browser:<\/p>\n<p style=\"text-align: left;padding-left: 30px\">(a) Make sure that the new lines show up and that<\/p>\n<p style=\"text-align: left;padding-left: 30px\">(b) the javascript files are being loaded. (e.g., Click on the links to the jquery and highcharts js files to make sure they load.)<\/p>\n<p style=\"text-align: left;padding-left: 30px\"><a href=\"http:\/\/blogs.law.harvard.edu\/rprasad\/files\/2011\/08\/view_source4.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-39\" src=\"http:\/\/blogs.law.harvard.edu\/rprasad\/files\/2011\/08\/view_source4-300x84.gif\" alt=\"\" width=\"300\" height=\"84\" srcset=\"https:\/\/archive.blogs.harvard.edu\/rprasad\/files\/2011\/08\/view_source4-300x84.gif 300w, https:\/\/archive.blogs.harvard.edu\/rprasad\/files\/2011\/08\/view_source4.gif 875w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p style=\"text-align: left;padding-left: 30px\">Note: <a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/ref\/contrib\/admin\/#modeladmin-media-definitions\">Django 1.3 has JQuery built-in<\/a> but it has it&#8217;s own namespace. Using the built-in JQuery requires editing highcharts.js and changing &#8220;JQuery&#8221; to &#8220;django.Jquery&#8221;.\u00a0 Because of maintenance, changing the highcharts.js is not advisable.<\/p>\n<p><strong>(4)<\/strong> For my Course model, I&#8217;m <strong>adding a function in the models.py file<\/strong> named &#8220;enrollment_chart&#8221;.\u00a0 For example purposes, I&#8217;m throwing test data into the function.\u00a0 (In reality, the function calls a queryset that is passed to the template.)<\/p>\n<pre>    def enrollment_chart(self):\r\n        lu = { 'categories' : [ 'Fall 2008', 'Spring 2009','Fall 2009', 'Spring 2010', 'Fall 2010', 'Spring 2011'],\\\r\n             'undergrad' : [18, 22, 30, 34, 40, 47],\\\r\n             'grad' : [1, 2, 4, 4, 5, 7],\\\r\n             'employee' : [2, 3, 0, 1, 1, 2] }\r\n        lu['total_enrolled'] = [sum(a) for a in zip(lu['undergrad'], lu['grad'],lu['employee'])]\r\n\r\n        return render_to_string('admin\/course\/course\/<strong>enrollment_chart.html<\/strong>', lu )\r\n    enrollment_chart.allow_tags = True<\/pre>\n<p><strong>(5)<\/strong> <strong>Make the &#8220;enrollment_chart.html&#8221; file<\/strong> referred to in the function above.\u00a0 Note, the file goes in the same directory as the &#8220;change_form.html&#8221; file in step (2).<\/p>\n<p><strong>(6)<\/strong> In the &#8220;<strong>enrollment_chart.html<\/strong>&#8221; file, add the following code:<\/p>\n<p>Note 1:\u00a0 This code is from the <a href=\"http:\/\/www.highcharts.com\/demo\/\">highcharts example<\/a> graph with some changes to the labels and the addition of Django template tags.<\/p>\n<p>Note 2: the &#8220;renderTo&#8221; attribute must match the &#8220;id&#8221; of the &lt;div ..&gt; at the bottom of this code.<\/p>\n<pre>&lt;script type=\"text\/javascript\"&gt;\r\nvar chart;\r\njQuery(document).ready(function() {\r\n\tchart = new Highcharts.Chart({\r\n\t\tchart: {\r\n\t\t\trenderTo: 'enrollment_container',\r\n\t\t\tdefaultSeriesType: 'line',\r\n\t\t\tmarginRight: 130,\r\n\t\t\tmarginBottom: 30\r\n\t\t},\r\n\t\ttitle: {\r\n\t\t\ttext: 'Enrollment by Semester ',\r\n\t\t\tx: -20 \/\/center\r\n\t\t},\r\n\t\tsubtitle: {\r\n\t\t\ttext: '',\r\n\t\t\tx: -20\r\n\t\t},\r\n\t\txAxis: {\r\n\t\t\tcategories: [ '{{ categories|join:\"','\" }}']\r\n\t\t\/\/\tcategories: ['Fall 2008', 'Spring 2009','Fall 2009', 'Spring 2010', 'Fall 2010', 'Spring 2011']\r\n\t\t},\r\n\t\tyAxis: {\r\n\t\t\ttitle: {\r\n\t\t\t\ttext: 'Number of Students'\r\n\t\t\t},\r\n\t\t\tplotLines: [{\r\n\t\t\t\tvalue: 0,\r\n\t\t\t\twidth: 1,\r\n\t\t\t\tcolor: '#808080'\r\n\t\t\t}]\r\n\t\t},\r\n\t\ttooltip: {\r\n\t\t\tformatter: function() {\r\n\t                return '<strong>'+ this.series.name +'<\/strong>'+this.x +': '+ this.y;\r\n\t\t\t}\r\n\t\t},\r\n\t\tlegend: {\r\n\t\t\tlayout: 'vertical',\r\n\t\t\talign: 'right',\r\n\t\t\tverticalAlign: 'top',\r\n\t\t\tx: -10,\r\n\t\t\ty: 100,\r\n\t\t\tborderWidth: 0\r\n\t\t},\r\n\t\tseries: [{\r\n\t\t\tname: 'Total Enrolled',\r\n\t\t\t\/\/data: [1, 27, 34, 39, 46, 56]\r\n\t\t\tdata: [{{ total_enrolled|join:\",\" }}]\r\n\t\t}, {\r\n\t\t\tname: 'Undergrads',\r\n            data: [{{ undergrad|join:\",\" }}]\r\n\t\t\t\/\/data: [18, 22, 30, 34, 40, 47]\r\n\t\t}, {\r\n\t\t\tname: 'Grads',\r\n\t\t\tdata: [{{ grad|join:\",\" }}]\r\n\t\t\t\/\/data: [1, 2, 4, 4, 5, 7]\r\n\t\t}, {\r\n\t\t\tname: 'Employees',\r\n\t\t\tdata: [{{ employee|join:\",\" }}]\r\n\t\t\t\/\/data: [2, 3, 0, 1, 1, 2]\r\n\t\t}]\r\n\t});\r\n\r\n});\r\n&lt;\/script&gt;\r\n&lt;div id=\"enrollment_container\" style=\"width: 700px;height: 500px\"&gt;&lt;\/div&gt;<\/pre>\n<p><strong>(7)<\/strong> Update your<strong> admin.py<\/strong> file to connect the<strong> enrollment_chart()<\/strong> function in step (4) to your admin screen.<\/p>\n<p>In the <strong>admin.py<\/strong> file, add <strong>enrollment_chart<\/strong> to:<\/p>\n<blockquote><p>(a) the list of <a href=\"http:\/\/docs.djangoproject.com\/en\/dev\/ref\/contrib\/admin\/#django.contrib.admin.ModelAdmin.readonly_fields\"><strong>readonly_fields<\/strong><\/a>, as well as <strong><br \/>\n<\/strong><\/p>\n<p>(b) a field in your <a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/ref\/contrib\/admin\/#django.contrib.admin.ModelAdmin.fieldsets\"><strong>fieldsets<\/strong><\/a> array<\/p><\/blockquote>\n<p>(Location of the admin.py file for the Course model: ..\/course\/admin.py)<\/p>\n<p>Below is an example where <strong>enrollment_chart<\/strong> has been added:<\/p>\n<pre>class CourseAdmin(admin.ModelAdmin):\r\n    list_display = ( 'course_id', 'title', 'catalog_number', )\r\n    search_fields = ( 'course_id', 'title', 'catalog_number', )\r\n    list_filter = ('status',)\r\n\r\n    <strong>readonly_fields<\/strong> = ('semester_details', '<strong>enrollment_chart<\/strong>' )\r\n    fieldsets = [\r\n     ('Course', { 'fields':  [  'course_id', 'title', 'catalog_number', \\\r\n                    'department', 'course_type', 'status', ]}), \\\r\n\r\n    ('Semester Details', { 'fields':  [  'semester_details',  ]}),\\\r\n    ('<strong>Enrollment<\/strong>', { 'fields':  [  '<strong>enrollment_chart<\/strong>',  ]}),\\\r\n                    ]\r\nadmin.site.register(Course, CourseAdmin)<\/pre>\n<p><strong>Summary<\/strong><\/p>\n<p>The explanation above is long, but, if you&#8217;re django instance is already running, the steps are fairly quick.<\/p>\n<p>(a) Download <a href=\"http:\/\/www.highcharts.com\/\">Highcharts<\/a>, unzip it, and place in a directory under your Django MEDIA_ROOT directory (step 1)<\/p>\n<p>(b) Add two admin templates:<\/p>\n<p style=\"padding-left: 30px\">change_form.html\u00a0 &#8211; call the JQuery and the highcharts.js libraries\u00a0 (steps 2 and 3)<\/p>\n<p style=\"padding-left: 30px\">enrollment_chart.html &#8211; or another template to put the chart&#8217;s javascript + containing &lt;div..&gt; (steps 5 and 6)<\/p>\n<p>(c) Create a function accessible by your model that passes chart data\u00a0 (step 4)<\/p>\n<p>(d) Modify the admin.py to link the function to the django admin and a template (step 7)<\/p>\n<p>Once the basics are going, you can start customizing your chart:)<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>(Note, this assumes that you have a Django project installed and running. This example is for Django 1.3, the official version.) Below are some notes for adding Highcharts to a Django admin page. In this case, I want to chart the enrollment in a science class over time. Specifically, I have a model name &#8220;Course&#8221; &hellip; <a href=\"https:\/\/archive.blogs.harvard.edu\/rprasad\/2011\/08\/30\/highcharts-django-admin\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Highcharts in the Django Admin<\/span><\/a><\/p>\n","protected":false},"author":3875,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_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},"jetpack_post_was_ever_published":false},"categories":[50627,50629,17294],"tags":[50638,50631,50639,50640],"class_list":["post-1","post","type-post","status-publish","format-standard","hentry","category-django","category-highcharts","category-jquery","tag-django","tag-django-admin","tag-highcharts","tag-jquery"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p4JC3p-1","_links":{"self":[{"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/posts\/1","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=1"}],"version-history":[{"count":58,"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/posts\/1\/revisions"}],"predecessor-version":[{"id":4,"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/posts\/1\/revisions\/4"}],"wp:attachment":[{"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/media?parent=1"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/categories?post=1"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/tags?post=1"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}