tag:blogger.com,1999:blog-90144570883940599182008-08-08T19:36:33.803+02:00DjangoTricksArchatashttp://www.blogger.com/profile/18444891139539061590noreply@blogger.comBlogger10125tag:blogger.com,1999:blog-9014457088394059918.post-49788445073229287212008-08-08T18:05:00.003+02:002008-08-08T18:20:28.759+02:00MultipleSubmitButton Widget for ChoiceFieldRecently I published a <a href="http://www.djangosnippets.org/snippets/951/">snippet</a> with a widget rendering a choice field as a series of submit buttons.<br /><br />So the <code>{{ form.do }}</code> field from the following form:<br /><br /><pre><span class="syntax0">SUBMIT_CHOICES <span class="syntax18">=</span> <span class="syntax18">(</span><br /> <span class="syntax18">(</span><span class="syntax13">'</span><span class="syntax13">save</span><span class="syntax13">'</span>, <span class="syntax6">_</span><span class="syntax18">(</span><span class="syntax13">"</span><span class="syntax13">Save</span><span class="syntax13">"</span><span class="syntax18">)</span><span class="syntax18">)</span>,<br /> <span class="syntax18">(</span><span class="syntax13">'</span><span class="syntax13">save</span><span class="syntax13">-</span><span class="syntax13">add</span><span class="syntax13">'</span>, <span class="syntax6">_</span><span class="syntax18">(</span><span class="syntax13">"</span><span class="syntax13">Save</span><span class="syntax13"> </span><span class="syntax13">and</span><span class="syntax13"> </span><span class="syntax13">Add</span><span class="syntax13"> </span><span class="syntax13">Another</span><span class="syntax13">"</span><span class="syntax18">)</span><span class="syntax18">)</span>,<br /> <span class="syntax18">)</span><br /><br /><span class="syntax8">class</span> <span class="syntax6">TestForm</span><span class="syntax18">(</span>forms.Form<span class="syntax18">)</span><span class="syntax8">:</span><br /> do <span class="syntax18">=</span> forms.<span class="syntax6">ChoiceField</span><span class="syntax18">(</span><br /> widget<span class="syntax18">=</span>MultipleSubmitButton,<br /> choices<span class="syntax18">=</span>SUBMIT_CHOICES,<br /> <span class="syntax18">)</span><br /><br /></span></pre><br /><br />will be rendered as:<br /><br /><pre><span class="syntax0"><span class="syntax17"><</span><span class="syntax17">ul</span><span class="syntax17">></span><br /><span class="syntax17"><</span><span class="syntax17">li</span><span class="syntax17">></span><span class="syntax17"><</span><span class="syntax17">button</span><span class="syntax17"> </span><span class="syntax17">type</span><span class="syntax18">=</span><span class="syntax13">"</span><span class="syntax13">submit</span><span class="syntax13">"</span><span class="syntax17"> </span><span class="syntax17">name</span><span class="syntax18">=</span><span class="syntax13">"</span><span class="syntax13">do</span><span class="syntax13">"</span><span class="syntax17"> </span><span class="syntax17">value</span><span class="syntax18">=</span><span class="syntax13">"</span><span class="syntax13">save</span><span class="syntax13">"</span><span class="syntax17">></span>Save<span class="syntax17"><</span><span class="syntax17">/</span><span class="syntax17">button</span><span class="syntax17">></span><span class="syntax17"><</span><span class="syntax17">/</span><span class="syntax17">li</span><span class="syntax17">></span><br /><span class="syntax17"><</span><span class="syntax17">li</span><span class="syntax17">></span><span class="syntax17"><</span><span class="syntax17">button</span><span class="syntax17"> </span><span class="syntax17">type</span><span class="syntax18">=</span><span class="syntax13">"</span><span class="syntax13">submit</span><span class="syntax13">"</span><span class="syntax17"> </span><span class="syntax17">name</span><span class="syntax18">=</span><span class="syntax13">"</span><span class="syntax13">do</span><span class="syntax13">"</span><span class="syntax17"> </span><span class="syntax17">value</span><span class="syntax18">=</span><span class="syntax13">"</span><span class="syntax13">save-add</span><span class="syntax13">"</span><span class="syntax17">></span>Save and Add Another<span class="syntax17"><</span><span class="syntax17">/</span><span class="syntax17">button</span><span class="syntax17">></span><span class="syntax17"><</span><span class="syntax17">/</span><span class="syntax17">li</span><span class="syntax17">></span><br /><span class="syntax17"><</span><span class="syntax17">/</span><span class="syntax17">ul</span><span class="syntax17">></span><br /></span></pre><br /><br />Can somebody enhance this widget so that it supports iteration through different choices and getting specific buttons by indexes in the template? My trials failed, but maybe you will succeed!Archatashttp://www.blogger.com/profile/18444891139539061590noreply@blogger.comtag:blogger.com,1999:blog-9014457088394059918.post-2639946289190619992008-07-16T01:16:00.019+02:002008-07-31T11:44:10.233+02:00EuroPython 2008I started writing this post at the airport just before flying back from Vilnius to Berlin. EuroPython 2008 - the three-days conference and sprints afterwards - gave me loads of information, new relations, and better understanding of the big image of Python developers' community.<br /><br /><a href="http://europython.org/"><img src="http://bp3.blogger.com/_nG3SKqiLARM/SHrDTFLntAI/AAAAAAAAANk/mf48aYxhXn8/s400/europython.png" border="0" alt="EuroPython" /></a><br /><br />Some highlights from the conference follow.<br /><ul><li>During video conference the author of Python programming language <a href="http://en.wikipedia.org/wiki/Guido_van_Rossum">Guido van Rossum</a> encouraged using Python 2.6 just after the release, but said that Python 3.0 still shouldn't be used for production. The good future-proof practices are inheriting from <code>object</code> for classes, using <code>xrange()</code>, <code>sorted()</code>, and <code>zip()</code> functions, "<code>//</code>" for floor divisions, and <code>dict.iterkeys()</code>. The full porting to 3.0 guide will be probably written and published in the python.org site.</li><br /><li><a href="http://clonedigger.sourceforge.net/">Clone Digger</a> is a project from Google Summer of Code 2008 for finding similar pieces of code which could be optimized by moving that to parameterized functions.</li><br /><li>Restrictive Python is a project which blocks the user from executing dangerous functions or methods or accessing files which might harm the system. You can try Restrictive Python out in the <a href="http://codespeak.net:7777/">simulated terminal</a>.</li><br /><li>Python is an interpreted language and if you want to deploy a project writen in Python, you have to be sure that the end user will have Python interpreter installed there. O you can create an executable file from Python project using one of the following tools: <a href="http://www.py2exe.org/">Py2exe</a>, <a href="http://pyinstaller.python-hosting.com/">PyInstaller</a>, or <a href="http://pypi.python.org/pypi/bbfreeze/0.95.4">BBFreeze</a>.</li><br /><li>There is a combined installer of Python, SQLite, and Django for Windows and it is called <a href="http://www.instantdjango.com/">Instant Django</a>.</li><br /><li><a href="http://code.google.com/p/deseb/">Django DB External Scheme Evolution Branch</a> is a separate application for doing DB scheme changes easily without manual DB field editing.</li><br /><li>Honza Král showed the essentials of the <a href="http://www.europython.org/TalkMaterials?action=AttachFile&do=view&target=django-nfa.pdf">new-forms admin</a> to which I am going to port our Django projects the next days. Directly from him I learned that new forms will still have validators which will work only to check the value of that one specific field (not related to other fields). If some multiple field validation is necessary, the clean method for the form should be overwritten. All the global field-unrelated form errors will be passed to <code>{{ form.non_field_errors }}</code> variable.</li><br /><li>Christian Scholtz presented <a href="http://mrtopf.de/blog/secondlife/python-and-the-open-grid-protocol-status-of-the-pyogp-project-technical/">PYOGP</a> which is Python-based environment for testing the Open Grid Protocol used for exchanging avatars and other objects among virtual realms like different regions of Second Life.</li><br /><li>Ricardo Quesada and Lucio Torre told us about <a href="http://europython.wordpress.com/2008/07/16/video-cocos2d-a-framework-for-building-2d-games/">cocos2d</a> - a framework made in Python for presentations and sprite-based 2D games.</li><br /><li>If you ever need to export some data from a database to Excel Sheet or import from Excel, you can do that not only in CSV (Comma Separated Values) format. You can also use the original XLS format with one of the following libraries: <a href="http://pypi.python.org/pypi/xlrd/0.5.2">xlrd</a>, <a href="https://secure.simplistix.co.uk/svn/xlwt/trunk/">xlwt</a>, or <a href="http://pypi.python.org/pypi/pyExcelerator/0.5.3a">pyExcelerator</a>. I successfully used the latter one last week.</li><br /><li>CVS and SVN are not the only version control management systems in the world :D. The others like <a href="http://www.selenic.com/mercurial/wiki/">Mercurial</a>, <a href="http://git.or.cz/">Git</a> and <a href="http://bazaar-vcs.org/">Bazaar</a> are also worthy checking. These are all distributed systems which mean that they don't have one centralized source. Bazaar is written in Python and has API for manipulating information about revisions, committers, and other version-control-related stuff.</li></ul><br /><br />Some other useful links:<br /><ul><li><a href="http://code.djangoproject.com/wiki/SprintEuroPython2008">Django Sprint at EuroPython 2008</a></li><br /><li><a href="http://www.europython.org/TalkMaterials">Talk Materials</a></li><br /><li><a href="http://www.europython.org/OreillyDiscount">Discount for O'Reilly Books<br /></a></li></ul><br /><br />Others blogged about EuroPython 2008 as well:<br /><ul><li>Ville Säävuori: <a href="http://www.unessa.net/en/hoyci/2008/07/europython-day-1/">Day 1</a>, <a href="http://www.unessa.net/en/hoyci/2008/07/europython-day-2/">Day 2</a>, <a href="http://www.unessa.net/en/hoyci/2008/07/europython-day-3/">Day 3</a>.</li><br /><li><a href="http://ollehost.dk/blog/2008/07/14/europython-2008-my-little-log/">Olle Jonsson Morningstar</a></li><br /><li><a href="http://www.sauria.com/blog/2008/07/11/my-first-europython/">Ted Leung</a></li><br /><li><a href="http://www.cheeming.com/blog/index.php/2008/07/18/europython-2008-in-vilnius">Chee Ming Chew</a></li></ul>Archatashttp://www.blogger.com/profile/18444891139539061590noreply@blogger.comtag:blogger.com,1999:blog-9014457088394059918.post-57340751778088036502008-06-02T19:28:00.012+02:002008-06-02T22:45:05.040+02:00Django Meetup PostmortemThanks to the organizer <a href="http://jannisleidel.com/">Jannis</a>, last Friday German djangoers met successfully, got some beer at <a href="http://www.schleusenkrug.de/">Schleusenkrug</a> in Tiergarten, Berlin, and became better aquainted with each other. We discussed the latest actualities like licenses, project deployment, business models, the future of Django, who from the gods of Django said what in which blog, and other geeky stuff.<br /><br /><a href="http://bp3.blogger.com/_nG3SKqiLARM/SERX6VYQ7zI/AAAAAAAAAME/gr5mIJBsh0A/s1600-h/left.jpg"><img src="http://bp3.blogger.com/_nG3SKqiLARM/SERX6VYQ7zI/AAAAAAAAAME/gr5mIJBsh0A/s320/left.jpg" border="0" alt="Some djangoers on the left side of the table" /></a><br /><br /><a href="http://bp0.blogger.com/_nG3SKqiLARM/SERYOfChfXI/AAAAAAAAAMM/YkxhTXGjHGQ/s1600-h/right.jpg"><img src="http://bp0.blogger.com/_nG3SKqiLARM/SERYOfChfXI/AAAAAAAAAMM/YkxhTXGjHGQ/s320/right.jpg" border="0" alt="Some djangoers on the right side of the table" /></a><br /><br />If you want to get in touch with German djangoers, you can join the <code>#django-de</code> IRC channel on <code>irc.freenode.net</code>. Also you can subscribe to their blogs at <a href="http://www.django-de.org/community/">django-de.org</a>.Archatashttp://www.blogger.com/profile/18444891139539061590noreply@blogger.comtag:blogger.com,1999:blog-9014457088394059918.post-10385414161392310252008-05-27T19:34:00.007+02:002008-05-27T20:04:41.012+02:00Django Meetup at LinuxtagPssst. Don't tell anybody! There is an unofficial <a href="http://jannisleidel.com/2008/05/django-user-meetup-in-berlin-at-linuxtag-2008/">Django user meetup</a> happening in Berlin this Friday at five. <br /><br /><pre><code><span class="syntax0">datetime.<span class="syntax6">datetime</span><span class="syntax18">(</span><span class="syntax5">2008</span>, <span class="syntax5">5</span>, <span class="syntax5">27</span>, <span class="syntax5">17</span>, <span class="syntax5">0</span><span class="syntax18">)</span><br /></span></code></pre><br /><br />The gathering point is at the <a href="http://www.linuxtag.org/2008/en/besucher/anreise.html">main entrance of Linuxtag conference</a> (Messe Berlin).<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://flickr.com/photos/67855182@N00/1124152390/"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px;" src="http://farm2.static.flickr.com/1295/1124152390_8af3273de4.jpg?v=0" border="0" alt="" /></a>Archatashttp://www.blogger.com/profile/18444891139539061590noreply@blogger.comtag:blogger.com,1999:blog-9014457088394059918.post-4603450515710278152008-05-23T23:07:00.014+02:002008-05-26T23:11:09.177+02:00Decorating the Render Methods of New-Form WidgetsPerhaps all template masters have already faced the problem of styling HTML input fields of different types. The selectors like <code>input[type=checkbox]</code> and similar in CSS are not supported by IE so people working with templates and CSS obviously need some other way to select and style specific types of input fields.<br /><br />There are a few ugly ways to do that which violate the <acronym title="Don't Repeat Yourself">DRY</acronym> principle:<br /><ul><br /><li><strong>Encompassing the form element in the template with HTML tag which has a class representing specific type of the input field.</strong><br />For example:<br /><pre><code><span class="syntax0"><span class="syntax17"><</span><span class="syntax17">span</span><span class="syntax17"> </span><span class="syntax17">class</span><span class="syntax18">=</span><span class="syntax13">"</span><span class="syntax13">form_checkbox</span><span class="syntax13">"</span><span class="syntax17">></span><br /> {{ form.is_privacy_policy_confirmed }}<br /><span class="syntax17"><</span><span class="syntax17">/</span><span class="syntax17">span</span><span class="syntax17">></span><br /></span></code></pre><br /></li><br /><li><strong>Defining the specific CSS class for each form field widget in the form.</strong><br />For example:<br /><pre><code><span class="syntax0"><span class="syntax8">class</span> <span class="syntax6">FormExample</span><span class="syntax18">(</span>forms.Form<span class="syntax18">)</span><span class="syntax8">:</span><br /> is_privacy_policy_confirmed <span class="syntax18">=</span> forms.<span class="syntax6">BooleanField</span><span class="syntax18">(</span><br /> required<span class="syntax18">=</span><span class="syntax10">True</span>,<br /> widget<span class="syntax18">=</span><span class="syntax6">CheckboxInput</span><span class="syntax18">(</span>attrs<span class="syntax18">=</span>{<span class="syntax13">'</span><span class="syntax13">class</span><span class="syntax13">'</span><span class="syntax8">:</span> <span class="syntax13">'</span><span class="syntax13">form_checkbox</span><span class="syntax13">'</span>}<span class="syntax18">)</span>,<br /> <span class="syntax18">)</span><br /></span></code></pre><br /></li><br /><li><strong>Extending all Fields and all Widgets which use HTML input fields and using the extended versions instead of the originals.</strong><br /></li> <br /></ul><br /><br />I don't like any of them, because they force me or the template formatters to repeat ourselves and make plenty of replacements in our existing forms.<br /><br />Although <a href="http://groups.google.com/group/django-developers/browse_thread/thread/40dde7a2de7f2d8d/5d62405623d6502b?#5d62405623d6502b">"most sane developers consider it a bad idea"</a>, I see the <strong>Guerrilla patching</strong> of the Widget's render method as the nicest solution to solve this problem.<br /><br /><a href="http://en.wikipedia.org/wiki/Monkey_patch">Guerrilla patch</a> is the modification of the runtime code in dynamic languages without changing the original source code.<br /><br />The method <code>render</code> of the <code>Widget</code> class draws the input field in HTML. As it takes a parameter <code>attrs</code> for additional input field attributes, my idea was to create a decorator which modifies the incoming parameters and adds a CSS class <code>"form_TYPE"</code>, where <code>TYPE</code> is the input field type.<br /><br />With a little help by <a href="http://blog.sandbox.lt/en/">Dalius Dobravolskas</a>, I succeeded to code a <strong>decorator</strong> having an optional parameter which defines the CSS class name for the field. If the class name is not defined, the attribute <code>input_type</code> of the Widget class is used for forming the CSS class name (N.B. not all widgets have this attribute).<br /><br /><pre><code><span class="syntax0"><span class="syntax8">from</span> django.newforms.widgets <span class="syntax8">import</span> Input, CheckboxInput, RadioSelect, CheckboxSelectMultiple<br /><br /><span class="syntax1">#</span><span class="syntax1">##</span><span class="syntax1"> </span><span class="syntax1">adding</span><span class="syntax1"> </span><span class="syntax1">class="form_*"</span><span class="syntax1"> </span><span class="syntax1">to</span><span class="syntax1"> </span><span class="syntax1">all</span><span class="syntax1"> </span><span class="syntax1">html</span><span class="syntax1"> </span><span class="syntax1">input</span><span class="syntax1"> </span><span class="syntax1">fields</span><span class="syntax1"> </span><span class="syntax1">###</span><br /><span class="syntax8">def</span> <span class="syntax6">add_css_class</span><span class="syntax18">(</span>css_class<span class="syntax18">=</span><span class="syntax13">"</span><span class="syntax13">"</span><span class="syntax18">)</span><span class="syntax8">:</span><br /> <span class="syntax8">def</span> <span class="syntax6">modify_input_class</span><span class="syntax18">(</span>function<span class="syntax18">)</span><span class="syntax8">:</span><br /> _css_class <span class="syntax18">=</span> css_class<br /> <span class="syntax8">def</span> <span class="syntax6">new_function</span><span class="syntax18">(</span><span class="syntax18">*</span>args, <span class="syntax18">*</span><span class="syntax18">*</span>kwargs<span class="syntax18">)</span><span class="syntax8">:</span><br /> arg_names <span class="syntax18">=</span> function.func_code.co_varnames<br /> new_kwargs <span class="syntax18">=</span> <span class="syntax9">dict</span><span class="syntax18">(</span><span class="syntax9">zip</span><span class="syntax18">(</span>arg_names, args<span class="syntax18">)</span><span class="syntax18">)</span><br /> new_kwargs.<span class="syntax6">update</span><span class="syntax18">(</span>kwargs<span class="syntax18">)</span><br /> attrs <span class="syntax18">=</span> new_kwargs.<span class="syntax6">get</span><span class="syntax18">(</span><span class="syntax13">"</span><span class="syntax13">attrs</span><span class="syntax13">"</span>, <span class="syntax10">None</span><span class="syntax18">)</span><br /> <span class="syntax8">if</span> <span class="syntax8">not</span> attrs<span class="syntax8">:</span><br /> attrs <span class="syntax18">=</span> {}<br /> css_class <span class="syntax18">=</span> _css_class <span class="syntax8">or</span> <span class="syntax13">"</span><span class="syntax13">form_</span><span class="syntax16">%s</span><span class="syntax13">"</span> <span class="syntax18">%</span> <span class="syntax9">getattr</span><span class="syntax18">(</span><br /> new_kwargs[<span class="syntax13">'</span><span class="syntax13">self</span><span class="syntax13">'</span>],<br /> <span class="syntax13">"</span><span class="syntax13">input_type</span><span class="syntax13">"</span>,<br /> <span class="syntax13">"</span><span class="syntax13">undefined</span><span class="syntax13">"</span>,<br /> <span class="syntax18">)</span><br /> <span class="syntax8">if</span> <span class="syntax13">"</span><span class="syntax13">class</span><span class="syntax13">"</span> <span class="syntax8">in</span> attrs<span class="syntax8">:</span><br /> css_classes <span class="syntax18">=</span> attrs[<span class="syntax13">"</span><span class="syntax13">class</span><span class="syntax13">"</span>].<span class="syntax6">split</span><span class="syntax18">(</span><span class="syntax18">)</span><br /> <span class="syntax8">if</span> css_class <span class="syntax8">not</span> <span class="syntax8">in</span> css_classes<span class="syntax8">:</span><br /> css_classes.<span class="syntax6">append</span><span class="syntax18">(</span>css_class<span class="syntax18">)</span><br /> attrs[<span class="syntax13">"</span><span class="syntax13">class</span><span class="syntax13">"</span>] <span class="syntax18">=</span> <span class="syntax13">"</span><span class="syntax13"> </span><span class="syntax13">"</span>.<span class="syntax6">join</span><span class="syntax18">(</span>css_classes<span class="syntax18">)</span><br /> <span class="syntax8">else</span><span class="syntax8">:</span><br /> attrs[<span class="syntax13">"</span><span class="syntax13">class</span><span class="syntax13">"</span>] <span class="syntax18">=</span> css_class<br /> new_kwargs[<span class="syntax13">"</span><span class="syntax13">attrs</span><span class="syntax13">"</span>] <span class="syntax18">=</span> attrs<br /> <span class="syntax8">self</span> <span class="syntax18">=</span> new_kwargs.<span class="syntax6">pop</span><span class="syntax18">(</span><span class="syntax13">"</span><span class="syntax13">self</span><span class="syntax13">"</span><span class="syntax18">)</span><br /> <span class="syntax8">return</span> <span class="syntax6">function</span><span class="syntax18">(</span><span class="syntax8">self</span>, <span class="syntax18">*</span><span class="syntax18">*</span>new_kwargs<span class="syntax18">)</span><br /> <span class="syntax8">return</span> new_function<br /> <span class="syntax8">return</span> modify_input_class<br />Input.render <span class="syntax18">=</span> <span class="syntax6">add_css_class</span><span class="syntax18">(</span><span class="syntax18">)</span><span class="syntax18">(</span>Input.render<span class="syntax18">)</span><br />CheckboxInput.render <span class="syntax18">=</span> <span class="syntax6">add_css_class</span><span class="syntax18">(</span><span class="syntax13">"</span><span class="syntax13">form_checkbox</span><span class="syntax13">"</span><span class="syntax18">)</span><span class="syntax18">(</span>CheckboxInput.render<span class="syntax18">)</span><br />RadioSelect.render <span class="syntax18">=</span> <span class="syntax6">add_css_class</span><span class="syntax18">(</span><span class="syntax13">"</span><span class="syntax13">form_radio</span><span class="syntax13">"</span><span class="syntax18">)</span><span class="syntax18">(</span>RadioSelect.render<span class="syntax18">)</span><br />CheckboxSelectMultiple.render <span class="syntax18">=</span> <span class="syntax6">add_css_class</span><span class="syntax18">(</span><span class="syntax13">"</span><span class="syntax13">form_checkbox</span><span class="syntax13">"</span><span class="syntax18">)</span><span class="syntax18">(</span>CheckboxSelectMultiple.render<span class="syntax18">)</span><br /></span></code></pre><br /><br />To use this code, just place it in some <code>models.py</code> file in your project.<br /><br />The <strong>strange part</strong> here was that the variable <code>css_class</code> isn't recognized by the sub-child function <code>new_function</code> directly although the scope of the variable <code>css_class</code> should let it be accessed there. Anyway, the value got easily accessible when I reassigned it to another variable like <code>_css_class</code> in the child function <code>modify_input_class</code>.<br /><br />The <strong>tricky part</strong> of this snippet was getting the <code>attrs</code> argument from the decorated function as it was not clear whether it would be passed as a positional or as a named argument. The first three lines of the function <code>new_function</code> collects all the incoming arguments to a dictionary <code>new_kwargs</code>. They can be modified and then passed to the original function to decorate.<br /><br />Ups. I am late to the studio. So see you next time!Archatashttp://www.blogger.com/profile/18444891139539061590noreply@blogger.comtag:blogger.com,1999:blog-9014457088394059918.post-16609063586878994572008-04-08T20:37:00.008+02:002008-05-26T02:47:34.874+02:00Tips #2What time is it now? It's time to give you some more tips about Django development!<br /><br /><strong id="tips_2.1">Use batch scripts to automate manual routines.</strong> Do not repeat yourself extracting and compiling translatable strings, starting and stopping development web-servers, updating and committing your project to the version-control system in the console. Write batch scripts which you can run within one mouse click instead.<br /><br /><strong id="tips_2.2">Define overwritable constants in your applications.</strong> Your applications are likely using some values that might be defined as constant values, i.e. the dimensions for avatars of users. Define those constants so, that you could overwrite them in the project settings if necessary. <br /><pre><code><span class="syntax0"><span class="syntax8">from</span> django.conf <span class="syntax8">import</span> settings<br />SOME_SETTING <span class="syntax18">=</span> <span class="syntax9">getattr</span><span class="syntax18">(</span>settings, <span class="syntax13">"</span><span class="syntax13">SOME_SETTING</span><span class="syntax13">"</span>, <span class="syntax13">"</span><span class="syntax13">default</span><span class="syntax13"> </span><span class="syntax13">value</span><span class="syntax13">"</span><span class="syntax18">)</span><br /></span></code></pre><br /><br /><strong id="tips_2.3">Have one view for site-related JavaScript globals.</strong> Django views usually return (X)HTML-based responses, but it can return XML, JavaScript or others as well. Usually you will hold all you JavaScript functions in static files, but there might be some situation, where you need to get information related to database or project settings, for example, the MEDIA_URL.<br />The following view might be used to display a javascript page directly from a template. Just pass the <code>template</code> to the view in your urls.py file.<br /><pre><code><span class="syntax0"><span class="syntax8">from</span> datetime <span class="syntax8">import</span> datetime, timedelta<br /><span class="syntax8">from</span> django.views.generic.simple <span class="syntax8">import</span> direct_to_template<br /><span class="syntax8">def</span> <span class="syntax6">direct_to_js_template</span><span class="syntax18">(</span>request, <span class="syntax18">*</span>args, <span class="syntax18">*</span><span class="syntax18">*</span>kwargs<span class="syntax18">)</span><span class="syntax8">:</span><br /> response <span class="syntax18">=</span> <span class="syntax6">direct_to_template</span><span class="syntax18">(</span>request, <span class="syntax18">*</span>args, <span class="syntax18">*</span><span class="syntax18">*</span>kwargs<span class="syntax18">)</span><br /> response[<span class="syntax13">'</span><span class="syntax13">Content</span><span class="syntax13">-</span><span class="syntax13">Type</span><span class="syntax13">'</span>] <span class="syntax18">=</span> <span class="syntax13">"</span><span class="syntax13">application</span><span class="syntax13">/</span><span class="syntax13">x</span><span class="syntax13">-</span><span class="syntax13">javascript</span><span class="syntax13">"</span><br /> now <span class="syntax18">=</span> datetime.<span class="syntax6">utcnow</span><span class="syntax18">(</span><span class="syntax18">)</span><br /> response[<span class="syntax13">'</span><span class="syntax13">Last</span><span class="syntax13">-</span><span class="syntax13">Modified</span><span class="syntax13">'</span>] <span class="syntax18">=</span> now.<span class="syntax6">strftime</span><span class="syntax18">(</span><span class="syntax13">'</span><span class="syntax13">%</span><span class="syntax13">a</span><span class="syntax13">,</span><span class="syntax13"> </span><span class="syntax16">%d</span><span class="syntax13"> </span><span class="syntax13">%</span><span class="syntax13">b</span><span class="syntax13"> </span><span class="syntax13">%</span><span class="syntax13">Y</span><span class="syntax13"> </span><span class="syntax13">%</span><span class="syntax13">H</span><span class="syntax13">:</span><span class="syntax13">%</span><span class="syntax13">M</span><span class="syntax13">:</span><span class="syntax16">%S</span><span class="syntax13"> </span><span class="syntax13">GMT</span><span class="syntax13">'</span><span class="syntax18">)</span><br /> expires <span class="syntax18">=</span> now <span class="syntax18">+</span> <span class="syntax6">timedelta</span><span class="syntax18">(</span><span class="syntax5">0</span>, <span class="syntax5">2678400</span><span class="syntax18">)</span><br /> response[<span class="syntax13">'</span><span class="syntax13">Expires</span><span class="syntax13">'</span>] <span class="syntax18">=</span> expires.<span class="syntax6">strftime</span><span class="syntax18">(</span><span class="syntax13">'</span><span class="syntax13">%</span><span class="syntax13">a</span><span class="syntax13">,</span><span class="syntax13"> </span><span class="syntax16">%d</span><span class="syntax13"> </span><span class="syntax13">%</span><span class="syntax13">b</span><span class="syntax13"> </span><span class="syntax13">%</span><span class="syntax13">Y</span><span class="syntax13"> </span><span class="syntax13">%</span><span class="syntax13">H</span><span class="syntax13">:</span><span class="syntax13">%</span><span class="syntax13">M</span><span class="syntax13">:</span><span class="syntax16">%S</span><span class="syntax13"> </span><span class="syntax13">GMT</span><span class="syntax13">'</span><span class="syntax18">)</span><br /> <span class="syntax8">return</span> response<br /></span></code></pre> <br /><br />And now it's time to go home and to get relaxed.Archatashttp://www.blogger.com/profile/18444891139539061590noreply@blogger.comtag:blogger.com,1999:blog-9014457088394059918.post-30876737199792393442008-03-24T09:34:00.007+01:002008-05-26T02:44:25.447+02:00DRY While Working With Choices for FormsWhen creating dozens of forms with selection fields for some many-to-one or many-to-many relations, you might find that it's ineffective to create choices for the form fields from querysets formed by the relations defined by ForeignKeys and ManyToManyFields. You have to import the related models, filter the choices analogously to the limit_choices_to parameter, and form a list of tuples again and again.<br /><br />To get the same choices from the model as in the admin form, you can use the following:<br /><pre><code><span class="syntax0">FIELD_CHOICES <span class="syntax18">=</span> SomeModel._meta.<span class="syntax6">get_field</span><span class="syntax18">(</span><span class="syntax13">"</span><span class="syntax13">field_name</span><span class="syntax13">"</span><span class="syntax18">)</span>.<span class="syntax6">get_choices</span><span class="syntax18">(</span><span class="syntax18">)</span><br /></span></code></pre><br />Then you can modify the text for the null-value choice, like<br /><pre><code><span class="syntax0">FIELD_CHOICES[<span class="syntax5">0</span>] <span class="syntax18">=</span> <span class="syntax18">(</span><span class="syntax13">"</span><span class="syntax13">"</span> <span class="syntax6">_</span><span class="syntax18">(</span><span class="syntax13">"</span><span class="syntax13">-</span><span class="syntax13"> </span><span class="syntax13">Choose</span><span class="syntax13"> </span><span class="syntax13">One</span><span class="syntax13"> </span><span class="syntax13">-</span><span class="syntax13">"</span><span class="syntax18">)</span><span class="syntax18">)</span><br /></span></code></pre><br />or even remove it:<br /><pre><code><span class="syntax0"><span class="syntax8">del</span> FIELD_CHOICES[<span class="syntax5">0</span>]<br /></span></code></pre><br />To save the selected object you can simply assign the chosen value to the foreign key, like:<br /><pre><code><span class="syntax0">new_instance <span class="syntax18">=</span> <span class="syntax6">SomeModel</span><span class="syntax18">(</span><span class="syntax18">)</span><br />new_instance.field_name_id <span class="syntax18">=</span> form.cleaned_data[<span class="syntax13">'</span><span class="syntax13">field_name</span><span class="syntax13">'</span>]<br />new_instance.<span class="syntax6">save</span><span class="syntax18">(</span><span class="syntax18">)</span><br /></span></code></pre><br />If you need to do something with the selected object, you can still live without importing specific models and filtering the entries in the same manner as limit_choices_to. To save time, you can use the following function, which returns the queryset containing all the choosable objects:<br /><pre><code><span class="syntax0"><span class="syntax8">def</span> <span class="syntax6">get_related_queryset</span><span class="syntax18">(</span>model, field_name<span class="syntax18">)</span><span class="syntax8">:</span><br /> <span class="syntax14">"""</span><br /><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14">Get</span><span class="syntax14"> </span><span class="syntax14">the</span><span class="syntax14"> </span><span class="syntax14">queryset</span><span class="syntax14"> </span><span class="syntax14">for</span><span class="syntax14"> </span><span class="syntax14">the</span><span class="syntax14"> </span><span class="syntax14">choices</span><span class="syntax14"> </span><span class="syntax14">of</span><span class="syntax14"> </span><span class="syntax14">the</span><span class="syntax14"> </span><span class="syntax14">field</span><span class="syntax14"> </span><span class="syntax14">in</span><span class="syntax14"> </span><span class="syntax14">a</span><span class="syntax14"> </span><span class="syntax14">model</span><br /><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14">Example</span><span class="syntax14">:</span><br /><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14">objects</span><span class="syntax14"> </span><span class="syntax14">=</span><span class="syntax14"> </span><span class="syntax14">get_related_queryset</span><span class="syntax14">(</span><span class="syntax14">SomeModel</span><span class="syntax14">,</span><span class="syntax14"> </span><span class="syntax14">"</span><span class="syntax14">field_name</span><span class="syntax14">"</span><span class="syntax14">)</span><br /><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14"> </span><span class="syntax14">"""</span><br /> f <span class="syntax18">=</span> model._meta.<span class="syntax6">get_field</span><span class="syntax18">(</span>field_name<span class="syntax18">)</span><br /> qs <span class="syntax18">=</span> f.rel.to._default_manager.<span class="syntax6">complex_filter</span><span class="syntax18">(</span>f.rel.limit_choices_to<span class="syntax18">)</span><br /> <span class="syntax8">return</span> qs<br /></span></code></pre><br />Just put this function in one of you applications and import it whenever you need to work with forms. And have happy Easter!Archatashttp://www.blogger.com/profile/18444891139539061590noreply@blogger.comtag:blogger.com,1999:blog-9014457088394059918.post-36679009727916275032008-03-04T23:28:00.013+01:002008-05-26T10:51:05.057+02:00Hacking Contributed ModelsDjango comes with a bunch of contributed applications like <code>auth</code> for authentication, <code>admin</code> for basic data manipulation, or <code>flatpages</code> for the dynamic content that tends to be rarely changed. Sometimes you want to use them, but their functionality doesn't completely fit your needs.<br /><br />You have several options in that case:<br /><ul><li>Use custom models with one-to-one or many-to-one relations, creating <a href="http://www.b-list.org/weblog/2006/jun/06/django-tips-extending-user-model/">extensions for existing models</a>. The main drawback of this approach is that those custom models will be editable in the contributed administration separately from the origin or you will need to create custom views to combine everything nicely.<br /></li><li>Use modified duplicates instead of the contributed applications. The main drawback of this case is that it will be hard to manage the updates of the models.</li><li><a href="http://www.mercurytide.co.uk/whitepapers/django-signals/">Use signals</a> to modify the models. This can be too complicated for simple changes.<br /></li><li>Modify the properties of the models on the fly.<br /></li></ul>Let's dig deeper into the last option. When you start the shell or request for a page on the web server, at first Django loads all modules according the order of the <code><a href="http://www.djangoproject.com/documentation/settings/#installed-apps">INSTALLED_APPS</a></code> setting. As Python is an interpreted language and all methods and properties are public, you can access and change them on the fly.<br /><br />For example, if your task is to rename verbose name of groups to "Roles" and show related users at the list view of contributed administration, then it can be achieved by the following code in some model which application appears somewhere below the <code>"django.contrib.auth"</code> in the <code>INSTALLED_APPS</code>.<br /><pre><code><span class="syntax0"><span class="syntax1">#</span><span class="syntax1">!/usr/bin/python</span><br /><span class="syntax1">#</span><span class="syntax1"> </span><span class="syntax1">-*-</span><span class="syntax1"> </span><span class="syntax1">coding:</span><span class="syntax1"> </span><span class="syntax1">UTF-8</span><span class="syntax1"> </span><span class="syntax1">-*-</span><br /><span class="syntax8">from</span> django.utils.translation <span class="syntax8">import</span> ugettext_lazy <span class="syntax8">as</span> _<br /><span class="syntax8">from</span> django.contrib.auth.models <span class="syntax8">import</span> Group<br /><br /><span class="syntax8">def</span> <span class="syntax6">modify_group_class</span><span class="syntax18">(</span><span class="syntax18">)</span><span class="syntax8">:</span><br /> <span class="syntax14">"""</span><span class="syntax14"> </span><span class="syntax14">A</span><span class="syntax14"> </span><span class="syntax14">function</span><span class="syntax14"> </span><span class="syntax14">modifying</span><span class="syntax14"> </span><span class="syntax14">the</span><span class="syntax14"> </span><span class="syntax14">contributed</span><span class="syntax14"> </span><span class="syntax14">Group</span><span class="syntax14"> </span><span class="syntax14">model</span><span class="syntax14"> </span><span class="syntax14">"""</span><br /> <span class="syntax1">#</span><span class="syntax1"> </span><span class="syntax1">modifying</span><span class="syntax1"> </span><span class="syntax1">the</span><span class="syntax1"> </span><span class="syntax1">verbose</span><span class="syntax1"> </span><span class="syntax1">names</span><br /> Group._meta.verbose_name <span class="syntax18">=</span> <span class="syntax6">_</span><span class="syntax18">(</span><span class="syntax13">"</span><span class="syntax13">Role</span><span class="syntax13">"</span><span class="syntax18">)</span><br /> Group._meta.verbose_name_plural <span class="syntax18">=</span> <span class="syntax6">_</span><span class="syntax18">(</span><span class="syntax13">"</span><span class="syntax13">Roles</span><span class="syntax13">"</span><span class="syntax18">)</span><br /><br /> <span class="syntax8">def</span> <span class="syntax6">display_users</span><span class="syntax18">(</span>group<span class="syntax18">)</span><span class="syntax8">:</span><br /> <span class="syntax14">"""</span><span class="syntax14"> </span><span class="syntax14">A</span><span class="syntax14"> </span><span class="syntax14">function</span><span class="syntax14"> </span><span class="syntax14">displaying</span><span class="syntax14"> </span><span class="syntax14">users</span><span class="syntax14"> </span><span class="syntax14">for</span><span class="syntax14"> </span><span class="syntax14">a</span><span class="syntax14"> </span><span class="syntax14">group</span><span class="syntax14"> </span><span class="syntax14">"""</span><br /> links <span class="syntax18">=</span> []<br /> <span class="syntax8">for</span> user <span class="syntax8">in</span> group.user_set.<span class="syntax9">all</span><span class="syntax18">(</span><span class="syntax18">)</span><span class="syntax8">:</span><br /> links.<span class="syntax6">append</span><span class="syntax18">(</span><br /> <span class="syntax14">"""</span><span class="syntax14"><</span><span class="syntax14">a</span><span class="syntax14"> </span><span class="syntax14">href</span><span class="syntax14">=</span><span class="syntax14">"</span><span class="syntax14">/</span><span class="syntax14">admin</span><span class="syntax14">/</span><span class="syntax14">auth</span><span class="syntax14">/</span><span class="syntax14">user</span><span class="syntax14">/</span><span class="syntax16">%d</span><span class="syntax14">"</span><span class="syntax14">></span><span class="syntax16">%s</span><span class="syntax14"><</span><span class="syntax14">/</span><span class="syntax14">a</span><span class="syntax14">></span><span class="syntax14">"""</span> <span class="syntax18">%</span> <span class="syntax18">(</span><br /> user.<span class="syntax9">id</span>,<br /> <span class="syntax18">(</span><span class="syntax13">"</span><span class="syntax16">%s</span><span class="syntax13"> </span><span class="syntax16">%s</span><span class="syntax13">"</span> <span class="syntax18">%</span> <span class="syntax18">(</span> <span class="syntax1">#</span><span class="syntax1"> </span><span class="syntax1">show</span><span class="syntax1"> </span><span class="syntax1">the</span><span class="syntax1"> </span><span class="syntax1">real</span><span class="syntax1"> </span><span class="syntax1">name</span><br /> user.first_name,<br /> user.last_name, <span class="syntax1">#</span><span class="syntax1"> </span><span class="syntax1">or</span><span class="syntax1"> </span><span class="syntax1">the</span><span class="syntax1"> </span><span class="syntax1">username</span><br /> <span class="syntax18">)</span><span class="syntax18">)</span>.<span class="syntax6">strip</span><span class="syntax18">(</span><span class="syntax18">)</span> <span class="syntax8">or</span> user.username,<br /> <span class="syntax18">)</span><br /> <span class="syntax18">)</span><br /> <span class="syntax8">return</span> <span class="syntax13">"</span><span class="syntax13"><</span><span class="syntax13">br</span><span class="syntax13"> </span><span class="syntax13">/</span><span class="syntax13">></span><span class="syntax13">"</span>.<span class="syntax6">join</span><span class="syntax18">(</span>links<span class="syntax18">)</span><br /> display_users.allow_tags <span class="syntax18">=</span> <span class="syntax10">True</span><br /> display_users.short_description <span class="syntax18">=</span> <span class="syntax6">_</span><span class="syntax18">(</span><span class="syntax13">"</span><span class="syntax13">Users</span><span class="syntax13">"</span><span class="syntax18">)</span><br /><br /> <span class="syntax1">#</span><span class="syntax1"> </span><span class="syntax1">attaching</span><span class="syntax1"> </span><span class="syntax1">the</span><span class="syntax1"> </span><span class="syntax1">new</span><span class="syntax1"> </span><span class="syntax1">function</span><span class="syntax1"> </span><span class="syntax1">to</span><span class="syntax1"> </span><span class="syntax1">the</span><span class="syntax1"> </span><span class="syntax1">Group</span><span class="syntax1"> </span><span class="syntax1">model</span><br /> Group.display_users <span class="syntax18">=</span> display_users<br /><br /> <span class="syntax1">#</span><span class="syntax1"> </span><span class="syntax1">changing</span><span class="syntax1"> </span><span class="syntax1">the</span><span class="syntax1"> </span><span class="syntax1">list_display</span><span class="syntax1"> </span><span class="syntax1">for</span><span class="syntax1"> </span><span class="syntax1">the</span><span class="syntax1"> </span><span class="syntax1">Group</span><span class="syntax1"> </span><span class="syntax1">model</span><br /> Group._meta.admin.list_display <span class="syntax18">=</span> <span class="syntax18">(</span><span class="syntax13">"</span><span class="syntax13">__str__</span><span class="syntax13">"</span>, <span class="syntax13">"</span><span class="syntax13">display_users</span><span class="syntax13">"</span><span class="syntax18">)</span><br /><br /><span class="syntax6">modify_group_class</span><span class="syntax18">(</span><span class="syntax18">)</span><br /></span></code></pre><br /><br />As you might see from this example, <code>Group._meta</code> returns the <code>Meta</code> class and <code>Group._meta.admin</code> returns the <code>Admin</code> class for the <code>Group</code> model. You can prove it to yourself by browsing objects in <a href="http://djangotricks.blogspot.com/2008/03/tips-1.html#tips_1.3">Django shell</a> <acronym title="also known as">aka</acronym> Python IDE.<br /><br />Use this kind of hacking whenever you reasonably need to change Django core functionalities or some third party modules and have no other choice. However, don't overuse it, 'cause it might lead to difficulties in maintaining the project.Archatashttp://www.blogger.com/profile/18444891139539061590noreply@blogger.comtag:blogger.com,1999:blog-9014457088394059918.post-32406910078018009222008-03-03T04:48:00.013+01:002008-05-26T02:06:25.515+02:00Tips #1As I can't get to sleep after my last mug of strong black tea, I decided to write my first tips which will make your life easier.<br /><br /><strong id="tips_1.1">Use consistent and readable coding convention.</strong> You know, class names start with capital letters, the variables and functions with small ones. The different words should be connected either using <code>camelCase</code> or <code>by_underscores</code>, but not mixed up in one project. Use triple double quotes <code>"""for documentation of functions"""</code> and triple single quotes <code>'''for commenting some code out'''</code>. For readability it is convenient to limit all your lines to 80 symbols. If a statement is very long, put it inside the brackets and then separate into different lines (this is easier to manage than having a backslash (\) before the new line symbol). When debugging and adding print statement or similar, also add some comment like <code># DEBUG</code>, which can be easily found later. If there is something to improve in the code, add a comment like <code># TODO</code> with the description of possible improvement. These words are easily findable later. If you have a long list, tuple or dictionary of items, or a function with many arguments which don't fit into the limit of 80 symbols, separate the items with each per line, indented by one tab. Use comma even after the last item unless it is <code>**kwargs</code>. Put the closing bracket after all. This will let you easily rearrange the order or amount of items later.<br /><pre><code><span class="syntax0">view <span class="syntax18">=</span> <span class="syntax6">my_special_view</span><span class="syntax18">(</span><br /> request,<br /> arg1,<br /> arg2,<br /> arg3,<br /> <span class="syntax18">)</span><br /></span></code></pre><br /><br /><strong id="tips_1.2">Access items in administration faster.</strong> Instead of browsing through links and loading unnecessary pages before getting to the necessary ones, type in the URI of the required model directly. All lists of objects can be accessed by /admin/<app_name>/<model_name_in_lower_case>/<br /><br /><strong id="tips_1.3">Use Python IDE and read Django source.</strong> Learn and use the interactive development environment, because it is usually a faster (and more attractive) way to learn how the functions work, than writing the code to the files first and checking the results in the browser afterwards. Use the <code>dir()</code> function for all objects to check the available methods and attributes, use the <code>__dict__</code> attribute for model instances to check its field values, write for-loops for listing out specific attributes from model instances from different querysets. Interaction and visual representation always gives you some better understanding about the architecture than just Django documentation. Also when something is not clear, don't be afraid to read the source. Take advantage of Django being an open source project.<br /><pre><code>>>> from django.contrib.auth.models import User<br />>>> for u in User.objects.all(): <br />... u.__dict__<br />... <br />{'username': u'aidas', 'first_name': u'Aidas', 'last_name': u'Bendoraitis', 'is_active': 1, 'email': u'', 'is_superuser': 0, 'is_staff': 0, 'last_login': datetime.datetime(2008, 2, 27, 13, 43, 58), 'password': u'sha1$e55b5$9aa9485f4ad6fc7947e80b63e6d56519c73ac5bb', 'id': 1L, 'date_joined': datetime.datetime(2007, 3, 30, 20, 56, 7)}<br /></code></pre><br /><br />That's it for this time. Now it's really time to sleep. :DArchatashttp://www.blogger.com/profile/18444891139539061590noreply@blogger.comtag:blogger.com,1999:blog-9014457088394059918.post-77966662853739778912008-03-02T05:22:00.005+01:002008-03-05T02:25:30.322+01:00HelloWorld.pyHello Pythoners! Hello Djangoers! Hello other people!<br /><br />This is yet another blog about <a href="http://www.djangoproject.com/">Django</a> - the Web framework for perfectionists with deadlines.<br /><br />I decided to start writing it to log some knowledge that comes from practice of daily work with Django. It's useful to have it for later reference and also for sharing it with you. And you are welcome to comment my code, correct where I am wrong, and open discussions.<br /><br />If you are not much familiar with Django, but would like to learn it, then I suggest you to read the following resources at first:<br /><ul><li><a href="http://www.djangobook.com/">http://www.djangobook.com/</a></li><li><a href="http://www.djangoproject.com/documentation/">http://www.djangoproject.com/documentation/</a></li><li><a href="http://www.djangosnippets.org/">http://www.djangosnippets.org/</a></li><li><a href="http://groups.google.com/group/django-users">http://groups.google.com/group/django-users</a></li></ul>Have a nice day.Archatashttp://www.blogger.com/profile/18444891139539061590noreply@blogger.com