<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>Los Techies</title><link>http://www.lostechies.com/blogs/</link><description>LosTechies.com was originally discussed a few years ago, over a couple of adult beverages whose name sounds very similar to l(D)os t(E)quies. Anyway the thought was to create a public forum where technical ideas and thoughts can be shared in the same way we all get together around a good meal and drinks. Ideas and thoughts are cultivated in discussion, and brought to fruition through professional debate and laughter. Sounds good in theory, well read our thoughts and ideas, take part in our debates and rejoice in our laughter.</description><dc:language>en-US</dc:language><generator>CommunityServer 2008.5 (Build: 30929.2835)</generator><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/LosTechies" type="application/rss+xml" /><item><title>Refactoring challenge Part 2 – Preparation</title><link>http://feedproxy.google.com/~r/LosTechies/~3/reCcDfLD9vk/refactoring-challenge-part-2-preparation.aspx</link><pubDate>Thu, 09 Jul 2009 02:22:00 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22740</guid><dc:creator>bogardj</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;Other posts in this series:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/07/06/refactoring-challenge.aspx"&gt;Refactoring challenge – cry for help&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/07/07/refactoring-challenge-part-1-examination.aspx"&gt;Part 1 – Examination&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;In the last part of this series, I took a closer look at the code smells found by commenters, which included:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;No tests&lt;/li&gt;    &lt;li&gt;Feature envy&lt;/li&gt;    &lt;li&gt;Conditional complexity&lt;/li&gt;    &lt;li&gt;Long method&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;All of these code smells can be found in the two main refactoring books out there, Fowler’s &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0201485672"&gt;Refactoring&lt;/a&gt; and Kerievsky’s &lt;a href="http://www.informit.com/store/product.aspx?isbn=0321213351"&gt;Refactoring to Patterns&lt;/a&gt;.&amp;#160; A while back, I created a handy &lt;a href="http://s3.amazonaws.com/grabbagoftimg/Smells%20to%20Refactorings.pdf"&gt;smells-to-refactorings quick reference guide&lt;/a&gt; for those sticky situations where I don’t have the books handy.&amp;#160; But before I address any of the code smells, I need to prepare for the refactorings.&amp;#160; The main refactorings I’m looking at are ones to move towards the Strategy and Chain of Responsibility patterns, but these only really become apparent when the code at hand is rather uniform.&lt;/p&gt;  &lt;p&gt;To fix this problem, I first need to flatten out all of those if statements in the original code.&amp;#160; The code after flattening all the if statements out now looks like this:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public object &lt;/span&gt;Map(&lt;span style="color:#2b91af;"&gt;ResolutionContext &lt;/span&gt;context, &lt;span style="color:#2b91af;"&gt;IMappingEngineRunner &lt;/span&gt;mapper)
{
    &lt;span style="color:blue;"&gt;object &lt;/span&gt;mappedObject = &lt;span style="color:blue;"&gt;null&lt;/span&gt;;
    &lt;span style="color:blue;"&gt;var &lt;/span&gt;profileConfiguration = mapper.ConfigurationProvider.GetProfileConfiguration(context.TypeMap.Profile);

    &lt;span style="color:blue;"&gt;if &lt;/span&gt;(context.TypeMap.CustomMapper != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)
    {
        context.TypeMap.BeforeMap(context.SourceValue, mappedObject);
        mappedObject = context.TypeMap.CustomMapper(context);
    }
    &lt;span style="color:blue;"&gt;else if &lt;/span&gt;((context.SourceValue == &lt;span style="color:blue;"&gt;null &lt;/span&gt;&amp;amp;&amp;amp; profileConfiguration.MapNullSourceValuesAsNull))
    {
        mappedObject = &lt;span style="color:blue;"&gt;null&lt;/span&gt;;
    }
    &lt;span style="color:blue;"&gt;else if &lt;/span&gt;(context.DestinationValue == &lt;span style="color:blue;"&gt;null &lt;/span&gt;&amp;amp;&amp;amp; context.InstanceCache.ContainsKey(context))
    {
        mappedObject = context.InstanceCache[context];
    }
    &lt;span style="color:blue;"&gt;else if &lt;/span&gt;(context.DestinationValue == &lt;span style="color:blue;"&gt;null&lt;/span&gt;)
    {
        mappedObject = mapper.CreateObject(context.DestinationType);
        &lt;span style="color:blue;"&gt;if &lt;/span&gt;(context.SourceValue != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)
            context.InstanceCache.Add(context, mappedObject);

        context.TypeMap.BeforeMap(context.SourceValue, mappedObject);
        &lt;span style="color:blue;"&gt;foreach &lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;PropertyMap &lt;/span&gt;propertyMap &lt;span style="color:blue;"&gt;in &lt;/span&gt;context.TypeMap.GetPropertyMaps())
        {
            MapPropertyValue(context, mapper, mappedObject, propertyMap);
        }
    }
    &lt;span style="color:blue;"&gt;else
    &lt;/span&gt;{
        mappedObject = context.DestinationValue;

        context.TypeMap.BeforeMap(context.SourceValue, mappedObject);
        &lt;span style="color:blue;"&gt;foreach &lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;PropertyMap &lt;/span&gt;propertyMap &lt;span style="color:blue;"&gt;in &lt;/span&gt;context.TypeMap.GetPropertyMaps())
        {
            MapPropertyValue(context, mapper, mappedObject, propertyMap);
        }
    }


    context.TypeMap.AfterMap(context.SourceValue, mappedObject);
    &lt;span style="color:blue;"&gt;return &lt;/span&gt;mappedObject;
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;By flattening my conditional statements, I can now much more easily apply other refactorings.&amp;#160; But in the process, I wound up creating more duplication, so we need to amend our code smell list.&amp;#160; With our updated list, here’s the planned refactorings:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Feature envy – Extract/Move method&lt;/li&gt;

  &lt;li&gt;Conditional complexity – Replace conditional logic with strategy/chain of responsibility&lt;/li&gt;

  &lt;li&gt;Long method – Same as above&lt;/li&gt;

  &lt;li&gt;Duplicated code – Form template method&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It turns out at one point I had to do the exact same refactorings on another large piece in AutoMapper, one that chose different mapping algorithms to use (type maps, direct assignment, arrays, dictionaries, lists, etc.).&amp;#160; In the next post, I’ll fix the feature envy code smell.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22740" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/18517EF2320F2AEC851F4194107136A63CEEF33F"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/18517EF2320F2AEC851F4194107136A63CEEF33F"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=reCcDfLD9vk:YI72b8_ORbY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=reCcDfLD9vk:YI72b8_ORbY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=reCcDfLD9vk:YI72b8_ORbY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=reCcDfLD9vk:YI72b8_ORbY:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/reCcDfLD9vk" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/jimmy_bogard/archive/tags/Refactoring/default.aspx">Refactoring</category><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/07/08/refactoring-challenge-part-2-preparation.aspx</feedburner:origLink></item><item><title>Refactoring challenge Part 1 - Examination</title><link>http://feedproxy.google.com/~r/LosTechies/~3/jeEirO_AjmM/refactoring-challenge-part-1-examination.aspx</link><pubDate>Wed, 08 Jul 2009 02:51:45 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22738</guid><dc:creator>bogardj</dc:creator><slash:comments>8</slash:comments><description>&lt;p&gt;Most of the time I post code on my blog, it’s something I’m proud of.&amp;#160; Other times, it’s code I didn’t write, which I promptly lambaste.&amp;#160; In my &lt;a href="http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/07/06/refactoring-challenge.aspx"&gt;last post&lt;/a&gt;, I threw up code I did write, but couldn’t see the design coming out.&amp;#160; From the responses, I think I have some direction.&amp;#160; But first, let’s take a closer look at the design issues with the original code, and try to catalog the code smells.&amp;#160; This should give us direction on how we need to refactor it.&amp;#160; Here’s the original code:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public object &lt;/span&gt;Map(ResolutionContext context, IMappingEngineRunner mapper)
{
    &lt;span style="color:blue;"&gt;object &lt;/span&gt;mappedObject = &lt;span style="color:blue;"&gt;null&lt;/span&gt;;
    &lt;span style="color:blue;"&gt;var &lt;/span&gt;profileConfiguration = mapper.ConfigurationProvider.GetProfileConfiguration(context.TypeMap.Profile);

    &lt;span style="color:blue;"&gt;if &lt;/span&gt;(context.TypeMap.CustomMapper != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)
    {
        context.TypeMap.BeforeMap(context.SourceValue, mappedObject);
        mappedObject = context.TypeMap.CustomMapper(context);
    }
    &lt;span style="color:blue;"&gt;else if &lt;/span&gt;(context.SourceValue != &lt;span style="color:blue;"&gt;null &lt;/span&gt;|| !profileConfiguration.MapNullSourceValuesAsNull)
    {
        &lt;span style="color:blue;"&gt;if &lt;/span&gt;(context.DestinationValue == &lt;span style="color:blue;"&gt;null &lt;/span&gt;&amp;amp;&amp;amp; context.InstanceCache.ContainsKey(context))
        {
            mappedObject = context.InstanceCache[context];
        }
        &lt;span style="color:blue;"&gt;else
        &lt;/span&gt;{
            &lt;span style="color:blue;"&gt;if &lt;/span&gt;(context.DestinationValue == &lt;span style="color:blue;"&gt;null&lt;/span&gt;)
            {
                mappedObject = mapper.CreateObject(context.DestinationType);
                &lt;span style="color:blue;"&gt;if &lt;/span&gt;(context.SourceValue != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)
                    context.InstanceCache.Add(context, mappedObject);
            }
            &lt;span style="color:blue;"&gt;else
            &lt;/span&gt;{
                mappedObject = context.DestinationValue;
            }

            context.TypeMap.BeforeMap(context.SourceValue, mappedObject);
            &lt;span style="color:blue;"&gt;foreach &lt;/span&gt;(PropertyMap propertyMap &lt;span style="color:blue;"&gt;in &lt;/span&gt;context.TypeMap.GetPropertyMaps())
            {
                MapPropertyValue(context, mapper, mappedObject, propertyMap);
            }
        }

    }

    context.TypeMap.AfterMap(context.SourceValue, mappedObject);
    &lt;span style="color:blue;"&gt;return &lt;/span&gt;mappedObject;
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;So let’s list out the code smells, there are quite a few.&lt;/p&gt;

&lt;h4&gt;No tests&lt;/h4&gt;

&lt;p&gt;I forgot to post the tests, but even more telling, I only really have large-grained, scenario based tests that cover this class.&amp;#160; No unit tests, and that problem starts to show here, as tests would have surfaced the code smells earlier.&lt;/p&gt;

&lt;h4&gt;Feature Envy&lt;/h4&gt;

&lt;p&gt;There’s lots of poking around the ResolutionContext object (which is responsible for holding all information pertaining to a mapping operation).&amp;#160; For example, the first nested “if” asks the ResolutionContext a lot of things that don’t seem to make any sense by themselves.&amp;#160; Additionally, it’s not clear at all what each conditional has to do with the work being done.&lt;/p&gt;

&lt;h4&gt;&lt;/h4&gt;

&lt;h4&gt;Long Method&lt;/h4&gt;

&lt;p&gt;This should be quite obvious.&amp;#160; For me, the ideal maximum method length is about 10 lines.&amp;#160; That’s pretty much the limit of my understanding of what’s going on.&amp;#160; Any more than that, and I have to put too much context into my head.&lt;/p&gt;

&lt;h4&gt;Conditional Complexity&lt;/h4&gt;

&lt;p&gt;Way too much branching going on here, and even worse, it looks like arrowhead programming.&amp;#160; Flip it sideways, it looks like a mountain range with all the indention.&amp;#160; The cyclomatic complexity is off the charts here, and a tool like NDepend would let me know right away where my maintenance problems will be.&lt;/p&gt;

&lt;p&gt;Those are a lot of code smells, but each one has their corresponding refactoring to take care of it.&amp;#160; In retrospect, I’m not sure why I just didn’t look for code smells in the first place.&amp;#160; In the next few posts, I’ll apply refactorings one by one to get to my destination – clean code.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22738" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/0523F0D9E2BCD6F8875D8FFA150A846385A72C99"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/0523F0D9E2BCD6F8875D8FFA150A846385A72C99"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=jeEirO_AjmM:0RYjDAcMk5A:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=jeEirO_AjmM:0RYjDAcMk5A:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=jeEirO_AjmM:0RYjDAcMk5A:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=jeEirO_AjmM:0RYjDAcMk5A:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/jeEirO_AjmM" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/jimmy_bogard/archive/tags/Refactoring/default.aspx">Refactoring</category><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/07/07/refactoring-challenge-part-1-examination.aspx</feedburner:origLink></item><item><title>VAN: Castle Monorail, Active Record and Brail talk at Wednesday 8PM CST (-5 GMT), by yours truly.</title><link>http://feedproxy.google.com/~r/LosTechies/~3/WpSnSPWeSAU/van-castle-monorail-active-record-and-brail-talk-at-wednesday-8pm-cst-5-gmt-by-yours-truly.aspx</link><pubDate>Tue, 07 Jul 2009 12:00:00 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22699</guid><dc:creator>Ryan Svihla</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;Last week I did a talk on Windsor and it went..ok. I’m not used to online presentations and am more experienced in front of crowds that I can interact with.&lt;/p&gt;  &lt;p&gt;So between last week’s experience and some advice from &lt;a href="http://www.lostechies.com/blogs/joe_ocampo/" target="_blank"&gt;Agile Joe&lt;/a&gt; this talk I’ll be aiming for more of a screen cast feel.&amp;#160; The talk should go for close to an hour and will be open for questions afterword.&lt;/p&gt;  &lt;p&gt;Outline is as follows (subject to change):&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Monorail&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;Controllers&lt;/li&gt;      &lt;li&gt;Windsor integration&lt;/li&gt;      &lt;li&gt;Grouping controllers (“Area’s”)&lt;/li&gt;      &lt;li&gt;Aspect Oriented Programming through Filters&lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;Brail View Engine&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;Conditionals and Iterators&lt;/li&gt;      &lt;li&gt;Parent/Child Views&lt;/li&gt;      &lt;li&gt;Sub Views&lt;/li&gt;      &lt;li&gt;Rescues&lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;Active Record&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;Architecture overview&lt;/li&gt;      &lt;li&gt;Using multiple databases&lt;/li&gt;      &lt;li&gt;Using Active Record in a more DDD friendly way&lt;/li&gt;      &lt;li&gt;Introduction to writing queries in HQL&lt;/li&gt;      &lt;li&gt;Working with the underlying ISession.&lt;/li&gt;   &lt;/ul&gt; &lt;/ul&gt;  &lt;p&gt;If any of you have the time drop by for some/all of this and give me some feedback please do so.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22699" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/D5697C6CAD9DAC935AE3AA5E94003AAB1492AFE1"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/D5697C6CAD9DAC935AE3AA5E94003AAB1492AFE1"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=WpSnSPWeSAU:MSpeZbO1TQQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=WpSnSPWeSAU:MSpeZbO1TQQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=WpSnSPWeSAU:MSpeZbO1TQQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=WpSnSPWeSAU:MSpeZbO1TQQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/WpSnSPWeSAU" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Castle/default.aspx">Castle</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/VAN/default.aspx">VAN</category><feedburner:origLink>http://www.lostechies.com/blogs/rssvihla/archive/2009/07/07/van-castle-monorail-active-record-and-brail-talk-at-wednesday-8pm-cst-5-gmt-by-yours-truly.aspx</feedburner:origLink></item><item><title>Refactoring challenge</title><link>http://feedproxy.google.com/~r/LosTechies/~3/uwPp2gXGaNI/refactoring-challenge.aspx</link><pubDate>Tue, 07 Jul 2009 02:42:47 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22696</guid><dc:creator>bogardj</dc:creator><slash:comments>23</slash:comments><description>&lt;p&gt;I don’t like messy, obfuscated code.&amp;#160; But &lt;strike&gt;occasionally&lt;/strike&gt; often, I write it anyway as I can’t quite see the right way to go.&amp;#160; Today is one of those days where I can’t seem to get past some ugly code, none of my normal tricks seem to work.&amp;#160; Instead of me doing any more work on it, I’m curious if anyone else has any ideas.&amp;#160; Here’s the offending function, in the TypeMapMapper class from the trunk (R97) of the &lt;a href="http://code.google.com/p/automapperhome/"&gt;AutoMapper codebase&lt;/a&gt;:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public object &lt;/span&gt;Map(&lt;span style="color:#2b91af;"&gt;ResolutionContext &lt;/span&gt;context, &lt;span style="color:#2b91af;"&gt;IMappingEngineRunner &lt;/span&gt;mapper)
{
    &lt;span style="color:blue;"&gt;object &lt;/span&gt;mappedObject = &lt;span style="color:blue;"&gt;null&lt;/span&gt;;
    &lt;span style="color:blue;"&gt;var &lt;/span&gt;profileConfiguration = mapper.ConfigurationProvider.GetProfileConfiguration(context.TypeMap.Profile);

    &lt;span style="color:blue;"&gt;if &lt;/span&gt;(context.TypeMap.CustomMapper != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)
    {
        context.TypeMap.BeforeMap(context.SourceValue, mappedObject);
        mappedObject = context.TypeMap.CustomMapper(context);
    }
    &lt;span style="color:blue;"&gt;else if &lt;/span&gt;(context.SourceValue != &lt;span style="color:blue;"&gt;null &lt;/span&gt;|| !profileConfiguration.MapNullSourceValuesAsNull)
    {
        &lt;span style="color:blue;"&gt;if &lt;/span&gt;(context.DestinationValue == &lt;span style="color:blue;"&gt;null &lt;/span&gt;&amp;amp;&amp;amp; context.InstanceCache.ContainsKey(context))
        {
            mappedObject = context.InstanceCache[context];
        }
        &lt;span style="color:blue;"&gt;else
        &lt;/span&gt;{
            &lt;span style="color:blue;"&gt;if &lt;/span&gt;(context.DestinationValue == &lt;span style="color:blue;"&gt;null&lt;/span&gt;)
            {
                mappedObject = mapper.CreateObject(context.DestinationType);
                &lt;span style="color:blue;"&gt;if &lt;/span&gt;(context.SourceValue != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)
                    context.InstanceCache.Add(context, mappedObject);
            }
            &lt;span style="color:blue;"&gt;else
            &lt;/span&gt;{
                mappedObject = context.DestinationValue;
            }

            context.TypeMap.BeforeMap(context.SourceValue, mappedObject);
            &lt;span style="color:blue;"&gt;foreach &lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;PropertyMap &lt;/span&gt;propertyMap &lt;span style="color:blue;"&gt;in &lt;/span&gt;context.TypeMap.GetPropertyMaps())
            {
                MapPropertyValue(context, mapper, mappedObject, propertyMap);
            }
        }

    }

    context.TypeMap.AfterMap(context.SourceValue, mappedObject);
    &lt;span style="color:blue;"&gt;return &lt;/span&gt;mappedObject;
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Yes, it’s very, very long. Originally, there were four different exit points all over the place, but that made it difficult to do other things I needed (the BeforeMap and AfterMap calls).&amp;#160; There’s just way too much going on here, so I’m curious if anyone out there in the æther has any other ideas.&amp;#160; Feel free to post ideas here, or for those adventurous folks, submit a patch on the &lt;a href="http://groups.google.com/group/automapper-users"&gt;AutoMapper group&lt;/a&gt;.&amp;#160; Frankly, it’s making me cross-eyed, so I’ll just turn away in shame.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22696" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/F98FEC204C48EF0D51F9DF24D53BC3BAD439AE7B"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/F98FEC204C48EF0D51F9DF24D53BC3BAD439AE7B"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=uwPp2gXGaNI:xK7FQTs4-dU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=uwPp2gXGaNI:xK7FQTs4-dU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=uwPp2gXGaNI:xK7FQTs4-dU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=uwPp2gXGaNI:xK7FQTs4-dU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/uwPp2gXGaNI" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/jimmy_bogard/archive/tags/Refactoring/default.aspx">Refactoring</category><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/07/06/refactoring-challenge.aspx</feedburner:origLink></item><item><title>Python Web Framework Series – Pylons Part 7: Refactoring, Deployment And Wrap-Up</title><link>http://feedproxy.google.com/~r/LosTechies/~3/6E9tFHXzi3I/python-web-series-pylons-part-7-refactoring-deployment-and-wrap-up.aspx</link><pubDate>Sat, 04 Jul 2009 12:00:00 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22631</guid><dc:creator>Ryan Svihla</dc:creator><slash:comments>7</slash:comments><description>&lt;p&gt;Lets take a look at our existing site and what we can do to clean it up and add some badly needed functionality, however that is beyond the scope of my series. So I&amp;rsquo;m going to leave some hints for the remaining functionality to get you started.&lt;/p&gt;
&lt;h3&gt;Refactoring Ideas&lt;/h3&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Replace default authkit login with custom login. HINT: make a sign-in link on your public page. then redirect to a custom login page that uses authkit. Trying it any other way will make you lose hair.&lt;/li&gt;
&lt;li&gt;Refactor database access into a class or two. This will make the db access more testable and allow you to monkey patch in different behavior later. HINT: If your controllers can avoid having to know anything about SQLAlchemy you&amp;rsquo;ve done your job.&lt;/li&gt;
&lt;li&gt;Replace return &amp;ldquo;rsvihla&amp;rdquo; in the users.py module with actual authkit user. HINT: just access pylons request object: &amp;ldquo;request.environ.get(&amp;quot;REMOTE_USER&amp;quot;)&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Create admin ui for users, with roles. HINT: look at &lt;a target="_blank" href="http://pylonsbook.com/en/1.0/simplesite-tutorial-part-3.html"&gt;Pylons Book&lt;/a&gt; for Authkit ideas here.&lt;/li&gt;
&lt;li&gt;Split threads into categories and then give the ability to respond to posts. HINT: just more controllers and views.&lt;/li&gt;
&lt;li&gt;Makes parts of your view visible depending on if a user has certain rights or not. HINT: while this is not what you&amp;rsquo;ll find in the Pylons Book I highly suggest not have gobs of if/else checks in your views. Make small functions that you can unit test easily which will change what is visible depending on role, then have your views call these. See what I did with my user.py module for a concept.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Deployment&lt;/h3&gt;
&lt;p&gt;This almost completely depends on your situation with hosting. If you are using something like &lt;a target="_blank" href="http://www.webfaction.com/"&gt;WebFaction&lt;/a&gt; you just have to upload files and follow their directions. I found it trivial to have a production site up and running with them. &lt;/p&gt;
&lt;p&gt;Now if you are using your own dedicated server or want to shrink wrap the project I suggest using Python Eggs, this is not pylons specific at all and I&amp;rsquo;ve built them for a number of other projects. There are some snags you can run into depend on your platform and how portable you want to make this but as long as your dev platform and production platform are the same all you need is &amp;ldquo;python setup.py bdist_egg&amp;rdquo; and you should have a egg file in the dist directory which can be installed with easy_install.&lt;/p&gt;
&lt;p&gt;Finally, you&amp;rsquo;ll want to build a production.ini . By and large you can copy your development.ini but you must must make your debug = false or you&amp;rsquo;ll give people access to your application in all sorts of bad ways.&amp;nbsp; Also, don&amp;rsquo;t forget to make your secret strings actually secret strings. &lt;/p&gt;
&lt;h3&gt;Overall Impressions&lt;/h3&gt;
&lt;p&gt;Things I like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pretty easy to get up and running quickly.&lt;/li&gt;
&lt;li&gt;paster and nose integration is pretty slick.&lt;/li&gt;
&lt;li&gt;being able to functional test response including view is actually nice.&amp;nbsp; Really wish I had this in Monorail as easily.&lt;/li&gt;
&lt;li&gt;Component based to the hilt. If you really don&amp;rsquo;t like something you can switch it out. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Things I don&amp;#39;t like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AuthKit is like all auth frameworks I&amp;rsquo;ve used, just a lot to make work the way I want.&lt;/li&gt;
&lt;li&gt;Too much violation of dry in the config. AuthKit being the main culprit here, while I may want to change which datasource I use, I&amp;rsquo;m not sure how helpful it is to have to select &amp;ldquo;form, cookie&amp;rdquo; for each ini file I make.&lt;/li&gt;
&lt;li&gt;Explicitly calling the view in my actions. Should have some convention over configuration here.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So I could certainly see using Pylons more once I get my own auth solution worked out, and get my own code flow working I could actually probably get work done more quickly in it than most web frameworks I&amp;rsquo;ve learned.&amp;nbsp; The majority of the time I wasted learning was dealing with authkit, in fact that took more time than everything else I studied combined.&lt;/p&gt;
&lt;p&gt;Thank you for taking the time to get this far with my posts. If you have any specifics parts you want me to dive into more depth and/or suggestions for me on the next series (which will be Pyxer with Google App Engine) let me know.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22631" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/A2BF389E31EAFC78F9FF9F733E543F1A94A1CA6C"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/A2BF389E31EAFC78F9FF9F733E543F1A94A1CA6C"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=6E9tFHXzi3I:F-C4VfBjVJA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=6E9tFHXzi3I:F-C4VfBjVJA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=6E9tFHXzi3I:F-C4VfBjVJA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=6E9tFHXzi3I:F-C4VfBjVJA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/6E9tFHXzi3I" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Python/default.aspx">Python</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Pylons/default.aspx">Pylons</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Authkit/default.aspx">Authkit</category><feedburner:origLink>http://www.lostechies.com/blogs/rssvihla/archive/2009/07/04/python-web-series-pylons-part-7-refactoring-deployment-and-wrap-up.aspx</feedburner:origLink></item><item><title>Theory Of Constraints: Productivity Metrics in Software Development</title><link>http://feedproxy.google.com/~r/LosTechies/~3/SOQ2gmRBZmE/theory-of-constraints-productivity-metrics-in-software-development.aspx</link><pubDate>Fri, 03 Jul 2009 17:38:16 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22619</guid><dc:creator>derick.bailey</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;In the past, I’ve been a true believer that software development is not really possible to measure from a productivity perspective. I was ignorant, basically. I’m now a bit wiser and I understand that software development is no different than any other product development process. We can and should measure productivity of software developers by understanding that we are building business value via functionality that the end-user wants. So, we should essentially be measuring our progress toward the end user facing functionality (as an over-simplification). &lt;/p&gt;  &lt;h3&gt;A Paper On The Theory Of Constraints&lt;/h3&gt;  &lt;p&gt;Several months ago, I wrote up a paper for an internal company effort to help define productivity metrics for software developers. This paper is largely based on the work of &lt;a href="http://agilemanagement.net/"&gt;David J. Anderson&lt;/a&gt;, in “&lt;a href="http://www.amazon.com/Agile-Management-Software-Engineering-Constraints/dp/0131424602"&gt;Agile Management For Software Engineering&lt;/a&gt;”. It also includes some of my own interpretations and understandings of the Theory of Constraints. &lt;/p&gt;  &lt;p&gt;The original intent of this paper was to facilitate the discussion of productivity and metrics in the Development Department at McLane Advanced Technologies, LLC., where I work. I decided to release it to the world, to hopefully help others understand how we can measure productivity as software developers. I did not intend this to be a comprehensive or exhaustive discussion of the points within, but am trying to spur additional research and conversations. I hope you enjoy reading it as much as I enjoyed writing it.&lt;/p&gt;  &lt;h3&gt;Download The Paper&lt;/h3&gt;  &lt;p&gt;You can download the PDF here: &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;a href="http://www.lostechies.com/media/p/22618.aspx"&gt;&lt;strong&gt;The Theory of Constraints: Productivity Metrics In Software Development&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22619" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/8B2C706DA0F7DF19BD4D8F10D4F468DE78F2BB91"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/8B2C706DA0F7DF19BD4D8F10D4F468DE78F2BB91"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=SOQ2gmRBZmE:opU10jJsLM0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=SOQ2gmRBZmE:opU10jJsLM0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=SOQ2gmRBZmE:opU10jJsLM0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=SOQ2gmRBZmE:opU10jJsLM0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/SOQ2gmRBZmE" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/derickbailey/archive/tags/Throughput/default.aspx">Throughput</category><category domain="http://www.lostechies.com/blogs/derickbailey/archive/tags/E-Books/default.aspx">E-Books</category><category domain="http://www.lostechies.com/blogs/derickbailey/archive/tags/Theory+Of+Constraints/default.aspx">Theory Of Constraints</category><category domain="http://www.lostechies.com/blogs/derickbailey/archive/tags/Productivity/default.aspx">Productivity</category><category domain="http://www.lostechies.com/blogs/derickbailey/archive/tags/Metrics/default.aspx">Metrics</category><feedburner:origLink>http://www.lostechies.com/blogs/derickbailey/archive/2009/07/03/theory-of-constraints-productivity-metrics-in-software-development.aspx</feedburner:origLink></item><item><title>How not to do Dependency Injection, in NerdDinner</title><link>http://feedproxy.google.com/~r/LosTechies/~3/2BwwdFMz5n8/how-not-to-do-dependency-injection-in-nerddinner.aspx</link><pubDate>Fri, 03 Jul 2009 16:19:29 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22612</guid><dc:creator>bogardj</dc:creator><slash:comments>49</slash:comments><description>&lt;p&gt;Checking out the &lt;a href="http://nerddinner.codeplex.com/"&gt;NerdDinner&lt;/a&gt; code the other day, I found a common Dependency Injection anti-pattern.&amp;#160; One of the core concepts of DI is that components are not responsible for locating their own dependencies.&amp;#160; The code went part of the way to full-on DI, but not quite far enough.&amp;#160; Here’s the offending code:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;SearchController &lt;/span&gt;: &lt;span style="color:#2b91af;"&gt;Controller &lt;/span&gt;{

&lt;span style="color:#2b91af;"&gt;IDinnerRepository &lt;/span&gt;dinnerRepository;

&lt;span style="color:green;"&gt;//
// Dependency Injection enabled constructors

&lt;/span&gt;&lt;span style="color:blue;"&gt;public &lt;/span&gt;SearchController()
    : &lt;span style="color:blue;"&gt;this&lt;/span&gt;(&lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;DinnerRepository&lt;/span&gt;()) {
}

&lt;span style="color:blue;"&gt;public &lt;/span&gt;SearchController(&lt;span style="color:#2b91af;"&gt;IDinnerRepository &lt;/span&gt;repository) {
    dinnerRepository = repository;
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;The second constructor is correct – the SearchController’s dependencies are passed in through the constructor.&amp;#160; This is because the IDinnerRepository is a required, or primal dependency.&amp;#160; SearchController depends on IDinnerRepository to function properly, and won’t work without it.&amp;#160; But on the first constructor, we violate DI by having the SearchController create a concrete DinnerRepository!&amp;#160; We’re now back to concrete, opaque dependencies.&amp;#160; We have a small benefit of easier testability, but we still force our controller to locate its own dependencies.&lt;/p&gt;

&lt;p&gt;So why is this a Bad Thing?&lt;/p&gt;

&lt;p&gt;For one, it’s confusing to have two constructors.&amp;#160; Why go through all the trouble of creating the IDinnerRepository interface if I’m just going to depend directly on an implementer?&amp;#160; Now what if DinnerRepository now needs some dependency?&amp;#160; What if it now needs some ILogger, security or policy dependency?&amp;#160; Do I now need to go fix all of my calls to “new”?&lt;/p&gt;

&lt;p&gt;And that’s the whole point of Dependency Injection, and the Dependency Inversion Principle.&amp;#160; I only know about my first level dependencies, and abstractions on top of that.&amp;#160; If we check out DinnerRepository, we see another issue:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;DinnerRepository &lt;/span&gt;: NerdDinner.Models.&lt;span style="color:#2b91af;"&gt;IDinnerRepository &lt;/span&gt;{

    &lt;span style="color:#2b91af;"&gt;NerdDinnerDataContext &lt;/span&gt;db = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NerdDinnerDataContext&lt;/span&gt;();&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;A private, opaque dependency to NerdDinnerDataContext.&amp;#160; If we wanted to make that opaque dependency explicit, we’d have to fix our SearchController (and all the other controllers as well).&amp;#160; It’s these kinds of ripple effects that prevent refactoring and improvement.&lt;/p&gt;

&lt;h3&gt;&lt;/h3&gt;

&lt;h3&gt;Fixing it&lt;/h3&gt;

&lt;p&gt;But we can fix this, quite easily.&amp;#160; From &lt;a href="http://www.codeplex.com/MVCContrib"&gt;MvcContrib&lt;/a&gt;, we can grab any one of the ControllerFactory implementations for the IoC container of our choice.&amp;#160; For me, that’s &lt;a href="http://structuremap.sourceforge.net/Default.htm"&gt;StructureMap&lt;/a&gt;.&amp;#160; First, we’ll need to configure StructureMap to wire up all of our dependencies.&amp;#160; The preferred way to do so is to create a Registry:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NerdDinnerRegistry &lt;/span&gt;: &lt;span style="color:#2b91af;"&gt;Registry
&lt;/span&gt;{
    &lt;span style="color:blue;"&gt;public &lt;/span&gt;NerdDinnerRegistry()
    {
        Scan(scanner =&amp;gt;
        {
            scanner.TheCallingAssembly();
            scanner.WithDefaultConventions();
        });

        ForRequestedType&amp;lt;&lt;span style="color:#2b91af;"&gt;NerdDinnerDataContext&lt;/span&gt;&amp;gt;()
            .CacheBy(&lt;span style="color:#2b91af;"&gt;InstanceScope&lt;/span&gt;.HttpContext)
            .TheDefault.Is.ConstructedBy(() =&amp;gt; &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NerdDinnerDataContext&lt;/span&gt;());
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;In the first part, we just tell StructureMap to scan the calling assembly with default conventions.&amp;#160; This will wire up IDinnerRepository to DinnerRepository.&amp;#160; Probably 99% of our dependencies will be taken care of in that one call.&amp;#160; Next, we need to wire up the NerdDinnerDataContext (for reasons we’ll see soon).&amp;#160; Since that class has multiple constructors, StructureMap likes to use the greediest dependency, with the most arguments.&amp;#160; I don’t want that, so I override it to use the no-arg constructor.&amp;#160; Finally, I cache it by HttpContext, though I could probably go Singleton if it’s expensive to instantiate.&lt;/p&gt;

&lt;p&gt;Next, I need a wrapper class to initialize StructureMap:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public static class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IoCContainer
&lt;/span&gt;{
    &lt;span style="color:blue;"&gt;public static void &lt;/span&gt;Configure()
    {
        &lt;span style="color:#2b91af;"&gt;ObjectFactory&lt;/span&gt;.Initialize(init =&amp;gt;
        {
            init.AddRegistry&amp;lt;&lt;span style="color:#2b91af;"&gt;NerdDinnerRegistry&lt;/span&gt;&amp;gt;();
        });
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Initialize only needs to get called once per AppDomain, and all I need to do is add the NerdDinnerRegistry I created earlier.&amp;#160; I &lt;em&gt;could&lt;/em&gt; wire up everything here, but again, the preferred configuration method is through registries.&amp;#160; The next piece is to wire up ASP.NET MVC to both call our configuration method and use the StructureMapControllerFactory:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;void &lt;/span&gt;Application_Start()
{
    RegisterRoutes(&lt;span style="color:#2b91af;"&gt;RouteTable&lt;/span&gt;.Routes);

    &lt;span style="color:#2b91af;"&gt;IoCContainer&lt;/span&gt;.Configure();
    &lt;span style="color:#2b91af;"&gt;ControllerBuilder&lt;/span&gt;.Current.SetControllerFactory(&lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;StructureMapControllerFactory&lt;/span&gt;());

    &lt;span style="color:#2b91af;"&gt;ViewEngines&lt;/span&gt;.Engines.Clear();
    &lt;span style="color:#2b91af;"&gt;ViewEngines&lt;/span&gt;.Engines.Add(&lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;MobileCapableWebFormViewEngine&lt;/span&gt;());
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;I put all this in with the other MVC configuration in the Global.asax Application_Start method.&amp;#160; One final piece is to remove the extra constructors on our controller:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;DinnersController &lt;/span&gt;: &lt;span style="color:#2b91af;"&gt;Controller &lt;/span&gt;{

    &lt;span style="color:#2b91af;"&gt;IDinnerRepository &lt;/span&gt;dinnerRepository;

    &lt;span style="color:green;"&gt;//
    // Dependency Injection enabled constructors

    &lt;/span&gt;&lt;span style="color:blue;"&gt;public &lt;/span&gt;DinnersController(&lt;span style="color:#2b91af;"&gt;IDinnerRepository &lt;/span&gt;repository) {
        dinnerRepository = repository;
    }&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;And make our DinnerRepository expose its dependencies explicitly:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;DinnerRepository &lt;/span&gt;: NerdDinner.Models.&lt;span style="color:#2b91af;"&gt;IDinnerRepository &lt;/span&gt;{
    
    &lt;span style="color:blue;"&gt;private readonly &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NerdDinnerDataContext &lt;/span&gt;db;

    &lt;span style="color:blue;"&gt;public &lt;/span&gt;DinnerRepository(&lt;span style="color:#2b91af;"&gt;NerdDinnerDataContext &lt;/span&gt;db)
    {
        &lt;span style="color:blue;"&gt;this&lt;/span&gt;.db = db;
    }&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Note that there are no no-arg constructors to be found!&amp;#160; When StructureMap creates a DinnersController, it will look to resolve the IDinnerRepository dependency.&amp;#160; That’s a DinnerRepository, which in turn needs the NerdDinnerDataContext.&amp;#160; But that’s all hidden from us, we never need to wire up an entire graph, as we would if we stuck to the “new” operator.&amp;#160; Just to make sure everything works, I can navigate to view upcoming dinners:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/image_5F00_411EA2FB.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/image_5F00_thumb_5F00_34149D1D.png" width="644" height="437" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;&lt;/h2&gt;

&lt;h3&gt;Wrapping it up&lt;/h3&gt;

&lt;p&gt;In the original NerdDinner code, dependency inversion was only partially implemented as the original controllers still contained a constructor that called a constructor of a concrete class.&amp;#160; To fix this, we added StructureMap to the mix, configuring ASP.NET MVC to use StructureMap to create controllers instead of the default controller factory.&amp;#160; Finally, we pushed the dependency inversion principle all the way down to our repository, removing the opaque dependencies where we found them.&amp;#160; When we finished, all of our classes exposed their dependencies explicitly through their constructor.&amp;#160; No one class knew more than one level of depth, and our controllers now properly depended exclusively on the IDinnerRepository abstraction.&lt;/p&gt;

&lt;p&gt;In the future, we can add things like logging, policies and the like to custom IDinnerRepository implementations, without needing to change any of our controllers.&amp;#160; Once we introduce inversion of control to our application, we open a lot of doors for functionality and simplicity, but only going halfway won’t give us the full benefit.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22612" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/E7F33F62DB730384803FF28D64350492B95F120F"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/E7F33F62DB730384803FF28D64350492B95F120F"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=2BwwdFMz5n8:WumYr2j9BYI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=2BwwdFMz5n8:WumYr2j9BYI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=2BwwdFMz5n8:WumYr2j9BYI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=2BwwdFMz5n8:WumYr2j9BYI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/2BwwdFMz5n8" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/jimmy_bogard/archive/tags/Refactoring/default.aspx">Refactoring</category><category domain="http://www.lostechies.com/blogs/jimmy_bogard/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://www.lostechies.com/blogs/jimmy_bogard/archive/tags/StructureMap/default.aspx">StructureMap</category><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/07/03/how-not-to-do-dependency-injection-in-nerddinner.aspx</feedburner:origLink></item><item><title>Python Web Framework Series – Pylons: Part 6 Basic Authorization With AuthKit</title><link>http://feedproxy.google.com/~r/LosTechies/~3/j61An8i9Cxo/python-web-framework-series-pylons-part-6-authentication-and-authorization-with-authkit.aspx</link><pubDate>Fri, 03 Jul 2009 12:00:00 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22599</guid><dc:creator>Ryan Svihla</dc:creator><slash:comments>1</slash:comments><description>Last post we left off with very basic database access, and testing story completed. Now we&amp;#39;re going to look at basic Authorization and Authentication with AuthKit. NOTE: most of this post is just an aggregation of a couple of chapters in the &lt;a href="http://pylonsbook.com/en/1.0/simplesite-tutorial-part-3.html"&gt;Pylons Book&lt;/a&gt; since this setup is a good base starting point. Read the previous link to the Pylons Book for more in depth coverage of this topic.&amp;#160; &lt;h3&gt;Setting Up AuthKit&lt;/h3&gt;  &lt;p&gt;First lets make sure we have AuthKit installed: &lt;em&gt;easy_install AuthKit&lt;/em&gt;. For this post we&amp;#39;re working with AuthKit 0.4.3, your mileage may vary if you read this post in the future and are using a different version. Now that we have Authkit installed open up &lt;strong&gt;pylonsforum\config\middleware.py&lt;/strong&gt; add the following imports: &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;   &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:0e36f3d6-bf71-45bf-bf78-d6c30cc7a027" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;&lt;b&gt;authkit.authenticate&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;&lt;b&gt;authkit.permissions&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;#160;ValidAuthKitUser&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt; &lt;/p&gt;  &lt;p&gt;and then add somewhere inside the &lt;em&gt;if asbool(full_stack):&lt;/em&gt; code block.&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:0b036444-d3da-4656-a78f-7f21d223d9ae" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
permission&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;ValidAuthKitUser()&lt;br /&gt;
app&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;authorize&lt;span style="color:#666666;"&gt;.&lt;/span&gt;middleware(app,&amp;#160;permission)&lt;br /&gt;
app&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;authenticate&lt;span style="color:#666666;"&gt;.&lt;/span&gt;middleware(app,app_conf)&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;in &lt;strong&gt;development.ini&lt;/strong&gt; add this to the end of your&lt;em&gt; [app:main]&lt;/em&gt; section&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:12fd82fc-e581-4566-a046-5f4fbfda3665" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;setup&lt;span style="color:#666666;"&gt;.&lt;/span&gt;enable&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;true&lt;br /&gt;
authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;setup&lt;span style="color:#666666;"&gt;.&lt;/span&gt;method&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;form,&amp;#160;cookie&lt;br /&gt;
authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;form&lt;span style="color:#666666;"&gt;.&lt;/span&gt;authenticate&lt;span style="color:#666666;"&gt;.&lt;/span&gt;user&lt;span style="color:#666666;"&gt;.&lt;/span&gt;type&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;users&lt;span style="color:#666666;"&gt;.&lt;/span&gt;sqlalchemy_driver:UsersFromDatabase&lt;br /&gt;
authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;form&lt;span style="color:#666666;"&gt;.&lt;/span&gt;authenticate&lt;span style="color:#666666;"&gt;.&lt;/span&gt;user&lt;span style="color:#666666;"&gt;.&lt;/span&gt;data&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;pylonsforum&lt;span style="color:#666666;"&gt;.&lt;/span&gt;model&lt;br /&gt;
authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;cookie&lt;span style="color:#666666;"&gt;.&lt;/span&gt;secret&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;secret&amp;#160;string&lt;br /&gt;
authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;cookie&lt;span style="color:#666666;"&gt;.&lt;/span&gt;signoutpath&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#666666;"&gt;/&lt;/span&gt;home&lt;span style="color:#666666;"&gt;/&lt;/span&gt;signout&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;Open your home.py controller and for now add a “signout” action:&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:2cc06811-a8cf-4df3-a509-fe95dd80ef5d" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;signout&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;You&amp;#39;ve&amp;#160;been&amp;#160;signed&amp;#160;out&amp;quot;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;Now in your &lt;strong&gt;websetup.py&lt;/strong&gt; we have a ton to add to get the basic setup working. Start right after imports and add these line.&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:0631806d-df32-4901-9f17-8f78e5a5532c" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;&lt;b&gt;authkit.users.sqlalchemy_driver&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;#160;UsersFromDatabase&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;next add the following in your “setup_app” method after load_environment&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:8cbafdcf-409e-43f0-bb5e-19a168a2f984" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;&lt;b&gt;pylonsforum.model&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;#160;meta&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;metadata&lt;span style="color:#666666;"&gt;.&lt;/span&gt;bind&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;engine&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;filename&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;os&lt;span style="color:#666666;"&gt;.&lt;/span&gt;path&lt;span style="color:#666666;"&gt;.&lt;/span&gt;split(conf&lt;span style="color:#666666;"&gt;.&lt;/span&gt;filename)[&lt;span style="color:#666666;"&gt;-&lt;/span&gt;&lt;span style="color:#666666;"&gt;1&lt;/span&gt;]&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;log&lt;span style="color:#666666;"&gt;.&lt;/span&gt;info(&lt;span style="color:#BA2121;"&gt;&amp;quot;Adding&amp;#160;the&amp;#160;AuthKit&amp;#160;model...&amp;quot;&lt;/span&gt;)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;users&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;UsersFromDatabase(model)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;metadata&lt;span style="color:#666666;"&gt;.&lt;/span&gt;create_all(checkfirst&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;log&lt;span style="color:#666666;"&gt;.&lt;/span&gt;info(&lt;span style="color:#BA2121;"&gt;&amp;quot;Adding&amp;#160;roles&amp;#160;and&amp;#160;uses...&amp;quot;&lt;/span&gt;)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;users&lt;span style="color:#666666;"&gt;.&lt;/span&gt;user_create(&lt;span style="color:#BA2121;"&gt;&amp;quot;admin&amp;quot;&lt;/span&gt;,&amp;#160;password&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#BA2121;"&gt;&amp;quot;admin&amp;quot;&lt;/span&gt;)&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;For the final piece delete your development.db file and run &lt;em&gt;paster setup.app development.ini&lt;/em&gt; to recreate it with the AuthKit user model. Now you have very basic authentication working in your site&lt;/p&gt;  &lt;p&gt;&lt;a href="http://localhost:5000"&gt;http://localhost:5000&lt;/a&gt; reveals:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/Picture2_5F00_21F07175.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="Picture 2" border="0" alt="Picture 2" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/Picture2_5F00_thumb_5F00_343BC8E8.png" width="348" height="296" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;type in “admin” for the username and password and it should let you pass.&amp;#160; Note going back to the site will not bring up a password box again.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://localhost:5000/home/signout"&gt;http://localhost:5000/home/signout&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;will remove your cookie and you’ll see the sign in form once more if you go to &lt;a href="http://localhost:5000"&gt;http://localhost:5000&lt;/a&gt; .&amp;#160; Stayed tuned for more posts as I go more in depth with the different features and customizations of AuthKit.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22599" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/79BBD282566B83AF81745798198C4ABA975F0B06"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/79BBD282566B83AF81745798198C4ABA975F0B06"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=j61An8i9Cxo:cAVv_jnp9kc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=j61An8i9Cxo:cAVv_jnp9kc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=j61An8i9Cxo:cAVv_jnp9kc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=j61An8i9Cxo:cAVv_jnp9kc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/j61An8i9Cxo" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Python/default.aspx">Python</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Pylons/default.aspx">Pylons</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Authkit/default.aspx">Authkit</category><feedburner:origLink>http://www.lostechies.com/blogs/rssvihla/archive/2009/07/03/python-web-framework-series-pylons-part-6-authentication-and-authorization-with-authkit.aspx</feedburner:origLink></item><item><title>Python Web Framework Series – Pylons: Part 5 Testing Models</title><link>http://feedproxy.google.com/~r/LosTechies/~3/UXdlqSLxks8/python-web-framework-series-pylons-part-5-testing-models.aspx</link><pubDate>Thu, 02 Jul 2009 20:09:00 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22596</guid><dc:creator>Ryan Svihla</dc:creator><slash:comments>3</slash:comments><description>&lt;p&gt;UPDATE: was an error caught by Govind (who is turning out to be my unofficial proofreader). I&amp;#39;ve made a correction in the thread mapping for &amp;quot;dateadded&amp;quot; property in the &lt;i&gt;previous&lt;/i&gt; article. If this you are caught up with and &lt;i&gt;error indicating there is no dateadded property on thread&lt;/i&gt; make sure to edit your &lt;b&gt;model\__init__.py&lt;/b&gt; file to match the previous article and rebuild your db so that everything is happy. Please bear with me as I hone my tutorial writing skill set.&lt;/p&gt;
&lt;p&gt;When we last left of with our Pylons forum we had a had just successfully created a post, and then could immediately retrieve that same post. However, we kind of skimped on the testing story so lets fill in the gaps and do some refactoring as a bonus.&lt;/p&gt;
&lt;h3&gt;Functional Testing Models&lt;/h3&gt;
&lt;p&gt;Open your functional controller test located at &lt;b&gt;pylonsforum\tests\functional\test_home.py&lt;/b&gt; and add the following import line&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:ea9eb64a-87d7-44db-b556-7b0ae4bdfdc3" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;pylonsforum.model&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;Thread,&amp;nbsp;Post,&amp;nbsp;meta&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and the following methods&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:477b4d45-bb43-409b-ac13-36373a0c94ba" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;setUp&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;remove()&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;metadata&lt;span style="color:#666666;"&gt;.&lt;/span&gt;create_all(meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;engine)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;_createpost(&lt;span style="color:#666666;"&gt;5&lt;/span&gt;)&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;_createpost&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;,times):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;i&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#666666;"&gt;0&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/span&gt;&amp;nbsp;i&amp;nbsp;&lt;span style="color:#666666;"&gt;&amp;lt;&lt;/span&gt;&amp;nbsp;times:&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;i&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;i&amp;nbsp;&lt;span style="color:#666666;"&gt;+&lt;/span&gt;&lt;span style="color:#666666;"&gt;1&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;thread&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;Thread()&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;subject&amp;nbsp;&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#666666;"&gt;+&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;str&lt;/span&gt;(i)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;post&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;Post()&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;post&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;posting&amp;nbsp;away&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;post&lt;span style="color:#666666;"&gt;.&lt;/span&gt;content&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;post&lt;span style="color:#666666;"&gt;.&lt;/span&gt;isparent&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts&lt;span style="color:#666666;"&gt;.&lt;/span&gt;append(post)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;add(thread)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;commit()&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;and change the test_recent_posts method to&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:5121d806-a714-43ee-8d45-ac625e97f68a" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;test_five_most_recent_threads_show_in_homepage&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;app&lt;span style="color:#666666;"&gt;.&lt;/span&gt;post(url(controller&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;home&amp;quot;&lt;/span&gt;,&amp;nbsp;action&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;index&amp;quot;&lt;/span&gt;))&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;subject&amp;nbsp;1&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#aa22ff;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;nbsp;response&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;subject&amp;nbsp;2&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#aa22ff;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;nbsp;response&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;subject&amp;nbsp;3&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#aa22ff;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;nbsp;response&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;subject&amp;nbsp;4&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#aa22ff;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;nbsp;response&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;subject&amp;nbsp;5&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#aa22ff;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;nbsp;response&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;In summary here we&amp;rsquo;re adding a _createpost factory method that generates some basic test threads and parent posts. running &lt;i&gt;nosetests &amp;ndash;-with-pylons=test.ini &lt;/i&gt;should result in failed tests.&lt;/p&gt;
&lt;h3&gt;Changing The View and Controller&lt;/h3&gt;
&lt;p&gt;Now adjust your &lt;b&gt;index.mako &lt;/b&gt;view to the following:&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:0603f2e8-543b-4335-bec6-bef0da5dd580" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#bc7a00;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;name=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;title()&amp;quot;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;&amp;gt;&lt;/span&gt;Pylons&amp;nbsp;Forum&lt;span style="color:#bc7a00;"&gt;&amp;lt;/%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;name=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;head_tags()&amp;quot;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;&amp;gt;&amp;lt;/%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;div&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;id=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;recentposts&amp;quot;&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;table&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;&lt;/b&gt;&lt;/span&gt;subject&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;&lt;/b&gt;&lt;/span&gt;author&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;&lt;/b&gt;&lt;/span&gt;date&amp;nbsp;submitted&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;tbody&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt;&amp;nbsp;t&amp;nbsp;&lt;span style="color:#aa22ff;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;nbsp;c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;threads:&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;t&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;t&lt;span style="color:#666666;"&gt;.&lt;/span&gt;parentpost&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;t&lt;span style="color:#666666;"&gt;.&lt;/span&gt;dateadded&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="color:#408080;"&gt;&lt;i&gt;&amp;lt;!--&amp;nbsp;changed&amp;nbsp;posts&amp;nbsp;properties&amp;nbsp;to&amp;nbsp;thread&amp;nbsp;properties&amp;nbsp;and&amp;nbsp;added&amp;nbsp;parentpost&amp;nbsp;--&amp;gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;endfor&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/tbody&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/table&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/div&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So once you&amp;rsquo;ve changed the to using a &amp;ldquo;threads&amp;rdquo; object, added parentpost (where did that come from? I&amp;rsquo;ll get to that in minute) and changed our properties around we need to change the our &lt;b&gt;home.py &lt;/b&gt;controller index action for our cosmetic changes and to work with our new tests:&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:ccbbb1ad-b28d-4796-b144-7014f2be59fd" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;index&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;username&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;rsvihla&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#408080;"&gt;&lt;i&gt;#&amp;nbsp;removing&amp;nbsp;this&amp;nbsp;line&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;c.posts&amp;nbsp;=&amp;nbsp;[Post(&amp;quot;jkruse&amp;quot;,&amp;nbsp;&amp;quot;New&amp;nbsp;Kindle&amp;quot;,&amp;nbsp;&amp;quot;06/24/2009&amp;quot;)]&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;thread_query&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;query(model&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Thread)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;threads&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;thread_query&lt;span style="color:#666666;"&gt;.&lt;/span&gt;order_by(model&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;dateadded&lt;span style="color:#666666;"&gt;.&lt;/span&gt;desc())&lt;span style="color:#666666;"&gt;.&lt;/span&gt;limit(&lt;span style="color:#666666;"&gt;5&lt;/span&gt;)&lt;span style="color:#666666;"&gt;.&lt;/span&gt;all()&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;render(&lt;span style="color:#ba2121;"&gt;&amp;#39;index.mako&amp;#39;&lt;/span&gt;)&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So our index action now is querying for the 5 most recent threads and storing in our new c.threads context variable. Lets strip the query down into pieces.&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:1a41659f-81a5-4faa-a6a7-e259e0e7a2f4" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
thread_query&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;query(model&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Thread)&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;we&amp;rsquo;re working with SQLAlchemy Session object. We call a Thread Model and then store a Thread query object inside the thread_query variable.&amp;nbsp; Now through the thread_query variable we can get&amp;nbsp; access to the Thread objects stored in the database.&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:9d73b132-bd56-4889-b0d4-ebc164ad8bcb" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;threads&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;thread_query&lt;span style="color:#666666;"&gt;.&lt;/span&gt;order_by(model&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;dateadded&lt;span style="color:#666666;"&gt;.&lt;/span&gt;desc())&lt;span style="color:#666666;"&gt;.&lt;/span&gt;limit(&lt;span style="color:#666666;"&gt;5&lt;/span&gt;)&lt;span style="color:#666666;"&gt;.&lt;/span&gt;all()&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here we call &amp;ldquo;order_by&amp;rdquo; on our query object and then pass in the Thread model specifying a descending order of the dateadded property. Next we limit it to 5 rows and then call &amp;ldquo;all()&amp;rdquo; which returns our results in a nice python &amp;ldquo;list&amp;rdquo; object.&lt;/p&gt;
&lt;h3&gt;Custom Properties on the Model&lt;/h3&gt;
&lt;p&gt;Ok so back a few paragraphs ago in the &lt;b&gt;index.mako&lt;/b&gt; view I stuck in a &amp;ldquo;parentpost&amp;rdquo; property on the thread, and I&amp;rsquo;m quite certain you&amp;rsquo;re wondering how I did that. So I&amp;rsquo;ve created the following class &lt;b&gt;tests\test_model.py&lt;/b&gt;&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:f56c8f6c-a468-4b9b-a58d-b4b3acdaabf3" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;pylonsforum.model&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;Thread,&amp;nbsp;Post,&amp;nbsp;meta&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;pylonsforum.tests&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#666666;"&gt;*&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;TestThreadParent&lt;/b&gt;&lt;/span&gt;(TestController):&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;_makethread&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;,&amp;nbsp;hasparent):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;thread&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;Thread()&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;test&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parentpost&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;Post()&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parentpost&lt;span style="color:#666666;"&gt;.&lt;/span&gt;content&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parentpost&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;first&amp;nbsp;post&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parentpost&lt;span style="color:#666666;"&gt;.&lt;/span&gt;isparent&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;hasparent&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;childpost&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;Post()&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;childpost&lt;span style="color:#666666;"&gt;.&lt;/span&gt;content&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;childpost&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;childpost&lt;span style="color:#666666;"&gt;.&lt;/span&gt;isparent&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;False&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts&lt;span style="color:#666666;"&gt;.&lt;/span&gt;append(childpost)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts&lt;span style="color:#666666;"&gt;.&lt;/span&gt;append(parentpost)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;thread&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;test_should_find_parent_post&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;thread&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;_makethread(&lt;span style="color:#008000;"&gt;True&lt;/span&gt;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;nbsp;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;parentpost&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author&amp;nbsp;&lt;span style="color:#666666;"&gt;==&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;first&amp;nbsp;post&amp;quot;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;test_should_not_find_parent_when_none_set&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;thread&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;_makethread(&lt;span style="color:#008000;"&gt;False&lt;/span&gt;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;nbsp;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;parentpost&amp;nbsp;&lt;span style="color:#aa22ff;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;None&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Our test has a _makethread factory method (another one of those maybe time for a factory class soon!) which can make a parent post or not depending on its parameter, then two tests documenting its behavior in each situation.&lt;/p&gt;
&lt;p&gt;So I&amp;rsquo;ve gone back to our &lt;b&gt;models\__init__.py&lt;/b&gt; class and changed the Thread class to look like this:&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:2c459365-15ee-44a0-965f-34e631b61cdd" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;Thread&lt;/b&gt;&lt;/span&gt;(&lt;span style="color:#008000;"&gt;object&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#aa22ff;"&gt;@property&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;parentpost&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt;&amp;nbsp;p&amp;nbsp;&lt;span style="color:#aa22ff;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts:&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt;&amp;nbsp;p&lt;span style="color:#666666;"&gt;.&lt;/span&gt;isparent&amp;nbsp;&lt;span style="color:#666666;"&gt;==&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;:&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;p&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Not the best method however its VERY interesting for static language veterans. We are searching an&lt;span style="text-decoration:underline;"&gt; instance variable that we have not even defined&lt;/span&gt;!&amp;nbsp; Remember only our SQLAlchemy mapper even makes mention of a &amp;ldquo;posts&amp;rdquo; variable through our relationship mapping, yet our &amp;ldquo;parentpost&amp;rdquo; property is searching through self.posts.&amp;nbsp; Once it finds a parent post it returns true, this is not perfect and again not the ideal way to enforce a database constraint but for a demo it works fine.&lt;/p&gt;
&lt;p&gt;Calling &lt;i&gt;nosetests &amp;ndash;-with-pylons=test.ini&lt;/i&gt; should now give you all passing tests&lt;i&gt;. &lt;/i&gt;Running &lt;i&gt;paster serve &amp;ndash;-reload development.ini&lt;/i&gt; and opening &lt;a href="http://localhost:5000"&gt;http://localhost:5000&lt;/a&gt; , adding a couple of threads and you should have something that looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/Picture1_5F00_6219E7BC.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="Picture 1" alt="Picture 1" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/Picture1_5F00_thumb_5F00_71505089.png" width="610" border="0" height="410" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ve completed a home page now that has some dynamic data, added a custom property on our database class, and addressed functional testing with models.&amp;nbsp; &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22596" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/CB2DEC411ED7070D5D8A78108CAA5F2EC3094343"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/CB2DEC411ED7070D5D8A78108CAA5F2EC3094343"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=UXdlqSLxks8:PpjGPbJYjnU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=UXdlqSLxks8:PpjGPbJYjnU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=UXdlqSLxks8:PpjGPbJYjnU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=UXdlqSLxks8:PpjGPbJYjnU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/UXdlqSLxks8" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Python/default.aspx">Python</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Pylons/default.aspx">Pylons</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/SqlAlchemy/default.aspx">SqlAlchemy</category><feedburner:origLink>http://www.lostechies.com/blogs/rssvihla/archive/2009/07/02/python-web-framework-series-pylons-part-5-testing-models.aspx</feedburner:origLink></item><item><title>Congrats to the Los Techies MVPs!</title><link>http://feedproxy.google.com/~r/LosTechies/~3/y8UtGr1BzMI/congrats-to-the-los-techies-mvps.aspx</link><pubDate>Thu, 02 Jul 2009 01:03:38 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22574</guid><dc:creator>bogardj</dc:creator><slash:comments>5</slash:comments><description>&lt;p&gt;This morning, I and fellow Los Techies alumni Eric Hexter and Chris Patterson learned that we are MVPs!&amp;#160; Well, technically I learned last night through an IM of a re-tweet of my MVP lead, but hey, close enough, right?&amp;#160; I know it’s cheesy, but I think these awards are a testament to the great community Los Techies has built over the years, so for me, this is really an award for Los Techies.&amp;#160; The roundup includes:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Jimmy Bogard, MVP ASP.NET&lt;/li&gt;    &lt;li&gt;Eric Hexter, MVP ASP.NET&lt;/li&gt;    &lt;li&gt;Chris Patterson, MVP C#&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Personally, I’ve viewed my community involvement as simply a desire to share my journey with others, and in turn learn where others have been and are going.&amp;#160; My favorite experiences thus far have been the open space conferences, book clubs, dojos and code camps, as it gives me a great chance to meet and talk with a lot of smart people.&amp;#160; Thanks again everyone!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22574" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/E54FF461465AA6808C18EFEA136C22695F9A5152"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/E54FF461465AA6808C18EFEA136C22695F9A5152"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=y8UtGr1BzMI:Y9ldva2pZcQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=y8UtGr1BzMI:Y9ldva2pZcQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=y8UtGr1BzMI:Y9ldva2pZcQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=y8UtGr1BzMI:Y9ldva2pZcQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/y8UtGr1BzMI" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/jimmy_bogard/archive/tags/Misc/default.aspx">Misc</category><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/07/01/congrats-to-the-los-techies-mvps.aspx</feedburner:origLink></item><item><title>I'm a Microsoft C# MVP!</title><link>http://feedproxy.google.com/~r/LosTechies/~3/uG78bS9JZmk/i-m-a-microsoft-c-mvp.aspx</link><pubDate>Thu, 02 Jul 2009 00:14:35 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22573</guid><dc:creator>Chris Patterson</dc:creator><slash:comments>4</slash:comments><description>&lt;p&gt;Opening my Inbox this morning resulted in a pleasant surprise from Microsoft. I have been presented with the 2009 Microsoft&amp;reg; MVP Award as a recognition for sharing my expertise in Visual C# with others. It is an honor to be recognized by Microsoft for doing something that I truly enjoy - building really cool software.&lt;/p&gt;

&lt;div style="text-align:center;"&gt;&lt;img src="http://blog.phatboyg.com/wp-content/uploads/2009/07/mvpbanner.png" alt="MVPbanner.png" border="0" width="584" height="108" /&gt;&lt;/div&gt;

&lt;p style="text-align:center;"&gt;&lt;blockquote&gt;&lt;em&gt;Microsoft Most Valuable Professionals (MVPs) are exceptional technical community leaders from around the world who are awarded for voluntarily sharing their high quality, real world expertise in offline and online technical communities. Microsoft MVPs are a highly select group of experts that represents the technical community&amp;#39;s best and brightest, and they share a deep commitment to community and a willingness to help others.&lt;/em&gt;&lt;/blockquote&gt;
&lt;/p&gt;
&lt;p&gt;A community-based award like this would not be possible without the support of my peers, and I look forward to meeting up with some of those very peers at the next MVP Summit! In the meantime, congratulations to all the new and renewed MVPs!&lt;/p&gt;

&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22573" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/9CC583EB0100C0BA41E79953AD16B179E80E054D"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/9CC583EB0100C0BA41E79953AD16B179E80E054D"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=uG78bS9JZmk:QtBrWP3TQxA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=uG78bS9JZmk:QtBrWP3TQxA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=uG78bS9JZmk:QtBrWP3TQxA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=uG78bS9JZmk:QtBrWP3TQxA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/uG78bS9JZmk" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/chris_patterson/archive/tags/.net/default.aspx">.net</category><category domain="http://www.lostechies.com/blogs/chris_patterson/archive/tags/c_2300_/default.aspx">c#</category><feedburner:origLink>http://www.lostechies.com/blogs/chris_patterson/archive/2009/07/01/i-m-a-microsoft-c-mvp.aspx</feedburner:origLink></item><item><title>Updated TDD Productivity Plug-in for Resharper</title><link>http://feedproxy.google.com/~r/LosTechies/~3/pdyTCOQY5Hk/updated-tdd-productivity-plug-in-for-resharper.aspx</link><pubDate>Wed, 01 Jul 2009 03:41:03 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22550</guid><dc:creator>erichexter</dc:creator><slash:comments>9</slash:comments><description>&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;I first want to thank JetBrains for being pretty awesome.&amp;#160; I have complained a lot about how they are constantly chaining their APIs to Resharper and as a result it makes keeping plugins very hard to maintain but they went way out of their way to help.&amp;#160; I received and email from one of their developers offering to help on my plugin.&amp;#160; Their was a change made in the latest version of resharp which made my plugin incompatible&amp;#160; and their telemetry showed them a pattern with this problem.&amp;#160; Just this week they made a commit to the source code and updated the project.&amp;#160; I did not have the time to get into the internals of this change and I was really motivated by their help.&lt;/p&gt;  &lt;p&gt;As a result, if you were using the plugin I recommend you download the latest version and install it!&lt;/p&gt;  &lt;h4&gt;&lt;a href="http://code.google.com/p/resharper-tdd-productivity-plugin/" target="_blank"&gt;Download it Here&lt;/a&gt;&lt;/h4&gt;  &lt;p&gt;For those of you who do not use it yet I will run down the features that are available.&lt;/p&gt;  &lt;h3&gt;1. Code forward, create a class in a referenced project.&lt;/h3&gt;  &lt;p&gt;When prompted with Quick Fixes for a non-existent class You get the following menu.&amp;#160; This adds menu items to create the class in all referenced projects.( If this menu does not show up… you may need to add the project references to you unit test project).&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/hex/image_5F00_1CA2EF1F.png" width="1028" height="404" /&gt; &lt;/p&gt;  &lt;p&gt;After selecting a menu item.&amp;#160; The class is created in the project you selected but the IDE stays in your test class.&amp;#160; And you are prompted with the quick fix for adding the using for your classes namespace.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/hex/image_5F00_4C7D90E0.png" width="1028" height="627" /&gt; &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;The class file is created in the corresponding project under the correct folder and namespace.&amp;#160; It is that easy!&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/hex/image_5F00_03776F1A.png" width="644" height="465" /&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;h3&gt;2. Move Class/Interface to referenced project&lt;/h3&gt;  &lt;p&gt;If you prefer working with your Class or Interface under test in the same file as your test class and move the class to your referenced project after you get your tests passing this feature will reduce the number of steps it takes to move the class to the referenced project. This eliminates the need to fumble around in the Solution Explorer window.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/hex/image_5F00_2F47C309.png" width="1028" height="272" /&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22550" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/9737C63EEBC4C5D0787A727512E08389701E1A2C"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/9737C63EEBC4C5D0787A727512E08389701E1A2C"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=pdyTCOQY5Hk:Zv9tp0udRNI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=pdyTCOQY5Hk:Zv9tp0udRNI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=pdyTCOQY5Hk:Zv9tp0udRNI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=pdyTCOQY5Hk:Zv9tp0udRNI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/pdyTCOQY5Hk" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/hex/archive/tags/c_2300_/default.aspx">c#</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/agile/default.aspx">agile</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/testing/default.aspx">testing</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/Tools/default.aspx">Tools</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/Open+Source+Software/default.aspx">Open Source Software</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/Unittests/default.aspx">Unittests</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/Resharper/default.aspx">Resharper</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/TDD/default.aspx">TDD</category><feedburner:origLink>http://www.lostechies.com/blogs/hex/archive/2009/06/30/updated-tdd-productivity-plug-in-for-resharper.aspx</feedburner:origLink></item><item><title>Opinionated Input Builders – Part 9 override the default Date Time picker</title><link>http://feedproxy.google.com/~r/LosTechies/~3/DF5TGGyd_X8/opinionated-input-builders-part-9-override-the-default-date-time-picker.aspx</link><pubDate>Tue, 30 Jun 2009 13:07:23 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22523</guid><dc:creator>erichexter</dc:creator><slash:comments>7</slash:comments><description>&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/09/opinionated-input-builders-for-asp-net-mvc-using-partials-part-i.aspx"&gt;Part 1 – Overview&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/09/opinionated-input-builders-for-asp-net-mvc-part-2-html-layout-for-the-label.aspx"&gt;Part 2 – the Labe&lt;/a&gt;l &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/10/opinionated-input-builders-for-asp-net-mvc-part-3-the-source-code.aspx"&gt;Part 3 – the Source Code&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/10/opinionated-input-builders-for-asp-net-mvc-part-3-the-partial-view-inputs.aspx"&gt;Part 4 – the Partial View&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/10/opinionated-input-builders-for-asp-net-mvc-part-5-the-required-input.aspx"&gt;Part 5 – the Required Field Indicator&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/13/opinionated-input-builders-part-6-performance-of-the-builders.aspx"&gt;Part 6 – the Performance&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/14/opinionated-input-builders-part-7-more-on-performance-take-2.aspx"&gt;Part 7 – the Performance Take 2&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/17/opinionated-input-builders-part-8-the-auto-form.aspx"&gt;Part 8 – the AutoForm&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Part 9 – override the default Date Time Picker&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I received a comment from Scott Hanselman about how would a better date time picker look using the opinionated input builders.&amp;#160; I knew that this would be a complex problem just for the fact that there are currently very few good solutions to this problem now.&amp;#160; While JQuery provides a great Date picker I am not very happy with the time picker.&amp;#160; So&amp;#160; here is a version of what this could look like.&amp;#160; What I like about this approach is that it takes all the complexity including the multiple form elements and javascript and pushes it to a small partial that can be easily reused as well as it could be easily tested using QUnit.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;The user interface I came up with is a combination of the Jquery UI datepicker and a set of dropdowns to select the time.&amp;#160; I trimmed down the minute select box so that it only contains fifteen minute increments for this example.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/hex/image_5F00_393D72DF.png" width="616" height="174" /&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;In order to implement this I added a call to the Partial( ) method and passed in the name of my opinion for how a datetime should be rendered.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/hex/image_5F00_69844795.png" width="1145" height="167" /&gt; &lt;/p&gt;  &lt;p&gt;The next step was to add a partial control with the same name to my Shared view folder.&amp;#160; This could have been placed in the Home folder if I only wanted to have this input available for that controller.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/hex/image_5F00_1D4C3DE7.png" width="245" height="357" /&gt; &lt;/p&gt;  &lt;p&gt;The code for the Partial view looks like the following. The view page is strongly typed to a DateTime model property. Than comes some jquery to pull it all together. &lt;/p&gt;  &lt;p&gt;I rendered a hidden field, this field will be used to databind when being posted back to my Save Action.&amp;#160; The other elements I appended some fixed names so that I can wire up an event that updates the hidden field when any of the values of the dropdowns or the date pickker text box changes.&amp;#160; I also write a dynamice method named after the input field in order to reduce the client side code.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/hex/image_5F00_75398EC7.png" width="1028" height="429" /&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;This is one approach to solve this problem,&amp;#160; if you did not want to include this javascript and do the client side wire up of updating the hidden field this same work could be done in a Custom Model Binder that is wired up for DateTime objects that could look for fields with these names and than it could do the formatting.&amp;#160; So there you go a few ways to tackle this problem.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22523" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/E72FEFEADC7AC48F1FE1229B9D006C6C5BCB42BE"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/E72FEFEADC7AC48F1FE1229B9D006C6C5BCB42BE"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=DF5TGGyd_X8:WVMHxrzjOV8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=DF5TGGyd_X8:WVMHxrzjOV8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=DF5TGGyd_X8:WVMHxrzjOV8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=DF5TGGyd_X8:WVMHxrzjOV8:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/DF5TGGyd_X8" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/hex/archive/tags/c_2300_/default.aspx">c#</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/mvc/default.aspx">mvc</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/mvccontrib/default.aspx">mvccontrib</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/Asp.Net/default.aspx">Asp.Net</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/.Net/default.aspx">.Net</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/Asp.Net+MVC/default.aspx">Asp.Net MVC</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/OSS/default.aspx">OSS</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/Open+Source+Software/default.aspx">Open Source Software</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/CoC/default.aspx">CoC</category><feedburner:origLink>http://www.lostechies.com/blogs/hex/archive/2009/06/30/opinionated-input-builders-part-9-override-the-default-date-time-picker.aspx</feedburner:origLink></item><item><title>How we do MVC – View models</title><link>http://feedproxy.google.com/~r/LosTechies/~3/_fYk6Mp_QV0/how-we-do-mvc-view-models.aspx</link><pubDate>Tue, 30 Jun 2009 03:06:36 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22505</guid><dc:creator>bogardj</dc:creator><slash:comments>31</slash:comments><description>&lt;p&gt;A while back, I went over a few of the patterns and opinions we’ve gravitated towards on our current large-ish ASP.NET MVC project, or, &lt;a href="http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/04/24/how-we-do-mvc.aspx"&gt;how we do MVC&lt;/a&gt;.&amp;#160; Many of these opinions were forged the hard way, by doing the wrong thing many times until we found the “right” opinion.&amp;#160; Of course, many of these opinions are only really valid in the constraints of our project.&amp;#160; While the domain of this project isn’t important, here are some key aspects to consider:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;AJAX is used very, very sparingly.&amp;#160; Section 508 compliance is required&lt;/li&gt;    &lt;li&gt;XHTML compliance is also required&lt;/li&gt;    &lt;li&gt;XHTML DTD validation is also required&lt;/li&gt;    &lt;li&gt;All (well, 99%) operations revolve a single uber-entity.&amp;#160; Think customer relationship management, where everything you do deals with exactly one customer&lt;/li&gt;    &lt;li&gt;Snippets of information repeated across many screens&lt;/li&gt;    &lt;li&gt;Screens are either edit, or view, but never both.&amp;#160; (99% never)&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Given these constraints, these opinions may or may not apply to the project you work on.&amp;#160; Again, patterns are all about tradeoffs, benefits and liabilities.&amp;#160; But, opinionated software is like building a bullet train.&amp;#160; It goes extremely fast, but only in the direction you build it.&lt;/p&gt;  &lt;p&gt;That said, I’m going to go over some of the main aspects of our MVC usage in a series of posts – starting with ViewModels.&lt;/p&gt;  &lt;h3&gt;ViewModel design&lt;/h3&gt;  &lt;p&gt;For our application, the ViewModel is a central aspect of our MVC architecture.&amp;#160; One of the first dilemmas facing MVC developers is to decide what the “M” in MVC means in ASP.NET MVC.&amp;#160; In Rails, this is fairly clear, the M is ActiveRecord (by default).&amp;#160; But in ASP.NET MVC, the “M” is silent!&amp;#160; Its out-of-the-box architecture offers no guidelines nor advice on what the M should be.&amp;#160; Should it be an entity?&amp;#160; Data access object?&amp;#160; DTO?&amp;#160; Something else?&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Sidenote – the term DTO is far overused.&amp;#160; DTO is a &lt;a href="http://martinfowler.com/eaaCatalog/dataTransferObject.html"&gt;Data Transfer Object&lt;/a&gt;.&amp;#160; The pattern describes the usage, not the shape of a type.&amp;#160; Just because an object is all properties and no methods does NOT mean it’s a DTO.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;For us, the ViewModel is inextricably linked to Views, which leads us to our first rule:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Rule #1 – All Views are strongly-typed&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;I think I’ve gone over this one enough, as I really can’t stand magic strings and loose contracts.&amp;#160; A dictionary as ViewModel is a very loose contract between the Controller and View.&amp;#160; While on rare occasions we still need to pass information in the dictionary part, we’ve limited this to supporting information to help render some of the lower-level pieces of the View, and are used for some “plumbing” pieces, these pieces do not show up in our Controller action nor are they visible when you design the view.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Rule #2 – For each ViewModel type, there is defined exactly one strongly typed View&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;We’ll get into how we do this soon, but this rule has a lot of implications:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;ViewModel types are distinct from our Domain Model types&lt;/li&gt;    &lt;li&gt;The choice of what View to show can be decided strictly on the shape of your ViewModel&lt;/li&gt;    &lt;li&gt;Re-used pieces in a View (through Partials) can be decided through re-using ViewModel types&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/image_5F00_05CE4D53.png"&gt;&lt;img title="image" style="border-right:0px;border-top:0px;display:inline;border-left:0px;border-bottom:0px;" height="153" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/image_5F00_thumb_5F00_6C664A18.png" width="425" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;On the first point, we never pass an Domain Model entity straight into the view.&amp;#160; Most of the time, we only show a slice of information from a single entity.&amp;#160; And many other times, the same snippet is shown in many places.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Rule #3 – The View dictates the design of the ViewModel.&amp;#160; Only what is required to render a View is passed in with the ViewModel.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;If a Customer object has fifty properties, but one component only shows their name, then we create a custom ViewModel type with &lt;em&gt;only those two properties&lt;/em&gt;.&amp;#160; Because we only have one ViewModel type per View, we shape our ViewModel around only what is displayed (or used) in that View.&amp;#160; Why is this a Good Thing?&lt;/p&gt;  &lt;p&gt;For one, just having a ViewModel points us to the right View.&amp;#160; We need any other information other than your ViewModel type to pick the correct View.&amp;#160; This also means we no longer need to concern ourselves with locating views by some arbitrary name, as the ViewModel &lt;em&gt;is&lt;/em&gt; the View.&amp;#160; Things like RenderPartial, which I have to select a name, become rather pointless at that point.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Rule #4 – The ViewModel contains only data and behavior related to the View&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;For the most part, our ViewModel contains only data.&amp;#160; Most, if not all aggregations/calculations or shaping is done through our Domain Model.&amp;#160; But occasionally, we have View-specific behavior or information, and that rightly belongs on our ViewModel.&lt;/p&gt;  &lt;p&gt;We’ve looked at how we design our ViewModel and what it looks like, but how does it get there?&amp;#160; If we create all these distinct ViewModel types separate from our Domain Model, didn’t we just create a bunch of work for ourselves?&amp;#160; We thought so too, which is why we developed &lt;a href="http://automapper.codeplex.com/"&gt;AutoMapper&lt;/a&gt; on this project.&lt;/p&gt;  &lt;h3&gt;Building the ViewModel&lt;/h3&gt;  &lt;p&gt;When we introduced AutoMapper into our MVC pipeline, we had a real problem.&amp;#160; Do Controllers need to do the mapping between Domain Model and ViewModel in each action method?&amp;#160; That becomes rather annoying for unit testing, as the mapping operation could warp things to a state that it becomes difficult to pull things back out.&amp;#160; For example, or EditModels (ViewModels for forms) are very string-y, where DateTimes, Ints, Decimals etc are represented as strings.&amp;#160; This comes from us using Castle Validators (future post, I promise) for validation.&amp;#160; &lt;/p&gt;  &lt;p&gt;So more moving parts, a dependency across &lt;em&gt;all&lt;/em&gt; controllers?&amp;#160; No, mapping in our Controller action just won’t do.&amp;#160; Instead, we’ll use an Action Filter to do the work for us:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/image_5F00_2510F426.png"&gt;&lt;img title="image" style="border-right:0px;border-top:0px;display:inline;border-left:0px;border-bottom:0px;" height="209" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/image_5F00_thumb_5F00_1D1951C4.png" width="744" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;A request comes in, handled by an Action.&amp;#160; The Action does its thing, ultimately deciding how to respond to the request.&amp;#160; In many cases, this means rendering a view (ViewResult).&amp;#160; From there, our Action Filter comes into play.&amp;#160; On our Action method, we decorate it with an AutoMap attribute to configure the source/destination type pair to be mapped:&lt;/p&gt;  &lt;pre class="code"&gt;[&lt;span style="color:#2b91af;"&gt;AutoMap&lt;/span&gt;(&lt;span style="color:blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;Product&lt;/span&gt;), &lt;span style="color:blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;ShowProduct&lt;/span&gt;))]
&lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;ActionResult &lt;/span&gt;Details(&lt;span style="color:blue;"&gt;int &lt;/span&gt;id)
{
    &lt;span style="color:blue;"&gt;var &lt;/span&gt;product = _productRepository.GetById(id);

    &lt;span style="color:blue;"&gt;return &lt;/span&gt;View(product);
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Very trivial, yes, but here we see that we still use the strongly-typed version of the View method, so that means that our model on the Action side, which I call the Presentation Model (feel free to pick a better name), is the strongly-typed ViewModel &lt;em&gt;for the moment&lt;/em&gt;.&amp;#160; The Presentation Model, which the Action creates, can be an entity, an aggregate root, or some other &lt;a href="http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/02/04/ddd-aggregate-component-pattern-in-action.aspx"&gt;custom aggregate component&lt;/a&gt; that we build up.&lt;/p&gt;

&lt;p&gt;From there, we decorated our action with a filter that specified we need to map from Product to ShowProduct.&amp;#160; Why do we have to specify the source type?&amp;#160; Well, many ORMs, including NHibernate, rely on proxy types for things like lazy loading.&amp;#160; Instead of relying on the runtime type, we’ll explicitly specify our source type directly.&amp;#160; This also helps us later in testing, as we can whip through all of our controller actions using reflection, and test to make sure the source/destination type specified is actually configured.&lt;/p&gt;

&lt;p&gt;The filter attribute is very simple:&lt;/p&gt;

&lt;pre class="code"&gt;[&lt;span style="color:#2b91af;"&gt;AttributeUsage&lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;AttributeTargets&lt;/span&gt;.Method, AllowMultiple = &lt;span style="color:blue;"&gt;false&lt;/span&gt;)]
&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;AutoMapAttribute &lt;/span&gt;: &lt;span style="color:#2b91af;"&gt;ActionFilterAttribute
&lt;/span&gt;{
    &lt;span style="color:blue;"&gt;private readonly &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;_sourceType;
    &lt;span style="color:blue;"&gt;private readonly &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;_destType;

    &lt;span style="color:blue;"&gt;public &lt;/span&gt;AutoMapAttribute(&lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;sourceType, &lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;destType)
    {
        _sourceType = sourceType;
        _destType = destType;
    }

    &lt;span style="color:blue;"&gt;public override void &lt;/span&gt;OnActionExecuted(&lt;span style="color:#2b91af;"&gt;ActionExecutedContext &lt;/span&gt;filterContext)
    {
        &lt;span style="color:blue;"&gt;var &lt;/span&gt;filter = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;AutoMapFilter&lt;/span&gt;(SourceType, DestType);

        filter.OnActionExecuted(filterContext);
    }

    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;SourceType
    {
        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;return &lt;/span&gt;_sourceType; }
    }

    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;DestType
    {
        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;return &lt;/span&gt;_destType; }
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;We simply capture the types and delegate to the real action filter for the work.&amp;#160; This is again because I believe in separating metadata in attributes from the behavior they perform.&amp;#160; Attributes just don’t work well for behavior.&amp;#160; Instead, I’ll create a separate action filter:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;AutoMapFilter &lt;/span&gt;: &lt;span style="color:#2b91af;"&gt;BaseActionFilter
&lt;/span&gt;{
    &lt;span style="color:blue;"&gt;private readonly &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;_sourceType;
    &lt;span style="color:blue;"&gt;private readonly &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;_destType;

    &lt;span style="color:blue;"&gt;public &lt;/span&gt;AutoMapFilter(&lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;sourceType, &lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;destType)
    {
        _sourceType = sourceType;
        _destType = destType;
    }

    &lt;span style="color:blue;"&gt;public override void &lt;/span&gt;OnActionExecuted(&lt;span style="color:#2b91af;"&gt;ActionExecutedContext &lt;/span&gt;filterContext)
    {
        &lt;span style="color:blue;"&gt;var &lt;/span&gt;model = filterContext.Controller.ViewData.Model;

        &lt;span style="color:blue;"&gt;object &lt;/span&gt;viewModel = &lt;span style="color:#2b91af;"&gt;Mapper&lt;/span&gt;.Map(model, _sourceType, _destType);

        filterContext.Controller.ViewData.Model = viewModel;
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;The BaseActionFilter is just a class that implements the various filter methods as virtual members, so I can override just the ones I need to use.&amp;#160; The AutoMapFilter pulls the original PresentationModel out of ViewData, performs the mapping operation, and puts the mapped ViewModel into the ViewData.Model property.&amp;#160; From there, the strongly-typed view for our specified ViewModel type is rendered.&lt;/p&gt;

&lt;p&gt;Because AutoMapper can flatten source types, we often find our ViewModel to simply follow a property chain for various pieces of information.&amp;#160; Again, we let our View shape that piece.&amp;#160; If we decide not to flatten, it’s usually because we’re creating a partial that re-uses a ViewModel type across other parent ViewModel types.&lt;/p&gt;

&lt;h3&gt;&lt;/h3&gt;

&lt;h3&gt;Wrapping it up&lt;/h3&gt;

&lt;p&gt;Designing ViewModels is quite ambiguous with MVC, as the shipped platform doesn’t offer any guidance or opinions in that area.&amp;#160; But by forming rules around our ViewModel, we can create a path and direction for our innovation.&amp;#160; Our rules are designed to strengthen the relationship between the View and the Model, with a concept of ViewModel – a Model designed exclusively for exactly one View.&lt;/p&gt;

&lt;p&gt;In the next post, we’ll look at designing our views – for both viewing and editing data, and how we’ve crafted opinionated HTML builders to eliminate a lot of duplication and enforce standardization.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22505" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/93A72CA986AAB383E2411DC9E51C3B228EF4DFA4"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/93A72CA986AAB383E2411DC9E51C3B228EF4DFA4"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=_fYk6Mp_QV0:qM44NXGkt8o:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=_fYk6Mp_QV0:qM44NXGkt8o:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=_fYk6Mp_QV0:qM44NXGkt8o:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=_fYk6Mp_QV0:qM44NXGkt8o:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/_fYk6Mp_QV0" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/jimmy_bogard/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://www.lostechies.com/blogs/jimmy_bogard/archive/tags/AutoMapper/default.aspx">AutoMapper</category><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/06/29/how-we-do-mvc-view-models.aspx</feedburner:origLink></item><item><title>Python Web Framework Series – Pylons: Part 4 Introduction For Database Support With SQL Alchemy.</title><link>http://feedproxy.google.com/~r/LosTechies/~3/Kzl0Og38C8Y/python-web-framework-series-pylons-part-4-database-support-with-sql-alchemy.aspx</link><pubDate>Mon, 29 Jun 2009 02:54:00 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22417</guid><dc:creator>Ryan Svihla</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;We last left off with &lt;a href="http://www.lostechies.com/blogs/rssvihla/archive/2009/06/25/python-web-framework-series-pylons-part-3-views-with-mako.aspx" target="_blank"&gt;Views with Mako&lt;/a&gt;, now Pylons does not enforce on you an ORM at all, so you can use hand crafted SQL if you prefer. However, since I&amp;rsquo;ve done enough of that for a career or two we&amp;rsquo;re going to use my Python ORM of choice and the preferred one for Pylons SQLAlchemy. &lt;/p&gt;
&lt;h3&gt;Where does SQLAlchemy fit in as an ORM?&lt;/h3&gt;
&lt;p&gt;If you used NHibernate, you should feel pretty close to right at home with SQLAlchemy. If you come from an ActiveRecord, Entity Framework, Subsonic,&amp;nbsp; or even Linq2Sql background this will be a bit more hand management than you are used to. If that is the case, I suggest&amp;nbsp; &lt;a href="http://elixir.ematia.de/trac/wiki" target="_blank"&gt;Elixir&lt;/a&gt; (which I&amp;rsquo;ve heard great things about) or &lt;a href="http://www.sqlobject.org/" target="_blank"&gt;SQLObject&lt;/a&gt; (which I&amp;rsquo;ve used as well and works fine).&lt;/p&gt;
&lt;h3&gt;Mapping and Setup&lt;/h3&gt;
&lt;p&gt;There are three different ways to map tables to classes with SQLAlchemy, I will pick the most commonly used one, but will show the other two in a later post. In our PylonsForum project open &lt;b&gt;model\__init__.py&amp;nbsp; &lt;/b&gt;and change the file to look like so:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:f4025bb5-54a0-4914-8a01-39bfa2b9209a" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#ba2121;"&gt;&lt;i&gt;&amp;quot;&amp;quot;&amp;quot;The&amp;nbsp;application&amp;#39;s&amp;nbsp;model&amp;nbsp;objects&amp;quot;&amp;quot;&amp;quot;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;sqlalchemy&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;orm&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;sqlalchemy&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;as&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;sa&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;datetime&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;pylonsforum.model&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;meta&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;now&lt;/span&gt;():&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;datetime&lt;span style="color:#666666;"&gt;.&lt;/span&gt;datetime&lt;span style="color:#666666;"&gt;.&lt;/span&gt;now()&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;init_model&lt;/span&gt;(engine):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&lt;i&gt;&amp;quot;&amp;quot;&amp;quot;Call&amp;nbsp;me&amp;nbsp;before&amp;nbsp;using&amp;nbsp;any&amp;nbsp;of&amp;nbsp;the&amp;nbsp;tables&amp;nbsp;or&amp;nbsp;classes&amp;nbsp;in&amp;nbsp;the&amp;nbsp;model&amp;quot;&amp;quot;&amp;quot;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;configure(bind&lt;span style="color:#666666;"&gt;=&lt;/span&gt;engine)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;engine&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;engine&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;Post&lt;/b&gt;&lt;/span&gt;(&lt;span style="color:#008000;"&gt;object&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;pass&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;Thread&lt;/b&gt;&lt;/span&gt;(&lt;span style="color:#008000;"&gt;object&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;pass&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
posts_table&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Table(&lt;span style="color:#ba2121;"&gt;&amp;quot;posts&amp;quot;&lt;/span&gt;,&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;metadata,&amp;nbsp;&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Integer,&amp;nbsp;primary_key&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;threadid&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Integer,sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;ForeignKey(&lt;span style="color:#ba2121;"&gt;&amp;#39;threads.id&amp;#39;&lt;/span&gt;)),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;String(&lt;span style="color:#666666;"&gt;4000&lt;/span&gt;),&amp;nbsp;nullable&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;False&lt;/span&gt;),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;author&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;String(&lt;span style="color:#666666;"&gt;255&lt;/span&gt;),&amp;nbsp;nullable&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;False&lt;/span&gt;),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;created&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;TIMESTAMP(),&amp;nbsp;default&lt;span style="color:#666666;"&gt;=&lt;/span&gt;now()),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;isparent&amp;quot;&lt;/span&gt;&amp;nbsp;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Boolean,&amp;nbsp;nullable&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;)&lt;br /&gt;
		)&lt;br /&gt;
threads_table&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Table(&lt;span style="color:#ba2121;"&gt;&amp;quot;threads&amp;quot;&lt;/span&gt;,&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;metadata,&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Integer,&amp;nbsp;primary_key&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;subject&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;String(&lt;span style="color:#666666;"&gt;255&lt;/span&gt;)),&lt;/div&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;sa.Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;dateadded&amp;quot;&lt;/span&gt;, sa.types.TIMESTAMP(), default=now())&lt;br /&gt;
		)&lt;br /&gt;
orm&lt;span style="color:#666666;"&gt;.&lt;/span&gt;mapper(Post,&amp;nbsp;posts_table)&lt;br /&gt;
orm&lt;span style="color:#666666;"&gt;.&lt;/span&gt;mapper(Thread,&amp;nbsp;threads_table,properties&lt;span style="color:#666666;"&gt;=&lt;/span&gt;{&lt;span style="color:#ba2121;"&gt;&amp;#39;posts&amp;#39;&lt;/span&gt;:orm&lt;span style="color:#666666;"&gt;.&lt;/span&gt;relation(Post,&amp;nbsp;backref&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;#39;thread&amp;#39;&lt;/span&gt;)})&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:ae4f52d8-3391-4b24-b22a-9eb112817b37" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Not the best table structure and you&amp;rsquo;re welcome to improve this on your own but I wanted to create a default setup that was easy to read.&amp;nbsp; Lets take a bit to recap the pieces:&lt;/p&gt;
&lt;hr /&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:1e770a1b-16bc-448e-ace4-cbc920d062aa" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;init_model&lt;/span&gt;(engine):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&lt;i&gt;&amp;quot;&amp;quot;&amp;quot;Call&amp;nbsp;me&amp;nbsp;before&amp;nbsp;using&amp;nbsp;any&amp;nbsp;of&amp;nbsp;the&amp;nbsp;tables&amp;nbsp;or&amp;nbsp;classes&amp;nbsp;in&amp;nbsp;the&amp;nbsp;model&amp;quot;&amp;quot;&amp;quot;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;configure(bind&lt;span style="color:#666666;"&gt;=&lt;/span&gt;engine)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;engine&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;engine&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Straightforward method here sets up a Session object with the database engine passed into the method.&amp;nbsp; Pylons will call init_model itself when the site is accessed.&lt;/p&gt;
&lt;hr /&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:7960a112-25d7-46d6-a9c8-d3eac146ff18" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;Post&lt;/b&gt;&lt;/span&gt;(&lt;span style="color:#008000;"&gt;object&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;pass&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;Thread&lt;/b&gt;&lt;/span&gt;(&lt;span style="color:#008000;"&gt;object&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;pass&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So a couple of empty classes?&amp;nbsp; Python being a dynamic language can get away with this and just add the properties at runtime.&amp;nbsp; These are the objects we&amp;rsquo;ll be interacting with when we want to store data.&lt;/p&gt;
&lt;hr /&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:1d500b79-b3df-444a-a6ce-3c85fe1be8d4" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
posts_table&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Table(&lt;span style="color:#ba2121;"&gt;&amp;quot;posts&amp;quot;&lt;/span&gt;,&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;metadata,&amp;nbsp;&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Integer,&amp;nbsp;primary_key&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;threadid&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Integer,sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;ForeignKey(&lt;span style="color:#ba2121;"&gt;&amp;#39;threads.id&amp;#39;&lt;/span&gt;)),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;String(&lt;span style="color:#666666;"&gt;4000&lt;/span&gt;),&amp;nbsp;nullable&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;False&lt;/span&gt;),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;author&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;String(&lt;span style="color:#666666;"&gt;255&lt;/span&gt;),&amp;nbsp;nullable&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;False&lt;/span&gt;),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;dateadded&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;TIMESTAMP(),&amp;nbsp;default&lt;span style="color:#666666;"&gt;=&lt;/span&gt;now()),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;isparent&amp;quot;&lt;/span&gt;&amp;nbsp;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Boolean,&amp;nbsp;nullable&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;)&lt;br /&gt;
		)&lt;br /&gt;
threads_table&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Table(&lt;span style="color:#ba2121;"&gt;&amp;quot;threads&amp;quot;&lt;/span&gt;,&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;metadata,&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Integer,&amp;nbsp;primary_key&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;subject&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;String(&lt;span style="color:#666666;"&gt;255&lt;/span&gt;))&lt;br /&gt;
		)&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Ok these table declarations are providing the data definition logic, including some basic relationship, nothing too interesting here post in comments if you have specific questions.&lt;/p&gt;
&lt;hr /&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:cc7574da-0863-4768-9570-c62e486b548e" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
orm&lt;span style="color:#666666;"&gt;.&lt;/span&gt;mapper(Post,&amp;nbsp;posts_table)&lt;br /&gt;
orm&lt;span style="color:#666666;"&gt;.&lt;/span&gt;mapper(Thread,&amp;nbsp;threads_table,properties&lt;span style="color:#666666;"&gt;=&lt;/span&gt;{&lt;span style="color:#ba2121;"&gt;&amp;#39;posts&amp;#39;&lt;/span&gt;:orm&lt;span style="color:#666666;"&gt;.&lt;/span&gt;relation(Post,&amp;nbsp;backref&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;#39;thread&amp;#39;&lt;/span&gt;)})&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here the orm.mapper calls take the Page and Thread classes and map them with the table data definitions typed in earlier.&amp;nbsp; You can also specify relationships here as we have done in the thread mapping, the properties argument is referencing the &lt;i&gt;Post&lt;/i&gt; class and mapping it to a property called posts on the &lt;i&gt;Thread&lt;/i&gt; class, while also mapping the other direction and putting thread on the &lt;i&gt;Post&lt;/i&gt; class.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Finally run &lt;i&gt;paster setup-app development.ini&lt;/i&gt; from the root pylonsforum directory and you should see a bunch of SQL flying by which indicates it has build the database schema for us:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_3D5BCA36.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_thumb_5F00_214D9BFC.png" width="609" border="0" height="420" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h3&gt;Making Our New Thread Store In The Database&lt;/h3&gt;
&lt;p&gt;In the interest of space and time I&amp;rsquo;ll skip the testing story for another post.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;Open up &lt;i&gt;controllers\home.py&lt;/i&gt; .&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Remove the Post class we created several posts ago &lt;/li&gt;
&lt;li&gt;under the imports add &lt;i&gt;import pylonsforum.model as model &lt;/i&gt;&lt;/li&gt;
&lt;li&gt;under the imports add &lt;i&gt;import pylonsforum.model.meta as meta&lt;/i&gt; &lt;/li&gt;
&lt;li&gt;change the submitnewthread method to the following      
&lt;ul&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:205d3b50-c0a8-4b5f-ae6b-b43755eb1e3b" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
	thread&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;model&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Thread()&amp;nbsp;&lt;br /&gt;
	thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;request&lt;span style="color:#666666;"&gt;.&lt;/span&gt;POST[&lt;span style="color:#ba2121;"&gt;&amp;#39;subject&amp;#39;&lt;/span&gt;]&lt;br /&gt;
	post&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;model&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Post()&lt;br /&gt;
	post&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;users&lt;span style="color:#666666;"&gt;.&lt;/span&gt;get_current_user(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;)&lt;br /&gt;
	post&lt;span style="color:#666666;"&gt;.&lt;/span&gt;isparent&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;&lt;br /&gt;
	post&lt;span style="color:#666666;"&gt;.&lt;/span&gt;content&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;request&lt;span style="color:#666666;"&gt;.&lt;/span&gt;POST[&lt;span style="color:#ba2121;"&gt;&amp;#39;content&amp;#39;&lt;/span&gt;]&lt;br /&gt;
	thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts&lt;span style="color:#666666;"&gt;.&lt;/span&gt;append(post)&amp;nbsp;&lt;span style="color:#408080;"&gt;&lt;i&gt;#adding&amp;nbsp;post&amp;nbsp;to&amp;nbsp;the&amp;nbsp;thread&amp;nbsp;object&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
	meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;add(thread)&amp;nbsp;&lt;span style="color:#408080;"&gt;&lt;i&gt;#look&amp;nbsp;only&amp;nbsp;have&amp;nbsp;to&amp;nbsp;add&amp;nbsp;the&amp;nbsp;thread&amp;nbsp;object&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
	meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;flush()&amp;nbsp;&lt;span style="color:#408080;"&gt;&lt;i&gt;#optional&amp;nbsp;when&amp;nbsp;AutoCommit&amp;nbsp;is&amp;nbsp;on,&amp;nbsp;but&amp;nbsp;useful&amp;nbsp;for&amp;nbsp;control&amp;nbsp;in&amp;nbsp;data&amp;nbsp;integrity&amp;nbsp;cases&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
	meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;commit()&amp;nbsp;&lt;span style="color:#408080;"&gt;&lt;i&gt;#makes&amp;nbsp;changes&amp;nbsp;real&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
	thread_query&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;query(model&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Thread)&amp;nbsp;&lt;span style="color:#408080;"&gt;&lt;i&gt;#query&amp;nbsp;back&amp;nbsp;submitted&amp;nbsp;data&amp;nbsp;to&amp;nbsp;display&amp;nbsp;to&amp;nbsp;ui&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
	thread&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;thread_query&lt;span style="color:#666666;"&gt;.&lt;/span&gt;filter_by(&lt;span style="color:#008000;"&gt;id&lt;/span&gt;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;id)&lt;span style="color:#666666;"&gt;.&lt;/span&gt;first()&amp;nbsp;&lt;span style="color:#408080;"&gt;&lt;i&gt;#&amp;nbsp;yes&amp;nbsp;actually&amp;nbsp;querying&amp;nbsp;using&amp;nbsp;the&amp;nbsp;thread&amp;nbsp;id&amp;nbsp;of&amp;nbsp;our&amp;nbsp;created&amp;nbsp;object&amp;nbsp;above&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;username&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts[&lt;span style="color:#666666;"&gt;0&lt;/span&gt;]&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author&lt;br /&gt;
	c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject&lt;br /&gt;
	c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;content&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts[&lt;span style="color:#666666;"&gt;0&lt;/span&gt;]&lt;span style="color:#666666;"&gt;.&lt;/span&gt;content&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;render(&lt;span style="color:#ba2121;"&gt;&amp;#39;submitnewthread.mako&amp;#39;&lt;/span&gt;)&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally run the newthread action&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &lt;a href="http://localhost:5000/home/newthread" target="_blank"&gt;http://localhost:5000/home/newthread&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;then create a thread&lt;/p&gt;
&lt;p&gt;&lt;a title="http://localhost:5000/home/submitnewthread" href="http://localhost:5000/home/submitnewthread"&gt;http://localhost:5000/home/submitnewthread&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Should be no change in the actual outward appearance of from what we were doing before.&lt;/p&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;h3&gt;Summary and Recap&lt;/h3&gt;
&lt;p&gt;This was a very quick and basic introduction to SQLAlchemy and I will do more with it over the next couple of posts, but please add any comments to things I did not make clear. SQLAlchemy and ORM&amp;rsquo;s in general are a very large subjects and those of us that have used them for a long time tend to forget not all of this was so obvious when we started.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22417" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/785A51E06BCAC0692FBC229EDD3B6C371D3A9823"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/785A51E06BCAC0692FBC229EDD3B6C371D3A9823"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=Kzl0Og38C8Y:kWMY9qrehEo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=Kzl0Og38C8Y:kWMY9qrehEo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=Kzl0Og38C8Y:kWMY9qrehEo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=Kzl0Og38C8Y:kWMY9qrehEo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/Kzl0Og38C8Y" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Python/default.aspx">Python</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/ORM/default.aspx">ORM</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Pylons/default.aspx">Pylons</category><feedburner:origLink>http://www.lostechies.com/blogs/rssvihla/archive/2009/06/28/python-web-framework-series-pylons-part-4-database-support-with-sql-alchemy.aspx</feedburner:origLink></item></channel></rss>
