<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Jaros&#322;aw Zabie&#322;&#322;o - BLOG: Django, Rails i wsp&#243;&#322;dzielenie danych</title>
    <link>http://blog.zabiello.com/articles/2006/07/19/django-rails-i-wsp%C3%B3%C5%82dzielenie-danych</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>moje notatki, linki, komentarze</description>
    <item>
      <title>Django, Rails i wsp&#243;&#322;dzielenie danych</title>
      <description>&lt;p&gt;Osoby maj&#261;ce wcze&#347;niej do czynienia z innymi frameworkami, gdy si&#281;gn&#261; do &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt; mog&#261; by&#263; troch&#281; zdezorientowane sposobem w jaki nale&#380;y przekazywa&#263; zmienne do wsp&#243;lnych cz&#281;&#347;ci serwisu. Aby lepiej zrozumie&#263; problem, podam wpierw jak jest on rozwi&#261;zywane w &lt;a href="http://rubyonrails.com"&gt;Railsach&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Ot&#243;&#380;, Railsy zak&#322;adaj&#261;, &#380;e ka&#380;dy kontroler dziedziczy po wsp&#243;lnym kontrolerze zwanym &lt;strong&gt;ApplicationControler&lt;/strong&gt;. A &#380;e jest to normalna klasa Rubiego, wi&#281;c nic dziwnego, &#380;e wszelkie jej metody i zmienne (instancji) s&#261; automatycznie dziedziczone we wszystkich jej klasach potomnych. To bardzo intuicyjne rozwi&#261;zanie. Je&#347;li chcemy przekaza&#263; jakie&#347; wsp&#243;lne dane do wszystkich kontroler&#243;w i ich szablon&#243;w, wystarczy te dane zdefiniowa&#263; w tym miejscu. We&#378;my np. poni&#380;szy kod.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="comment"&gt;# plik: app/controllers/application.rb&lt;/span&gt;
&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ApplicationController&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActionController&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;
  &lt;span class="ident"&gt;before_filter&lt;/span&gt; &lt;span class="symbol"&gt;:defaults&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;
    &lt;span class="attribute"&gt;@name&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Jarek&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;defaults&lt;/span&gt;
    &lt;span class="attribute"&gt;@msg&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Hello!&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="comment"&gt;# plik: app/controllers/home_controller.rb&lt;/span&gt;
&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;HomeController&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ApplicationController&lt;/span&gt; 
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="comment"&gt;# plik: app/controllers/about_controller.rb&lt;/span&gt;
&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;AboutController&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ApplicationController&lt;/span&gt; 
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;index&lt;/span&gt;
    &lt;span class="attribute"&gt;@dodatkowa&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;warto&#347;&#263;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Zak&#322;adaj&#261;c, &#380;e nie zmieniali&#347;my domy&#347;lnego dzia&#322;ania resolvera adres&#243;w &lt;span class="caps"&gt;URL&lt;/span&gt;, wpisanie strony http://localhost:3000/home wywo&#322;a domy&#347;ln&#261; metod&#281; index() z klasy HomeController. Je&#347;li jej nie ma (jak na naszym przyk&#322;adzie), to Rails zak&#322;ada, &#380;e chcemy wywo&#322;a&#263; jej szablon tak, jakby ta metoda istnia&#322;a. Wczytywany jest zatem plik app/views/home/index.rhtml. Dzi&#281;ki temu, &#380;e w klasie ApplicationController zdefiniowali&#347;my 2 zmienne instancji (@name i @msg) automatycznie s&#261; one dziedziczone przez klas&#281; HomeController i tym samym dost&#281;pne w w/w szablonie. Identycznie b&#281;dzie z drug&#261; klas&#261;, jej szablon r&#243;wnie&#380; b&#281;dzie mia&#322; obie, zdefiniowane wy&#380;ej, zmienne&lt;sup&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;


	&lt;p&gt;W wypadku &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt;, sprawy wygl&#261;daj&#261; inaczej dlatego, &#380;e kontrolery&lt;sup&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt; nie s&#261; metodami klas Pythona! S&#261; one metodami &lt;strong&gt;modu&#322;u&lt;/strong&gt; Pythona. Co prawda modu&#322; te&#380; jest obiektem, ma w&#322;asn&#261; przetrze&#324; nazw itp. ale posiada jedn&#261; zasadnicz&#261; r&#243;&#380;nic&#281; wobec klasy &amp;#8211; &lt;strong&gt;nie mo&#380;na dziedziczy&#263;&lt;/strong&gt; modu&#322;u od modu&#322;u. Tym samym pr&#243;ba wsp&#243;&#322;dzielenia zmiennych musi by&#263; zrobiona zupe&#322;nie inn&#261; metod&#261;.&lt;/p&gt;


	&lt;p&gt;Troch&#281; z tym problemem si&#281; m&#281;czy&#322;em, bo w dokumentacji ma&#322;o na ten temat pisz&#261;. Dopiero na &lt;span class="caps"&gt;IRC&lt;/span&gt; podsuni&#281;to mi link do artyku&#322;u &lt;a href="http://www.b-list.org/weblog/2006/06/14/django-tips-template-context-processors"&gt;Django tips: Template context processors&lt;/a&gt;, kt&#243;ry wszystko &#322;adnie wyja&#347;ni&#322;&lt;sup&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;. Okazuje si&#281;, &#380;e jest kilka sposob&#243;w rozwi&#261;zania tego problemu. Napisanie w&#322;asnego MiddleWare (ech, nie chcia&#322;o mi si&#281;, to armata na much&#281;), napisanie w&#322;asnego znacznika dla szablon&#243;w (w wypadku mojej ma&#322;ej aplikacji, to te&#380; by&#322;aby przesada) lub wykorzystanie tzw. procesora kontekstu (Context Processor). I to by&#322;o to!&lt;/p&gt;


	&lt;p&gt;Wystarczy stworzy&#263; sobie plik (o nazwie np. context_processors.py) z funkcjami implementuj&#261;cymi to, co chcemy wrzuci&#263; do wszystkich szablon&#243;w.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;request&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
  &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Jarek&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;

&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;msg&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;request&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
  &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Hello!&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Nast&#281;pnie trzeba doda&#263; w settings.py informacj&#281; &#380;e b&#281;dziemy tego u&#380;ywa&#263;:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;TEMPLATE_CONTEXT_PROCESSORS&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;
  &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;myapp.context_processors.name&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;
  &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;myapp.context_processors.msg&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;
  &lt;span class="punct"&gt;)&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;W wypadku &lt;a href="http://www.djangoproject.com/documentation/generic_views/"&gt;generic views&lt;/a&gt; to wszystko, bo one automatycznie wci&#261;gaj&#261; RequestContext dla swoich szablon&#243;w. W wypadku naszych kontroler&#243;w (zak&#322;adaj&#261;c, &#380;e u&#380;ywamy render_to_response() aby wy&#347;wietla&#263; szablon) trzeba na ko&#324;cu metody render_to_response() doda&#263; jeden parametr &amp;#8216;context_instance&amp;#8217;. Czyli:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="comment"&gt;# wpierw wci&#261;gamy RequestContext&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;django&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;template&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;RequestContext&lt;/span&gt;

&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;home&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;request&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
  &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="ident"&gt;render_to_response&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;
    &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;home.html&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; 
    &lt;span class="ident"&gt;context_instance&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;RequestContext&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;request&lt;/span&gt;&lt;span class="punct"&gt;))&lt;/span&gt;

&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;about&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;request&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
  &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="ident"&gt;render_to_response&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;
    &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;about.html&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; 
    &lt;span class="punct"&gt;{'&lt;/span&gt;&lt;span class="string"&gt;dodatkowa&lt;/span&gt;&lt;span class="punct"&gt;':&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;warto&#347;&#263;&lt;/span&gt;&lt;span class="punct"&gt;'},&lt;/span&gt;
    &lt;span class="ident"&gt;context_instance&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;RequestContext&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;request&lt;/span&gt;&lt;span class="punct"&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Tak coraz bardziej wg&#322;&#281;biaj&#261;c si&#281; w Rails i Django widz&#281;, &#380;e Rails jest jednak bardziej intuicyjny i &#322;atwiej si&#281; go nauczy&#263;. Jednak&#380;e Django wydaje si&#281; mie&#263; sporo pot&#281;&#380;nych mechanizm&#243;w, kt&#243;rych odkrywanie (mam nadziej&#281;) si&#281; upro&#347;ci jak tylko jego tw&#243;rcy opublikuj&#261; pierwsz&#261; ksi&#261;&#380;k&#281; na jego temat (ma by&#263; dost&#281;pna tak&#380;e w wersji online za darmo!)&lt;/p&gt;


	&lt;p&gt;&lt;del&gt;-&lt;/del&gt;&lt;/p&gt;


	&lt;p id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; W podanym wy&#380;ej przyk&#322;adzie wykorzysta&#322;em dwa r&#243;&#380;ne sposoby przekazania zmiennych. Za pomoc&#261; konstruktora i za pomoc&#261; metody &amp;#8216;before_filter&amp;#8217;. Wiadomo, &#380;e konstruktor nie nadaje si&#281; do przekazywania wszystkiego. Czasami musimy przekaza&#263; co&#347;, co istnieje ju&#380; po wywo&#322;aniu konstruktora. Wtedy przydaje si&#281; metoda &amp;#8216;before_filter&amp;#8217;. To jedna z wielu sztuczek jakie ma w swym arsenale Rails aby kod by&#322; czysty, klarowny i zgodny z zasad&#261; &lt;span class="caps"&gt;DRY&lt;/span&gt; (nie powtarzania si&#281;).&lt;/p&gt;


	&lt;p id="fn2"&gt;&lt;sup&gt;2&lt;/sup&gt; Zobacz te&#380; artyku&#322; &lt;a href="http://www.b-list.org/weblog/2006/06/13/how-django-processes-request"&gt;How Django processes a request?&lt;/a&gt;.&lt;/p&gt;


	&lt;p id="fn3"&gt;&lt;sup&gt;3&lt;/sup&gt; W Django nazywane s&#261; one metodami widoku. Osobi&#347;cie nie podoba mi si&#281; zamieszanie terminologiczne jakie Django zrobi&#322;o z modelem &lt;span class="caps"&gt;MVC&lt;/span&gt;. Kontroler to dla nich Widok (View), za&#347; Widok to Szablon. Troch&#281; to bez sensu, bo nikt tak tych rzecz nie nazywa. Czyli djangowe metody widoku to nic innego jak akcje kontrolera dla Rails i reszty &#347;wiata.&lt;/p&gt;</description>
      <pubDate>Wed, 19 Jul 2006 21:22:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:33840d51-676c-4426-a315-012a57809d60</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2006/07/19/django-rails-i-wsp%C3%B3%C5%82dzielenie-danych</link>
      <category>Ruby on Rails</category>
      <category>Django</category>
      <category>django</category>
      <category>rails</category>
    </item>
    <item>
      <title>"Django, Rails i wsp&#243;&#322;dzielenie danych" by Adam Hoscilo</title>
      <description>&lt;p&gt;Rozwiazanie problemu za pomoca Context Processor jest oczywiscie dopuszczalne i poprawne ale malo elastyczne i moim zdaniem nieladne.
Zdecydowanie ladniej i logiczniej robi sie template taga. Takie rozwiazanie pozbawia kod &amp;#8220;magii&amp;#8221;, wymusza czystosc i daje wieksza elastycznosc. Dodatkowo tego stworzenie takiego taga jest dosc proste.&lt;/p&gt;</description>
      <pubDate>Sat, 29 Jul 2006 17:37:27 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:03a67d7e-0996-42ac-aa8f-429c8861880a</guid>
      <link>http://blog.zabiello.com/articles/2006/07/19/django-rails-i-wsp%C3%B3%C5%82dzielenie-danych#comment-166</link>
    </item>
  </channel>
</rss>
