<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Francisco Souza &#187; django</title>
	<atom:link href="http://www.franciscosouza.com.br/tag/django/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.franciscosouza.com.br</link>
	<description>Open source, Python, Django, Java, Ruby on Rails, agile e outras coisas mais</description>
	<lastBuildDate>Sat, 28 Aug 2010 22:28:16 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1-alpha</generator>
		<item>
		<title>II Liberdade Interativa: foi show!</title>
		<link>http://www.franciscosouza.com.br/2010/08/20/ii-liberdade-interativa-foi-show/</link>
		<comments>http://www.franciscosouza.com.br/2010/08/20/ii-liberdade-interativa-foi-show/#comments</comments>
		<pubDate>Fri, 20 Aug 2010 17:26:43 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[eventos]]></category>
		<category><![CDATA[comunidade]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[palestras]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.franciscosouza.com.br/?p=1096</guid>
		<description><![CDATA[Ontem aconteceu a segunda edição do Liberdade Interativa, um evento da comunidade Tux-ES. O evento contou com três apresentações: na primeira, a Rapha falou sobre o Bacula, uma ferramenta para backups de servidores em redes. Logo depois da Rapha, fui &#8230; <a href="http://www.franciscosouza.com.br/2010/08/20/ii-liberdade-interativa-foi-show/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Ontem aconteceu a segunda edição do <a title="Liberadade Interativa" rel="nofollow" href="http://www.tux-es.org/liberdadeinterativa/" target="_blank">Liberdade Interativa</a>, um evento da comunidade <a title="Tux ES" rel="nofollow" href="http://www.tux-es.org" target="_blank">Tux-ES</a>. O evento contou com três apresentações: na primeira, a <a title="Rapha" rel="nofollow" href="http://twitter.com/ra_pha" target="_blank">Rapha</a> falou sobre o Bacula, uma ferramenta para backups de servidores em redes. Logo depois da Rapha, <span style="text-decoration: line-through;">fui desafiado</span> apresentei a palestra &#8220;Django: o framework web para perfeccionistas com prazo&#8221;. Fechando o evento, o colega <a title="Almir M3nd3s" rel="nofollow" href="http://twitter.com/m3nd3s" target="_blank">M3nd3s</a> apresentou a palestra &#8220;Iptables &#8211; Entendendo como fazer um firewall pessoal&#8221;.<span id="more-1096"></span></p>
<p>Excetuando o fato que estourei um pouquinho o tempo na minha apresentação, o momento foi super válido, pois pude contar com a colaboração do público com muitas perguntas e comentários, e acredito que pelo menos algumas pessoas ficaram interessadas em dar uma olhada no Django. Também foi bacana o momento pós-evento onde puder trocar uma ideia com algumas pessoas, inclusive um aluno da UFES que está utilizando Django para uma aplicação de backend em seu trabalho de conclusão de curso.</p>
<p>Disponibilizei os slides da apresentação no SlideShare:<br />
<center>
<div id="__ss_5015915" style="width: 425px;"><strong style="display: block; margin: 12px 0 4px;"><a title="Django: O Framework web para perfeccionistas com prazos" rel="nofollow" href="http://www.slideshare.net/franciscosouza/django-o-framework-web-para-perfeccionistas-com-prazos" target="_blank">Django: O Framework web para perfeccionistas com prazos</a></strong><object id="__sse5015915" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="425" height="355" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowScriptAccess" value="always" /><param name="src" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=apresentacaodjango-100819211400-phpapp01&amp;stripped_title=django-o-framework-web-para-perfeccionistas-com-prazos" /><param name="name" value="__sse5015915" /><param name="allowfullscreen" value="true" /><embed id="__sse5015915" type="application/x-shockwave-flash" width="425" height="355" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=apresentacaodjango-100819211400-phpapp01&amp;stripped_title=django-o-framework-web-para-perfeccionistas-com-prazos" name="__sse5015915" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<div style="padding: 5px 0 12px;">View more <a rel="nofollow" href="http://www.slideshare.net/" target="_blank">presentations</a> from <a rel="nofollow" href="http://www.slideshare.net/franciscosouza" target="_blank">Francisco Souza</a>.</div>
</div>
<p></center><br />
Como os slides não fazem muito sentido sem as notas, também disponibilizo os slides com as notas, para quem tiver interesse:<br />
<center>
<div id="__ss_5020424" style="width: 477px;"><strong style="display: block; margin: 12px 0 4px;"><a title="Django: o framework web para perfeccionistas com prazos" rel="nofollow" href="http://www.slideshare.net/franciscosouza/django-o-framework-web-para-perfeccionistas-com-prazos-5020424" target="_blank">Django: o framework web para perfeccionistas com prazos</a></strong><object id="__sse5020424" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="477" height="510" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowScriptAccess" value="always" /><param name="src" value="http://static.slidesharecdn.com/swf/doc_player.swf?doc=101pdfsamapresentacaodjango-100820121739-phpapp02&amp;stripped_title=django-o-framework-web-para-perfeccionistas-com-prazos-5020424" /><param name="name" value="__sse5020424" /><param name="allowfullscreen" value="true" /><embed id="__sse5020424" type="application/x-shockwave-flash" width="477" height="510" src="http://static.slidesharecdn.com/swf/doc_player.swf?doc=101pdfsamapresentacaodjango-100820121739-phpapp02&amp;stripped_title=django-o-framework-web-para-perfeccionistas-com-prazos-5020424" name="__sse5020424" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<div style="padding: 5px 0 12px;">View more <a rel="nofollow" href="http://www.slideshare.net/" target="_blank">documents</a> from <a rel="nofollow" href="http://www.slideshare.net/franciscosouza" target="_blank">Francisco Souza</a>.</div>
</div>
<p></center><br />
Novamente, gostaria muito de feedback, então se você tem alguma crítica, comentário, dúvida ou qualquer coisa, entre em contato comigo, ou faça um comentário aqui :) E no mais, é isso! Nos vemos no III Liberdade Interativa! ;)</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2010/08/20/ii-liberdade-interativa-foi-show/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Voando com o Django no Google App Engine</title>
		<link>http://www.franciscosouza.com.br/2010/08/02/voando-com-o-django-no-google-app-engine/</link>
		<comments>http://www.franciscosouza.com.br/2010/08/02/voando-com-o-django-no-google-app-engine/#comments</comments>
		<pubDate>Mon, 02 Aug 2010 20:00:34 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[desenvolvimento de softwares]]></category>
		<category><![CDATA[appengine]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[frameworks]]></category>
		<category><![CDATA[google app engine]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.franciscosouza.com.br/?p=1088</guid>
		<description><![CDATA[O Google App Engine é uma ferramenta sensacional para desenvolvedores web. Uma ferramente certamente útil e que deveria pelo menos ser experimentada por todo desenvolvedor web que se preza :) A primeira linguagem de programação suportada pelo App Engine foi &#8230; <a href="http://www.franciscosouza.com.br/2010/08/02/voando-com-o-django-no-google-app-engine/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>O <a title="Google App Engine" rel="nofollow" href="http://appengine.google.com" target="_blank">Google App Engine</a> é uma ferramenta sensacional para desenvolvedores web. Uma ferramente certamente útil e que deveria pelo menos ser experimentada por todo desenvolvedor web que se preza :) A primeira linguagem de programação suportada pelo App Engine foi o <a title="Python" rel="nofollow" href="http://www.python.org" target="_blank">Python</a>, e hoje a linguagem Java também é suportada. Python é uma linguagem com muitos frameworks web (muitos mesmo), e você pode usar alguns deles no App Engine. Resolvi, então, criar uma série com três posts sobre como usar três frameworks web Python no Google App Engine: <a title="Django Project" rel="nofollow" href="http://www.djangoproject.com" target="_blank">Django</a>, <a title="Flask" rel="nofollow" href="http://flask.pocoo.org" target="_blank">Flask</a> e <a title="web2py" rel="nofollow" href="http://www.web2py.com" target="_blank">web2py</a>.</p>
<p>Em todos os casos, desenvolverei uma aplicação simples, que será enviada para o Google App Engine e disponibilizada publicamente :) Nesta primeira parte, abordarei o Django, o mais famoso dentre os frameworks Python para a web.<span id="more-1088"></span></p>
<p>O principal recurso do Django é a camada de modelo, chamada <em>Django models</em>. Trata-se de uma camada de abstração de dados composta por um poderoso framework de mapeamento objeto-relacional, que suporta diversos sistemas de gerenciamento de banco de dados relacionais. O único problema é que o Google App Engine não usa um banco de dados relacional, o App Engine usa o BigTable, um poderoso banco de dados para armazenamento de dados em larga escala. Assim, a poderosa camada de modelo do Django é simplesmente inútil, pelo menos nativamente falando.</p>
<p>Não há motivo para pânico, existe um fork do Django, o projeto <a title="django-nonrel project" href="http://www.allbuttonspressed.com/projects/django-nonrel" target="_blank">django-nonrel</a>, que visa trazer o poder do <em>Django models</em> para bancos de dados não-relacionais, como o BigTable. Na aplicação deste post, foi utilizado o subprojeto <a title="djangoappengine project" href="http://www.allbuttonspressed.com/projects/djangoappengine" target="_blank">djangoappengine</a>, que une o Django ao BigTable de forma descomplicada.</p>
<p>A aplicação de exemplo não será nenhum exemplo de criatividade: um blog extremamente simples, com apenas uma página para listar os posts e outra para cadastrá-los (protegida por login). Vamos utilizar a autenticação nativa do Django, e não a API de autenticação fornecida pelo App Engine.</p>
<p>O primeiro passo é deixar o ambiente pronto para receber nosso código (e voar em produção =P). De acordo com a <a title="Instalação do djangoappengine" rel="nofollow" href="http://www.allbuttonspressed.com/projects/djangoappengine#installation" target="_blank">documentação oficial do djangoappengine</a>, é necessário baixar quatro arquivos e juntá-los. Comecei pela aplicação, baixei o arquivo <em>django-testapp.zip</em>, extraí e renomeei o diretório de <em>django-testapp</em> para <em>blog_gae</em>. Depois eu baixei as outras bibliotecas, de forma que a estrutura do projeto ficou da seguinte forma:</p>
<p><img class="aligncenter size-full wp-image-1089" title="Estrutura do projeto" src="http://img.franciscosouza.com.br/2010/07/screenshot1.png" alt="Estrutura do projeto" width="176" height="213" />O diretório &#8220;django&#8221; foi extraído do pacote <em>django-nonrel.zip</em>, o diretório &#8220;djangoappengine&#8221; do pacote <em>djangoappengine.zip </em>e o &#8220;djangotoolbox&#8221; extraído do pacote <em>djangotoolbox.zip</em>. Junto à estrutura de exemplo da aplicação está presente o arquivo <em>app.yaml</em>, que é o arquivo de configuração da aplicação no Google App Engine. Neste arquivo, é necessário apenas mudar o ID da aplicação (primeira linha). Veja como fica o arquivo após a mudança:</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">application: gaeseries<br />
version: 1<br />
runtime: python<br />
api_version: 1<br />
<br />
default_expiration: '365d'<br />
<br />
handlers:<br />
- url: /remote_api<br />
script: $PYTHON_LIB/google/appengine/ext/remote_api/handler.py<br />
login: admin<br />
<br />
- url: /_ah/queue/deferred<br />
&nbsp; script: djangoappengine/deferred/handler.py<br />
&nbsp; login: admin<br />
<br />
- url: /media/admin<br />
&nbsp; static_dir: django/contrib/admin/media/<br />
<br />
- url: /.*<br />
&nbsp; script: djangoappengine/main/main.py</div></td></tr></tbody></table></div>
<p>A cada parte da série de posts eu vou fazer o deploy de uma versão diferente, assim, todas as versões ficarão disponíveis online dentro de uma mesma aplicação do Google App Engine. Como esta é a primeira parte, então será a primeira versão =P Outro ponto é o arquivo de configuração do Django (<em>settings.py</em>), neste momento, a única mudança neste arquivo é &#8220;descomentar&#8221; a linha <em>django.contrib.auth</em> na tupla <em>INSTALLED_APPS</em>, para que possamos utilizar a aplicação de autenticação nativa do Django.</p>
<p>Agora nosso ambiente está devidamente configurado, podemos iniciar uma nova aplicação Django e começar a codar. A forma de iniciar a aplicação é a mesma de sempre (daqui pra frente, tudo se parecerá naturalmente Django): basta rodar o startapp.</p>
<pre>$ ./manage.py startapp core</pre>
<p>Criamos a aplicação principal do projeto, chamada <em>core</em>. É criado o diretório da aplicação com os módulos Python &#8220;normais&#8221;: <em>models</em>, <em>views</em> e <em>tests</em>. Vamos então criar o model Post. Note que tudo está em inglês, pois esta aplicação foi desenvolvida em inglês :) Eis o código do módulo <em>models.py</em>, com a classe Post:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">db</span> <span style="color: #ff7700;font-weight:bold;">import</span> models<br />
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">contrib</span>.<span style="color: black;">auth</span>.<span style="color: black;">models</span> <span style="color: #ff7700;font-weight:bold;">import</span> User<br />
<br />
<span style="color: #ff7700;font-weight:bold;">class</span> Post<span style="color: black;">&#40;</span>models.<span style="color: black;">Model</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; title = models.<span style="color: black;">CharField</span><span style="color: black;">&#40;</span>max_length = <span style="color: #ff4500;">200</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; content = models.<span style="color: black;">TextField</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; date = models.<span style="color: black;">DateTimeField</span><span style="color: black;">&#40;</span>auto_now_add = <span style="color: #008000;">True</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #dc143c;">user</span> = models.<span style="color: black;">ForeignKey</span><span style="color: black;">&#40;</span>User<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Agora basta instalar a aplicação <em>core</em> colocando-a dentro da tupla <em>INSTALLED_APPS</em> no arquivo <em>settings.py</em>. Como vamos utilizar a aplicação de autenticação do Django, vamos criar um usuário de administração (super-usuário) para gerenciar toda a bagunça:</p>
<pre>$ ./manage.py createsuperuser</pre>
<p>Após informar o nome de usuário, o e-mail e a senha, o usuário estará criado no banco de dados. Agora vamos fazer nossa aplicação estar preparada para fazer login e logout. Primeiro, vamos mapear as URLs de login e logout no arquivos <em>urls.py</em>:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span>.<span style="color: black;">urls</span>.<span style="color: black;">defaults</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span><br />
<br />
urlpatterns = patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span><span style="color: #483d8b;">'^$'</span>, <span style="color: #483d8b;">'django.views.generic.simple.direct_to_template'</span>,<br />
&nbsp; &nbsp; &nbsp;<span style="color: black;">&#123;</span><span style="color: #483d8b;">'template'</span>: <span style="color: #483d8b;">'home.html'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>,<br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span><span style="color: #483d8b;">'^login/$'</span>, <span style="color: #483d8b;">'django.contrib.auth.views.login'</span><span style="color: black;">&#41;</span>,<br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span><span style="color: #483d8b;">'^logout/$'</span>, <span style="color: #483d8b;">'django.contrib.auth.views.logout'</span><span style="color: black;">&#41;</span>,<br />
<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Note as linhas 6 e 7, onde as URLs são mapeadas. Você pode também conferir os códigos dos templates <a href="http://gist.github.com/502967" target="_blank" rel="nofollow" title="Template login.html">registration/login.html</a> e <a href="http://gist.github.com/502969" rel="nofollow" target="_blank" title="Template logged_out.html">registration/logged_out.html</a>. Finalmente, basta adicionar três linhas ao <em>settings.py</em>:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">LOGIN_URL = <span style="color: #483d8b;">'/login/'</span><br />
LOGOUT_URL = <span style="color: #483d8b;">'/logout/'</span><br />
LOGIN_REDIRECT_URL = <span style="color: #483d8b;">'/'</span></div></td></tr></tbody></table></div>
<p>Agora as URLs de login e logout já estão prontas para voar, podemos criar nossas views de cadastro e listagem dos posts. Vamos primeiro criar a view de cadastro, que contará com um formulário composto pelos campos <em>title</em> (título) e <em>content</em> (conteúdo). Será um <em>ModelForm</em> atrelado ao modelo <em>Post</em>. Além dos campos title e content, o atributo <em>user</em> do modelo Post será preenchido automaticamente com o usuário logado. Eis o código completo do formulário:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">class</span> PostForm<span style="color: black;">&#40;</span>forms.<span style="color: black;">ModelForm</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">class</span> Meta:<br />
&nbsp; &nbsp; &nbsp; &nbsp; model = Post<br />
&nbsp; &nbsp; &nbsp; &nbsp; exclude = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'user'</span>,<span style="color: black;">&#41;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> save<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #dc143c;">user</span>, commit = <span style="color: #008000;">True</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; post = <span style="color: #008000;">super</span><span style="color: black;">&#40;</span>PostForm, <span style="color: #008000;">self</span><span style="color: black;">&#41;</span>.<span style="color: black;">save</span><span style="color: black;">&#40;</span>commit = <span style="color: #008000;">False</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; post.<span style="color: #dc143c;">user</span> = <span style="color: #dc143c;">user</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> commit:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; post.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> post</div></td></tr></tbody></table></div>
<p>Agora basta criar a <em>view</em> para cadastro de um post. Vamos criar também a <em>view</em> de listagem com um simples redirecionamento para que as coisas funcionem bem aqui. Eis o código do módulo <em>views.py</em>:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">contrib</span>.<span style="color: black;">auth</span>.<span style="color: black;">decorators</span> <span style="color: #ff7700;font-weight:bold;">import</span> login_required<br />
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">shortcuts</span> <span style="color: #ff7700;font-weight:bold;">import</span> render_to_response<br />
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">template</span> <span style="color: #ff7700;font-weight:bold;">import</span> RequestContext<br />
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">http</span> <span style="color: #ff7700;font-weight:bold;">import</span> HttpResponseRedirect<br />
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">core</span>.<span style="color: black;">urlresolvers</span> <span style="color: #ff7700;font-weight:bold;">import</span> reverse<br />
<span style="color: #ff7700;font-weight:bold;">from</span> forms <span style="color: #ff7700;font-weight:bold;">import</span> PostForm<br />
<br />
@login_required<br />
<span style="color: #ff7700;font-weight:bold;">def</span> new_post<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; form = PostForm<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> request.<span style="color: black;">method</span> == <span style="color: #483d8b;">'POST'</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; form = PostForm<span style="color: black;">&#40;</span>request.<span style="color: black;">POST</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> form.<span style="color: black;">is_valid</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; form.<span style="color: black;">save</span><span style="color: black;">&#40;</span>request.<span style="color: #dc143c;">user</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponseRedirect<span style="color: black;">&#40;</span>reverse<span style="color: black;">&#40;</span><span style="color: #483d8b;">'core.views.list_posts'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> render_to_response<span style="color: black;">&#40;</span><span style="color: #483d8b;">'new_post.html'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">locals</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, context_instance=RequestContext<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: black;">&#41;</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> list_posts<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponseRedirect<span style="color: black;">&#40;</span><span style="color: #483d8b;">'/'</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Agora, para que a <em>view</em> <em>new_post</em> funcione, precisamos apenas mapear as duas <em>views</em> acima para suas respectivas URLs, e criar o template <em>new_post.html</em>. Eis o mapeamento de URLs:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: black;">&#40;</span><span style="color: #483d8b;">'^posts/new/$'</span>, <span style="color: #483d8b;">'core.views.new_post'</span><span style="color: black;">&#41;</span>,<br />
<span style="color: black;">&#40;</span><span style="color: #483d8b;">'^posts/$'</span>, <span style="color: #483d8b;">'core.views.list_posts'</span><span style="color: black;">&#41;</span>,</div></td></tr></tbody></table></div>
<p>Confira também o template <a href="http://gist.github.com/502976" rel="nofollow" title="Template new_post.html" target="_blank">new_post.html</a>.</p>
<p>Finalmente já podemos ver alguma coisa através do navegador. Rodando o comando <em>./manage.py runserver</em> no terminal temos o servidor inicializado, então é possível acessar a URL <em>http://localhost:8000/posts/new</em> no navegador para ver um formulário de cadastro de posts, onde os posts podem ser escritos e salvos (lembre-se apenas que é necessário efetuar login para acessar esta <em>view</em>). Agora, precisamos apenas listar todos os posts na URL <em>/posts/</em>. A <em>view</em> <em>list_posts</em> já está mapeada para a URL <em>/posts/</em>, então a única coisa a fazer é escrever o código da <em>view</em>, que lista todos os posts do banco de dados e envia para um template:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> list_posts<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; posts = Post.<span style="color: black;">objects</span>.<span style="color: #008000;">all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> render_to_response<span style="color: black;">&#40;</span><span style="color: #483d8b;">'list_posts.html'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">locals</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, context_instance=RequestContext<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Confira o template <a href="http://gist.github.com/502981" rel="nofollow" title="Template list_posts.html" target="_blank">list_posts.html</a>. Finalmente nossa aplicação está pronta para o deploy, mas como fazemos isso? De uma maneira muito difícil:</p>
<pre>$ ./manage.py deploy</pre>
<p>Pronto, aplicação em produção :) Para poder ter acesso como usuário na aplicação, basta apenas rodar o comando para criar o usuário remotamente:</p>
<pre>$ ./manage.py remote createsuperuser</pre>
<p>Você pode ver esta aplicação voando neste link: <a href="http://1.latest.gaeseries.appspot.com/" rel="nofollow" target="_blank" title="Veja a aplicação voando no Google App Engine">http://1.latest.gaeseries.appspot.com/</a> (para logar-se no sistema, utilize o nome de usuário <strong>demo</strong> com a senha <strong>demo</strong>)</p>
<p>E também ver o código fonte completo neste link: <a href="http://github.com/franciscosouza/gaeseries/tree/django" rel="nofollow" target="_blank" title="Código fonte da aplicação">http://github.com/franciscosouza/gaeseries/tree/django</a></p>
<p>Nos vemos na próxima parte ;)</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2010/08/02/voando-com-o-django-no-google-app-engine/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>II Liberdade Interativa</title>
		<link>http://www.franciscosouza.com.br/2010/07/29/ii-liberdade-interativa/</link>
		<comments>http://www.franciscosouza.com.br/2010/07/29/ii-liberdade-interativa/#comments</comments>
		<pubDate>Fri, 30 Jul 2010 00:59:24 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[eventos]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.franciscosouza.com.br/?p=1081</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.tux-es.org/liberdadeinterativa/" rel="nofollow" target="_blank" title="II Liberdade Interativa"><img class="alignleft size-full wp-image-1087" title="II Liberdade Interativa" src="http://img.franciscosouza.com.br/2010/07/scale_li.png" alt="II Liberdade Interativa" width="664" height="939" /></a></p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2010/07/29/ii-liberdade-interativa/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Atividades em Agosto</title>
		<link>http://www.franciscosouza.com.br/2010/07/19/atividades-em-agosto/</link>
		<comments>http://www.franciscosouza.com.br/2010/07/19/atividades-em-agosto/#comments</comments>
		<pubDate>Mon, 19 Jul 2010 15:13:01 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[desenvolvimento de softwares]]></category>
		<category><![CDATA[agile]]></category>
		<category><![CDATA[comunidade]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[eventos]]></category>
		<category><![CDATA[palestras]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[scrum]]></category>

		<guid isPermaLink="false">http://www.franciscosouza.com.br/?p=1074</guid>
		<description><![CDATA[Agosto se aproxima e com ele alguns eventos bacanas de informática no Espírito Santo. No dia 19 de agosto, acontecerá o II Liberdade Interativa, na Faesa da Av. Vitória. Na ocasião, apresentarei a palestra &#8220;Django: o framework web para perfeccionistas &#8230; <a href="http://www.franciscosouza.com.br/2010/07/19/atividades-em-agosto/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><img class="alignright" title="Django" src="http://img.franciscosouza.com.br/2010/07/Django1.png" alt="Django" width="208" height="94" />Agosto se aproxima e com ele alguns eventos bacanas de informática no Espírito Santo. No dia 19 de agosto, acontecerá o <a title="Liberdade Interativa" rel="nofollow" href="http://www.tux-es.org/liberdadeinterativa/" target="_blank">II Liberdade Interativa</a>, na <a title="Faesa" rel="nofollow" href="http://site.faesa.br/" target="_blank">Faesa da Av. Vitória</a>. Na ocasião, apresentarei a palestra &#8220;Django: o framework web para perfeccionistas com prazos&#8221;.</p>
<p>A programação completa do II Liberdade Interativa é a seguinte:</p>
<ul>
<li><strong>19h00:</strong> Bacula &#8211; O backup da meia-noite (<a title="Rapha" rel="nofollow" href="http://www.rapha.net.br" target="_blank">Raphaela M. Rocha</a>);</li>
<li><strong>19h50:</strong> Django: O framework web para perfeccionistas com prazos (<a title="Francisco Souza" rel="nofollow" href="http://twitter.com/franciscosouza" target="_blank">Francisco Souza</a>);</li>
<li><strong>20h40:</strong> Iptables: Entendendo como fazer um firewall pessoal (<a title="Almir M3nd3s" rel="nofollow" href="http://www.almirmendes.net" target="_blank">Almir M3nd3s</a>)</li>
</ul>
<p>O evento acontecerá no mini-auditório da Faesa da Av. Vitória, no dia 19 de agosto de 2010 e começará às 19 horas. A inscrição será feita &#8220;na hora&#8221;, então não é necessário fazer inscrição previamente, basta aparecer :)</p>
<p><img class="alignleft size-full wp-image-1078" title="codeigniter" src="http://img.franciscosouza.com.br/2010/07/codeigniter.png" alt="CodeIgniter" width="77" height="106" />Já no dia 28 de agosto, acontecerá o <a title="II Workshop de PHP do Espírito Santo" rel="nofollow" href="http://www.phpes.org/ii-workshop-php-es/" target="_blank">II Workshop de PHP do Espírito Santo</a> na <a title="UVV" rel="nofollow" href="http://www.uvv.br" target="_blank">UVV</a>, em Vila Velha. Neste evento eu apresentarei junto ao colega de trabalho <a title="André Tagliati" rel="nofollow" href="http://www.tagliati.com.br" target="_blank">André Tagliati</a> a palestra &#8220;CodeIgniter: turbinando a produtividade com MVC&#8221; e junto ao time da Giran um hands-on de Scrum entitulado &#8220;Aprendendo a começar um projeto com Scrum&#8221;.</p>
<p>A programação completa do II Workshop de PHP do Espírito Santo é a seguinte:</p>
<ul>
<li><strong>09h10:</strong> PHPZeiro: Adote um framework! (<a title="Leo Hackin" rel="nofollow" href="http://www.leohackin.com.br" target="_blank">Leo &#8220;Hackin&#8221;</a>)</li>
<li><strong>10h10:</strong> CodeIgniter: Turbinando a produtividade com MVC (<a title="Francisco Souza" href="http://www.franciscosouza.net" target="_blank">Francisco Souza</a> e <a title="André Tagliati" rel="nofollow" href="http://twitter.com/tagliati" target="_blank">André Tagliati</a>)</li>
<li><strong>11h10:</strong> Técnicas simples e eficazes para tirar o máximo do seu servidor MySQL (<a title="Marcelo Raposo" rel="nofollow" href="http://twitter.com/mmqraposo" target="_blank">Marcelo Raposo</a>)</li>
<li><strong>14h00:</strong> PHP Data Object &#8211; Interface Única de Comunicação com SGBDs (<a title="Almir M3nd3s" rel="nofollow" href="http://twitter.com/m3nd3s" target="_blank">Almir M3nd3s</a>)</li>
<li><strong>15h10:</strong> Moodle: fazendo EAD de qualidade com PHP (<a title="Lucas Coradini" rel="nofollow" href="http://www.lucascoradini.com" target="_blank">Lucas Coradini</a>)</li>
<li><strong>16h10:</strong> Aprendendo a começar um projeto com Scrum (<a title="Time da Giran" rel="nofollow" href="http://www.giran.com.br/empresa/time" target="_blank">Time da Giran</a>)</li>
</ul>
<p>Neste caso, a inscrição é gratuita e obrigatória, e deve ser feita <a title="Formulário de inscrição no II Workshop de PHP do ES" rel="nofollow" href="http://spreadsheets.google.com/viewform?hl=en&amp;formkey=dHJibnkyZEs2VzhFNmhHYTEyYXRwV0E6MQ#gid=0" target="_blank">neste formulário</a>. O evento acontecerá no dia 28 de agosto, a partir da 8:30 na UVV, campus Boa Vista.</p>
<p>Será um mês de boas atividades, e eu espero ver muita gente em todas elas =P</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2010/07/19/atividades-em-agosto/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>BDD em Django: Desenvolvimento web mais divertido com qualidade usando Freshen</title>
		<link>http://www.franciscosouza.com.br/2010/06/24/bdd-em-django-desenvolvimento-web-mais-divertido-com-qualidade-usando-freshen/</link>
		<comments>http://www.franciscosouza.com.br/2010/06/24/bdd-em-django-desenvolvimento-web-mais-divertido-com-qualidade-usando-freshen/#comments</comments>
		<pubDate>Thu, 24 Jun 2010 12:23:49 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[desenvolvimento de softwares]]></category>
		<category><![CDATA[agile]]></category>
		<category><![CDATA[BDD]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[frameworks]]></category>
		<category><![CDATA[freshen]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[TDD]]></category>

		<guid isPermaLink="false">http://www.franciscosouza.com.br/?p=955</guid>
		<description><![CDATA[Freshen é um framework Python para construção de testes de aceitação, baseado no Cucumber e tem o mesmo objetivo do Cucumber: fazer o desenvolvimento de softwares com BDD mais divertido. Podemos aplicar os conceitos do BDD escrevendo testes de aceitação &#8230; <a href="http://www.franciscosouza.com.br/2010/06/24/bdd-em-django-desenvolvimento-web-mais-divertido-com-qualidade-usando-freshen/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Freshen é um framework Python para construção de testes de aceitação, baseado no <a title="Cucumber" rel="nofollow" href="http://cukes.info" target="_blank">Cucumber</a> e tem o mesmo objetivo do Cucumber: fazer o desenvolvimento de softwares com BDD mais divertido. Podemos aplicar os conceitos do BDD escrevendo testes de aceitação em alto nível e graças à integração com o Nose, podemos ainda usar testes unitários para testar unidades de código.<span id="more-955"></span></p>
<p>Este post tem como objetivo fazer uma apresentação básica do uso do Django com o Freshen. Antes de começar, vamos preparar as ferramentas necessárias :) Como o Freshen é um plugin do Nose, para utilizar o Freshen, precisamos do Nose. Já que vamos integrar o Django também no esquema, precisamos também adicionar um plugin para testar o Django, NoseDjango, e também o próprio Django. Por fim, para isolar os tests do banco de dados, um framework de Mock é uma boa pedida. Vamos utilizar o Ludibrio, que foi feito por brasileiros, é simples e bom o suficiente. Se você tem o PIP instalado, um simples comando instala tudo que nós precisamos:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> pip <span style="color: #c20cb9; font-weight: bold;">install</span> django nose nosedjango freshen ludibrio</div></td></tr></tbody></table></div>
<p>Agora que temos todas as ferramentas necessárias, podemos começar a trabalhar no nosso &#8220;sisteminha&#8221;. Nosso exemplo vai ser um delivery de medicamentos para a farmácia do tio-avô da ex-namorada do meu primo de segundo grau. Vamos implementar apenas uma funcionalidade, que será descrita em um arquivo de funcionalidade.</p>
<p>Primeiramente, vamos criar o projeto do Django para a farmácia:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ django-admin.py startproject farmacia</div></td></tr></tbody></table></div>
<p>Criado o projeto, vamos iniciar a aplicação <em>delivery</em>, que vai ser o que vamos testar:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ django-admin.py startapp delivery</div></td></tr></tbody></table></div>
<p>Não há muita coisa a ser configurada no projeto, vamos apenas configurar o banco de dados, definir o diretório dos templates (no projeto) e adicionar nossa aplicação ao <em>INSTALLED_APPS</em>:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">DATABASES = <span style="color: black;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #483d8b;">'default'</span>: <span style="color: black;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'ENGINE'</span>: <span style="color: #483d8b;">'django.db.backends.sqlite3'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'NAME'</span>: <span style="color: #483d8b;">'dados.db'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'USER'</span>: <span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'PASSWORD'</span>: <span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'HOST'</span>: <span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'PORT'</span>: <span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; <span style="color: black;">&#125;</span><br />
<span style="color: black;">&#125;</span><br />
<br />
<span style="color: #808080; font-style: italic;">#Outras configurações aqui...</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span><br />
ROOT = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">abspath</span><span style="color: black;">&#40;</span>__file__<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
TEMPLATE_DIRS = <span style="color: black;">&#40;</span><br />
&nbsp; &nbsp; <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>ROOT, <span style="color: #483d8b;">'templates'</span><span style="color: black;">&#41;</span>,<br />
<span style="color: black;">&#41;</span><br />
<br />
INSTALLED_APPS = <span style="color: black;">&#40;</span><br />
&nbsp; &nbsp; <span style="color: #483d8b;">'django.contrib.auth'</span>,<br />
&nbsp; &nbsp; <span style="color: #483d8b;">'django.contrib.contenttypes'</span>,<br />
&nbsp; &nbsp; <span style="color: #483d8b;">'django.contrib.sessions'</span>,<br />
&nbsp; &nbsp; <span style="color: #483d8b;">'django.contrib.sites'</span>,<br />
&nbsp; &nbsp; <span style="color: #483d8b;">'django.contrib.messages'</span>,<br />
&nbsp; &nbsp; <span style="color: #483d8b;">'delivery'</span>,<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Uncomment the next line to enable the admin:</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># 'django.contrib.admin',</span><br />
<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Agora que temos nosso projeto iniciado e configurado, com nossa aplicação iniciada e instalada, vamos começar a desenvolver, mas primeiro vamos escrever as funcionalidades do Freshen. As funcionalidades do Freshen são compostas por cenários que por sua vez são compostos por passos. As funcionalidades de um sistema são definidas dentro de arquivos de funcionalidades. Vamos criar a funcionalidade Listar remédios, que será a listagem de remédios para serem selecionados para compra e entrega.</p>
<p>Vamos criar dentro da aplicação <em>delivery</em> um diretório chamado <em>features</em> e dentro deste diretório criaremos o arquivo listar_remedios.feature, com o seguinte conteúdo:</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Funcionalidade: Listar remédios<br />
&nbsp; &nbsp; Para poder comprar um remédio<br />
&nbsp; &nbsp; Como um usuário do sistema<br />
&nbsp; &nbsp; Eu gostaria de ver uma lista contendo os remédios para eu escolher<br />
<br />
&nbsp; &nbsp; Cenário: Listando todos os remédios<br />
&nbsp; &nbsp; &nbsp; &nbsp; Dado que existem 10 remédios cadastrados no banco de dados<br />
&nbsp; &nbsp; &nbsp; &nbsp; Quando eu vou para a página de listagem de remédios<br />
&nbsp; &nbsp; &nbsp; &nbsp; Então eu deveria ver a listagem com o nome dos 10 remédios</div></td></tr></tbody></table></div>
<p>O &#8220;código&#8221; da funcionalidade é totalmente simples: a funcionalidade tem um nome, no nosso caso &#8220;Listar remédios&#8221;, um cabeçalho, que é uma descrição livre da funcionalidade (você realmente pode escrever o que quiser no cabeçalho). Para cada história, definimos cenários, utilizando a palavra chave &#8220;Cenário:&#8221;. O cenário é composto por um nome e alguns passos, definidos pelas palavras-chave Given, When, Then, And e But (em português: Dado, Quando, Então, E e Mas). Para entender mais a organização do BDD e a definição de funcionalidades, cenários e passos, dê uma olhada em algum <a title="Behaviour-Driven Development" rel="nofollow" href="http://pt.wikipedia.org/wiki/Behavior_Driven_Development" target="_blank">material sobre BDD</a> (vastidão de material apenas em inglês =P).</p>
<p>Após criar a funcionalidade e o cenário, temos que definir os passos do nosso cenário. O cenário <em>&#8220;Listando todos os remédios&#8221;</em> possui três passos: <em>&#8220;Dado que existem 10 remédios cadastrados no banco de dados&#8221;</em>, <em>&#8220;Quando eu vou para a página de listagem de remédios&#8221;</em> e <em>&#8220;Então eu deveria ver a listagem com o nome dos 10 remédios&#8221;</em>. Precisamos definir o que o Freshen fará em cada um desses passos para garantir o funcionamento da funcionalidade especificada.</p>
<p>Vamos rodar o Freshen, para ver a saída neste momento. Quem sabe nosso teste passa sem fazermos nada =D</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ nosetests <span style="color: #660033;">--with-freshen</span> <span style="color: #660033;">--with-django</span> <span style="color: #660033;">--language</span>=pt <span style="color: #660033;">-v</span><br />
Listar remédios: Listando todos os remédios ... UNDEFINED: <span style="color: #000000; font-weight: bold;">&amp;</span>quot;que existem <span style="color: #000000;">10</span> remédios cadastrados no banco de dados<span style="color: #000000; font-weight: bold;">&amp;</span>quot; <span style="color: #666666; font-style: italic;"># delivery/features/listar_remedios.feature:7</span><br />
Tests that <span style="color: #000000;">1</span> + <span style="color: #000000;">1</span> always equals <span style="color: #000000;">2</span>. ... ok<br />
<span style="color: #660033;">----------------------------------------------------------------------</span><br />
Ran <span style="color: #000000;">2</span> tests <span style="color: #000000; font-weight: bold;">in</span> 0.175s<br />
OK <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">UNDEFINED</span>=<span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
Destroying <span style="color: #7a0874; font-weight: bold;">test</span> database <span style="color: #ff0000;">'default'</span>...</div></td></tr></tbody></table></div>
<p>Vamos entender o comando executado: executamos o comando <strong>nosetests</strong>, que é o comando do Nose. Como o Freshen é um plugin do Nose, precisamos habilitá-lo utilizando a opção <strong>&#8211;with-freshen</strong>, e habilitamos o Django com a opção <strong>&#8211;with-django</strong>. Uma vez que escrevemos nossa funcionalidade em Português, temos que avisar ao Freshen que ele deve lê-la em português, por isso utilizamos a opção <strong>&#8211;language=pt</strong>. Por fim, utilizamos a opção <strong>-v</strong> para habilitar o modo verbose.</p>
<p>Agora, vamos entender a saída do comando: veja na primeira linha, que o Freshen encontrou funcionalidade &#8220;Listar remédios&#8221;, e dentro desta funcionalidade encontrou o cenário &#8220;Listando todos os remédios&#8221; com o passo &#8220;que existem 10 remédios cadastrados no banco de dados&#8221; indefinido. Então, vamos definir tal passo e executar o teste novamente. Os passos são definidos em um módulo chamado steps.py presente no mesmo diretório do arquivo da funcionalidade (features, dentro da aplicação).</p>
<p>Para definir os passos, utilizamos decorators correspondentes a estes passos: para o passo Given/Dado, utilizamos o decorator @Given; para o passo When/Quando, utilizanmos o decorator @When; e para o passo Then/Então, utilizamos o decorator @Then. Vamos definir nosso primeiro passo, utilizando o decorator @Given, e ver o que acontece ao executar o Freshen novamente após tal definição:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">@Given<span style="color: black;">&#40;</span><span style="color: #483d8b;">'que existem (<span style="color: #000099; font-weight: bold;">\\</span>d+) remédios cadastrados no banco de dados'</span><span style="color: black;">&#41;</span><br />
<span style="color: #ff7700;font-weight:bold;">def</span> gravar_remedios<span style="color: black;">&#40;</span>quantidade_remedios<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; scc.<span style="color: black;">remedios</span> = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span><span style="color: #008000;">int</span><span style="color: black;">&#40;</span>quantidade_remedios<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; remedio = Remedio<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; remedio.<span style="color: black;">nome</span> = <span style="color: #483d8b;">'Remédio %d'</span> <span style="color: #66cc66;">%</span><span style="color: black;">&#40;</span>i + <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; scc.<span style="color: black;">remedios</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span>remedio<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Note que nós recebemos um parâmetro para nossa função a partir do texto que define o passo. O formato deste parâmetro é definido por uma expressão regular. Atenção: o parâmetro passado para a função sempre é uma string, se você precisar trabalhar este parâmetro como um inteiro, ele deverá ser convertido (como aconteceu no nosso caso).</p>
<p>Na função acima, nós criamos uma lista chamada <em>remedios</em> dentro de um objeto chamado <em>scc</em>. Trata-se do contexto de armazenamento de objetos do Freshen. O Freshen da suporte a três tipos de contexto: <em>glc</em>, o contexto global, que nunca é apagado; <em>ftc</em>, o contexto de funcionalidade, que é apagado no início da execução de cada funcionalidade; e o <em>scc</em>, que é o contexto de cenário, apagado no início da execução de cada cenário. Quando armazenamos nossa lista de remédios dentro do contexto de cenário, significa que esta lista estará disponível em todos os passos deste cenário.</p>
<p>Agora, vamos executar novamente o Freshen para ver o que acontece:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ nosetests <span style="color: #660033;">--with-freshen</span> <span style="color: #660033;">--with-django</span> <span style="color: #660033;">--language</span>=pt <span style="color: #660033;">-v</span><br />
Listar remédios: Listando todos os remédios ... ERROR<br />
Tests that <span style="color: #000000;">1</span> + <span style="color: #000000;">1</span> always equals <span style="color: #000000;">2</span>. ... ok<br />
======================================================================<br />
ERROR: Listar remédios: Listando todos os remédios<br />
<span style="color: #660033;">----------------------------------------------------------------------</span><br />
Traceback <span style="color: #7a0874; font-weight: bold;">&#40;</span>most recent call <span style="color: #c20cb9; font-weight: bold;">last</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:<br />
&nbsp; File <span style="color: #000000; font-weight: bold;">&amp;</span>quot;<span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>francisco<span style="color: #000000; font-weight: bold;">/</span>Projetos<span style="color: #000000; font-weight: bold;">/</span>blog<span style="color: #000000; font-weight: bold;">/</span>farmacia<span style="color: #000000; font-weight: bold;">/</span>delivery<span style="color: #000000; font-weight: bold;">/</span>features<span style="color: #000000; font-weight: bold;">/</span>steps.py<span style="color: #000000; font-weight: bold;">&amp;</span>quot;, line <span style="color: #000000;">9</span>, <span style="color: #000000; font-weight: bold;">in</span> gravar_remedios<br />
&nbsp; &nbsp; remedio = Remedio<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
NameError: global name <span style="color: #ff0000;">'Remedio'</span> is not defined<br />
<span style="color: #000000; font-weight: bold;">&amp;</span>gt;<span style="color: #000000; font-weight: bold;">&amp;</span>gt; <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #000000; font-weight: bold;">&amp;</span>quot;que existem <span style="color: #000000;">10</span> remédios cadastrados no banco de dados<span style="color: #000000; font-weight: bold;">&amp;</span>quot; <span style="color: #666666; font-style: italic;"># delivery/features/listar_remedios.feature:7</span><br />
<span style="color: #660033;">----------------------------------------------------------------------</span><br />
Ran <span style="color: #000000;">2</span> tests <span style="color: #000000; font-weight: bold;">in</span> 0.162s<br />
FAILED <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">errors</span>=<span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
Destroying <span style="color: #7a0874; font-weight: bold;">test</span> database <span style="color: #ff0000;">'default'</span>...</div></td></tr></tbody></table></div>
<p>E o feedback obtido foi: não encontrei esse classe Remedio. Isto ocorre por que nós não definimos nosso model Remedio. Então, vamos definí-lo, com apenas um nome, dentro do módulo <em>models.py</em> da aplicação <em>delivery</em>, e executar novamente o teste:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">db</span> <span style="color: #ff7700;font-weight:bold;">import</span> models<br />
<span style="color: #ff7700;font-weight:bold;">class</span> Remedio<span style="color: black;">&#40;</span>models.<span style="color: black;">Model</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; nome = models.<span style="color: black;">CharField</span><span style="color: black;">&#40;</span>max_length=<span style="color: #ff4500;">255</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Agora, vamos novamente rodar nossos testes e ver o que acontece:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ nosetests <span style="color: #660033;">--with-freshen</span> <span style="color: #660033;">--with-django</span> <span style="color: #660033;">--language</span>=pt <span style="color: #660033;">-v</span><br />
Listar remédios: Listando todos os remédios ... UNDEFINED: <span style="color: #000000; font-weight: bold;">&amp;</span>quot;eu vou para a página de listagem de remédios<span style="color: #000000; font-weight: bold;">&amp;</span>quot; <span style="color: #666666; font-style: italic;"># delivery/features/listar_remedios.feature:8</span><br />
Tests that <span style="color: #000000;">1</span> + <span style="color: #000000;">1</span> always equals <span style="color: #000000;">2</span>. ... ok<br />
<br />
<span style="color: #660033;">----------------------------------------------------------------------</span><br />
Ran <span style="color: #000000;">2</span> tests <span style="color: #000000; font-weight: bold;">in</span> 0.198s<br />
<br />
OK <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">UNDEFINED</span>=<span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
Destroying <span style="color: #7a0874; font-weight: bold;">test</span> database <span style="color: #ff0000;">'default'</span>...</div></td></tr></tbody></table></div>
<p>Nossa definição de passo agora passou, porém recebemos o feedback de outro passo indefinido: &#8220;eu vou para a página de listagem de remédios&#8221;. Vamos então definir este passo, utilizando o decorator @When:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">@When<span style="color: black;">&#40;</span><span style="color: #483d8b;">'eu vou para a página de listagem de remédios'</span><span style="color: black;">&#41;</span><br />
<span style="color: #ff7700;font-weight:bold;">def</span> visitar_pagina_listagem<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">with</span> Mock<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> delivery:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">from</span> delivery.<span style="color: black;">models</span> <span style="color: #ff7700;font-weight:bold;">import</span> Remedio<br />
&nbsp; &nbsp; &nbsp; &nbsp; Remedio.<span style="color: black;">objects</span>.<span style="color: #008000;">all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;&gt;</span> scc.<span style="color: black;">remedios</span><br />
&nbsp; &nbsp; client = Client<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; scc.<span style="color: black;">response</span> = client.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/delivery/remedios'</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; delivery.<span style="color: black;">validate</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Vamos entender o que foi feito aqui: o método começa fazendo um mock da aplicação do Django, tudo isso para garantir o mock interno do model. Assim, separamos nossa definição do banco de dados: quando o método Remedio.objects.all() for chamado, o objeto de mock, gerenciado pelo Ludibrio, retornará a nossa lista de remédios armazenadas no contexto do cenário. Pulando um pouco, na última linha da função validamos o nosso mock, ou seja, verificamos se o comportamento que esperávamos dele realmente aconteceu. Traduzindo: esta última linha garante que o método realmente foi invocado, mas onde?</p>
<p>Na linha superior, utilizamos o <a title="Making requests in Django testing" rel="nofollow" href="http://docs.djangoproject.com/en/dev/topics/testing/#making-requests" target="_blank">Client do Django</a> para fazer uma requisição do tipo GET na URL &#8216;/delivery/models&#8217; do nosso projeto. A resposta desta requisição é armazenada dentro do nosso contexto de cenário, em um objeto chamado <em>response</em>. Vamos novamente executar o Freshen e ver o que acontece:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ nosetests <span style="color: #660033;">--with-freshen</span> <span style="color: #660033;">--with-django</span> <span style="color: #660033;">--language</span>=pt <span style="color: #660033;">-v</span><br />
Listar remédios: Listando todos os remédios ... ERROR<br />
Tests that <span style="color: #000000;">1</span> + <span style="color: #000000;">1</span> always equals <span style="color: #000000;">2</span>. ... ok<br />
<br />
======================================================================<br />
ERROR: Listar remédios: Listando todos os remédios<br />
<span style="color: #660033;">----------------------------------------------------------------------</span><br />
Traceback <span style="color: #7a0874; font-weight: bold;">&#40;</span>most recent call <span style="color: #c20cb9; font-weight: bold;">last</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:<br />
&nbsp; File <span style="color: #000000; font-weight: bold;">&amp;</span>quot;<span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>francisco<span style="color: #000000; font-weight: bold;">/</span>Projetos<span style="color: #000000; font-weight: bold;">/</span>blog<span style="color: #000000; font-weight: bold;">/</span>farmacia<span style="color: #000000; font-weight: bold;">/</span>delivery<span style="color: #000000; font-weight: bold;">/</span>features<span style="color: #000000; font-weight: bold;">/</span>steps.py<span style="color: #000000; font-weight: bold;">&amp;</span>quot;, line <span style="color: #000000;">22</span>, <span style="color: #000000; font-weight: bold;">in</span> visitar_pagina_listagem<br />
&nbsp; &nbsp; scc.response = client.get<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">'/delivery/remedios'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
&nbsp; File <span style="color: #000000; font-weight: bold;">&amp;</span>quot;<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>python2.6<span style="color: #000000; font-weight: bold;">/</span>dist-packages<span style="color: #000000; font-weight: bold;">/</span>django<span style="color: #000000; font-weight: bold;">/</span>test<span style="color: #000000; font-weight: bold;">/</span>client.py<span style="color: #000000; font-weight: bold;">&amp;</span>quot;, line <span style="color: #000000;">290</span>, <span style="color: #000000; font-weight: bold;">in</span> get<br />
&nbsp; &nbsp; response = self.request<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000; font-weight: bold;">**</span>r<span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
&nbsp; File <span style="color: #000000; font-weight: bold;">&amp;</span>quot;<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>python2.6<span style="color: #000000; font-weight: bold;">/</span>dist-packages<span style="color: #000000; font-weight: bold;">/</span>django<span style="color: #000000; font-weight: bold;">/</span>core<span style="color: #000000; font-weight: bold;">/</span>handlers<span style="color: #000000; font-weight: bold;">/</span>base.py<span style="color: #000000; font-weight: bold;">&amp;</span>quot;, line <span style="color: #000000;">127</span>, <span style="color: #000000; font-weight: bold;">in</span> get_response<br />
&nbsp; &nbsp; <span style="color: #7a0874; font-weight: bold;">return</span> callback<span style="color: #7a0874; font-weight: bold;">&#40;</span>request, <span style="color: #000000; font-weight: bold;">**</span>param_dict<span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
&nbsp; File <span style="color: #000000; font-weight: bold;">&amp;</span>quot;<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>python2.6<span style="color: #000000; font-weight: bold;">/</span>dist-packages<span style="color: #000000; font-weight: bold;">/</span>django<span style="color: #000000; font-weight: bold;">/</span>views<span style="color: #000000; font-weight: bold;">/</span>defaults.py<span style="color: #000000; font-weight: bold;">&amp;</span>quot;, line <span style="color: #000000;">13</span>, <span style="color: #000000; font-weight: bold;">in</span> page_not_found<br />
&nbsp; &nbsp; t = loader.get_template<span style="color: #7a0874; font-weight: bold;">&#40;</span>template_name<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #666666; font-style: italic;"># You need to create a 404.html template.</span><br />
&nbsp; File <span style="color: #000000; font-weight: bold;">&amp;</span>quot;<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>python2.6<span style="color: #000000; font-weight: bold;">/</span>dist-packages<span style="color: #000000; font-weight: bold;">/</span>django<span style="color: #000000; font-weight: bold;">/</span>template<span style="color: #000000; font-weight: bold;">/</span>loader.py<span style="color: #000000; font-weight: bold;">&amp;</span>quot;, line <span style="color: #000000;">157</span>, <span style="color: #000000; font-weight: bold;">in</span> get_template<br />
&nbsp; &nbsp; template, origin = find_template<span style="color: #7a0874; font-weight: bold;">&#40;</span>template_name<span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
&nbsp; File <span style="color: #000000; font-weight: bold;">&amp;</span>quot;<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>python2.6<span style="color: #000000; font-weight: bold;">/</span>dist-packages<span style="color: #000000; font-weight: bold;">/</span>django<span style="color: #000000; font-weight: bold;">/</span>template<span style="color: #000000; font-weight: bold;">/</span>loader.py<span style="color: #000000; font-weight: bold;">&amp;</span>quot;, line <span style="color: #000000;">138</span>, <span style="color: #000000; font-weight: bold;">in</span> find_template<br />
&nbsp; &nbsp; raise TemplateDoesNotExist<span style="color: #7a0874; font-weight: bold;">&#40;</span>name<span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
TemplateDoesNotExist: <span style="color: #000000;">404</span>.html<br />
<br />
<span style="color: #000000; font-weight: bold;">&amp;</span>gt;<span style="color: #000000; font-weight: bold;">&amp;</span>gt; <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #000000; font-weight: bold;">&amp;</span>quot;eu vou para a página de listagem de remédios<span style="color: #000000; font-weight: bold;">&amp;</span>quot; <span style="color: #666666; font-style: italic;"># delivery/features/listar_remedios.feature:8</span><br />
<br />
<span style="color: #660033;">----------------------------------------------------------------------</span><br />
Ran <span style="color: #000000;">2</span> tests <span style="color: #000000; font-weight: bold;">in</span> 0.370s<br />
<br />
FAILED <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">errors</span>=<span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
Destroying <span style="color: #7a0874; font-weight: bold;">test</span> database <span style="color: #ff0000;">'default'</span>...</div></td></tr></tbody></table></div>
<p>E a resposta do Freshen ao nosso teste foi: Não encontrei o template 404.html! Nada a ver com nosso teste, certo? Acontece que, na verdade, a URL /delivery/remedios não foi encontrada e o Django tenta renderizar o template 404.html nestes casos, mas não importa isso no momento. Nosso desejo aqui é fazer a definição de passo passar, então vamo simplesmente colocar um arquivo chamado 404.html dentro do nosso diretório de templates, chamar o Freshen novamente e ver o que acontece:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ <span style="color: #c20cb9; font-weight: bold;">mkdir</span> templates<br />
francisco<span style="color: #000000; font-weight: bold;">@</span>radukibook ~<span style="color: #000000; font-weight: bold;">/</span>Projetos<span style="color: #000000; font-weight: bold;">/</span>blog<span style="color: #000000; font-weight: bold;">/</span>farmacia <span style="color: #7a0874; font-weight: bold;">&#40;</span>master<span style="color: #7a0874; font-weight: bold;">&#41;</span> $ <span style="color: #c20cb9; font-weight: bold;">touch</span> templates<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">404</span>.html<br />
francisco<span style="color: #000000; font-weight: bold;">@</span>radukibook ~<span style="color: #000000; font-weight: bold;">/</span>Projetos<span style="color: #000000; font-weight: bold;">/</span>blog<span style="color: #000000; font-weight: bold;">/</span>farmacia <span style="color: #7a0874; font-weight: bold;">&#40;</span>master<span style="color: #7a0874; font-weight: bold;">&#41;</span> $ nosetests <span style="color: #660033;">--with-freshen</span> <span style="color: #660033;">--with-django</span> <span style="color: #660033;">--language</span>=pt <span style="color: #660033;">-v</span><br />
Listar remédios: Listando todos os remédios ... FAIL<br />
Tests that <span style="color: #000000;">1</span> + <span style="color: #000000;">1</span> always equals <span style="color: #000000;">2</span>. ... ok<br />
<br />
======================================================================<br />
FAIL: Listar remédios: Listando todos os remédios<br />
<span style="color: #660033;">----------------------------------------------------------------------</span><br />
Traceback <span style="color: #7a0874; font-weight: bold;">&#40;</span>most recent call <span style="color: #c20cb9; font-weight: bold;">last</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:<br />
&nbsp; File <span style="color: #000000; font-weight: bold;">&amp;</span>quot;<span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>francisco<span style="color: #000000; font-weight: bold;">/</span>Projetos<span style="color: #000000; font-weight: bold;">/</span>blog<span style="color: #000000; font-weight: bold;">/</span>farmacia<span style="color: #000000; font-weight: bold;">/</span>delivery<span style="color: #000000; font-weight: bold;">/</span>features<span style="color: #000000; font-weight: bold;">/</span>steps.py<span style="color: #000000; font-weight: bold;">&amp;</span>quot;, line <span style="color: #000000;">23</span>, <span style="color: #000000; font-weight: bold;">in</span> visitar_pagina_listagem<br />
&nbsp; &nbsp; delivery.validate<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
&nbsp; File <span style="color: #000000; font-weight: bold;">&amp;</span>quot;<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>python2.6<span style="color: #000000; font-weight: bold;">/</span>dist-packages<span style="color: #000000; font-weight: bold;">/</span>ludibrio<span style="color: #000000; font-weight: bold;">/</span>mock.py<span style="color: #000000; font-weight: bold;">&amp;</span>quot;, line <span style="color: #000000;">103</span>, <span style="color: #000000; font-weight: bold;">in</span> validate<br />
&nbsp; &nbsp; self._call_waiting_msg<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
MockExpectationError: Call waiting:<br />
Expected:<br />
Remedio.objects.all<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000; font-weight: bold;">&amp;</span>gt;<span style="color: #000000; font-weight: bold;">&amp;</span>gt; scc.remedios<br />
Got only:<br />
<br />
<span style="color: #660033;">----------------------------------------------------------------------</span><br />
Ran <span style="color: #000000;">2</span> tests <span style="color: #000000; font-weight: bold;">in</span> 0.373s<br />
<br />
FAILED <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">failures</span>=<span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
Destroying <span style="color: #7a0874; font-weight: bold;">test</span> database <span style="color: #ff0000;">'default'</span>...</div></td></tr></tbody></table></div>
<p>A validação do mock falhou. Simplesmente por que o mock não teve o comportamento esperado, que é a chamada ao método <em>Remedio.objects.all()</em>. Vamos fazer agora com que a requisição na URL <em>/delivery/remedios</em> seja mapeada para uma view que deverá fazer a chamada ao nosso método.</p>
<p>Primeiro, vamos definir a nossa view: dentro do módulo view da aplicação delivery, vamos criar a função a ser mapeada para a URL <em>/delivery/remedios</em>. Esta função se chamará <em>lista_remedios</em>:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> listar_remedios<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; Remedio.<span style="color: black;">objects</span>.<span style="color: #008000;">all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponse<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Note que aqui novamente fizemos apenas o necessário para que a definição de passo passe. Tudo o que precisamos é da chamada a <em>Remedio.objects.all()</em>. Mas apenas isso não é suficiente, precisamos ainda mapear a URL <em>/delivery/remedios</em> para a nossa view recém-definida. Para isso, criaremos o model <em>urls.py</em> dentro da aplicação <em>delivery</em> com o seguinte conteúdo:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span>.<span style="color: black;">urls</span>.<span style="color: black;">defaults</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span><br />
<br />
urlpatterns = patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">'delivery.views'</span>,<br />
&nbsp; &nbsp; url<span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^remedios'</span>, <span style="color: #483d8b;">'listar_remedios'</span>, name = <span style="color: #483d8b;">'listar_remedios'</span><span style="color: black;">&#41;</span>,<br />
<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Depois de definir tal arquivo, vamos incluir dentro do módulo urls.py principal do projeto, que deverá ficar desta forma:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span>.<span style="color: black;">urls</span>.<span style="color: black;">defaults</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span><br />
<br />
<span style="color: #808080; font-style: italic;"># Uncomment the next two lines to enable the admin:</span><br />
<span style="color: #808080; font-style: italic;"># from django.contrib import admin</span><br />
<span style="color: #808080; font-style: italic;"># admin.autodiscover()</span><br />
<br />
urlpatterns = patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Example:</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># (r'^farmacia/', include('farmacia.foo.urls')),</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Uncomment the admin/doc line below and add 'django.contrib.admindocs'</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># to INSTALLED_APPS to enable admin documentation:</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># (r'^admin/doc/', include('django.contrib.admindocs.urls')),</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Uncomment the next line to enable the admin:</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># (r'^admin/', include(admin.site.urls)),</span><br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^delivery/'</span>, include<span style="color: black;">&#40;</span><span style="color: #483d8b;">'delivery.urls'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,<br />
<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Com o mapeamento de URLs configurado e a view devidamente criada, vamos novamente executar o Freshen para obter o feedback:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ nosetests <span style="color: #660033;">--with-freshen</span> <span style="color: #660033;">--with-django</span> <span style="color: #660033;">--language</span>=pt <span style="color: #660033;">-v</span><br />
Listar remédios: Listando todos os remédios ... UNDEFINED: <span style="color: #000000; font-weight: bold;">&amp;</span>quot;eu deveria ver a listagem com o nome dos <span style="color: #000000;">10</span> remédios<span style="color: #000000; font-weight: bold;">&amp;</span>quot; <span style="color: #666666; font-style: italic;"># delivery/features/listar_remedios.feature:9</span><br />
Tests that <span style="color: #000000;">1</span> + <span style="color: #000000;">1</span> always equals <span style="color: #000000;">2</span>. ... ok<br />
<br />
<span style="color: #660033;">----------------------------------------------------------------------</span><br />
Ran <span style="color: #000000;">2</span> tests <span style="color: #000000; font-weight: bold;">in</span> 0.390s<br />
<br />
OK <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">UNDEFINED</span>=<span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
Destroying <span style="color: #7a0874; font-weight: bold;">test</span> database <span style="color: #ff0000;">'default'</span>...</div></td></tr></tbody></table></div>
<p>A parte boa é que nossa definição para o segundo passou funcionou! Agora o Freshen encontrou outro passo indefinido: &#8220;eu deveria ver a listagem com o nome dos 10 remédios&#8221;. Vamos agora implementar este passo, testando o conteúdo da resposta obtida na requisição à URL /delivery/remedios. Para definir este passo, utilizamos o decorator @Then:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">@Then<span style="color: black;">&#40;</span><span style="color: #483d8b;">'eu deveria ver a listagem com o nome dos (<span style="color: #000099; font-weight: bold;">\d</span>+) remédios'</span><span style="color: black;">&#41;</span><br />
<span style="color: #ff7700;font-weight:bold;">def</span> verificar_conteudo_listagem<span style="color: black;">&#40;</span>quantidade_remedios<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> remedio <span style="color: #ff7700;font-weight:bold;">in</span> scc.<span style="color: black;">remedios</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; conteudo_esperado = <span style="color: #483d8b;">'&amp;lt;li&amp;gt;%s&amp;lt;/li&amp;gt;'</span> <span style="color: #66cc66;">%</span><span style="color: black;">&#40;</span>remedio.<span style="color: black;">nome</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; assert_true<span style="color: black;">&#40;</span>conteudo_esperado <span style="color: #ff7700;font-weight:bold;">in</span> scc.<span style="color: black;">response</span>.<span style="color: black;">content</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Montamos o elemento HTML <em>li</em> com o conteúdo esperado e depois testamos se todos os nomes de remédios estão presentes na resposta da requisição, cada um em seu respectivo <strong>li</strong>. Depois fazemos um assert, para verificar se o conteúdo que definimos acima está presente no conteúdo da resposta da requisição. Ao chamar novamente o Freshen, obtemos a seguinte saída:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ nosetests <span style="color: #660033;">--with-freshen</span> <span style="color: #660033;">--with-django</span> <span style="color: #660033;">--language</span>=pt <span style="color: #660033;">-v</span><br />
Listar remédios: Listando todos os remédios ... FAIL<br />
Tests that <span style="color: #000000;">1</span> + <span style="color: #000000;">1</span> always equals <span style="color: #000000;">2</span>. ... ok<br />
<br />
======================================================================<br />
FAIL: Listar remédios: Listando todos os remédios<br />
<span style="color: #660033;">----------------------------------------------------------------------</span><br />
Traceback <span style="color: #7a0874; font-weight: bold;">&#40;</span>most recent call <span style="color: #c20cb9; font-weight: bold;">last</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:<br />
&nbsp; File <span style="color: #000000; font-weight: bold;">&amp;</span>quot;<span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>francisco<span style="color: #000000; font-weight: bold;">/</span>Projetos<span style="color: #000000; font-weight: bold;">/</span>blog<span style="color: #000000; font-weight: bold;">/</span>farmacia<span style="color: #000000; font-weight: bold;">/</span>delivery<span style="color: #000000; font-weight: bold;">/</span>features<span style="color: #000000; font-weight: bold;">/</span>steps.py<span style="color: #000000; font-weight: bold;">&amp;</span>quot;, line <span style="color: #000000;">31</span>, <span style="color: #000000; font-weight: bold;">in</span> verificar_conteudo_listagem<br />
&nbsp; &nbsp; assert_true<span style="color: #7a0874; font-weight: bold;">&#40;</span>conteudo_esperado <span style="color: #000000; font-weight: bold;">in</span> scc.response.content<span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
AssertionError<br />
<br />
<span style="color: #660033;">----------------------------------------------------------------------</span><br />
Ran <span style="color: #000000;">2</span> tests <span style="color: #000000; font-weight: bold;">in</span> 0.362s<br />
<br />
FAILED <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">failures</span>=<span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
Destroying <span style="color: #7a0874; font-weight: bold;">test</span> database <span style="color: #ff0000;">'default'</span>...</div></td></tr></tbody></table></div>
<p>E aí está: um AssertionError, o que significa que nossa definição falhou e o conteúdo esperado não veio na resposta da requisição. Para fazer com que esta definição funcione, vamos refatorar nossa view, para que ela renderize um template e dentro deste template teremos nossos elementos li com os nomes dos remédios. Eis o código da view, refatorado:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> listar_remedios<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; remedios = Remedio.<span style="color: black;">objects</span>.<span style="color: #008000;">all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> render_to_response<span style="color: black;">&#40;</span><span style="color: #483d8b;">'listar_remedios.html'</span>, <span style="color: black;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'remedios'</span> : remedios<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: black;">&#125;</span>, context_instance=RequestContext<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Então devemos criar um template chamado <em>listar_remedios.html</em>. Como é um template da aplicação, coloque ele dentro do diretório templates da aplicação <em>delivery</em>. O conteúdo do template pode ser visto no Gist: <a title="Gist do template" rel="nofollow" href="http://gist.github.com/450936" target="_blank">http://gist.github.com/450936</a></p>
<p>Acredito que aqui tudo está pronto. Vamos perguntar ao Freshen?</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ nosetests <span style="color: #660033;">--with-freshen</span> <span style="color: #660033;">--with-django</span> <span style="color: #660033;">--language</span>=pt <span style="color: #660033;">-v</span><br />
Listar remédios: Listando todos os remédios ... ok<br />
Tests that <span style="color: #000000;">1</span> + <span style="color: #000000;">1</span> always equals <span style="color: #000000;">2</span>. ... ok<br />
<br />
<span style="color: #660033;">----------------------------------------------------------------------</span><br />
Ran <span style="color: #000000;">2</span> tests <span style="color: #000000; font-weight: bold;">in</span> 0.366s<br />
<br />
OK<br />
Destroying <span style="color: #7a0874; font-weight: bold;">test</span> database <span style="color: #ff0000;">'default'</span>...</div></td></tr></tbody></table></div>
<p>Nossa definição de passo passou, e não existe nenhum passo indefinido! Nosso trabalho está pronto, agora basta repetir o ciclo para implementar todas as funcionalidades do sistema, mas isso fica por conta de vocês.</p>
<p>O código deste projeto está disponível no Github: <a title="Exemplo de BDD em Django" rel="nofollow" href="http://github.com/franciscosouza/farmacia" target="_blank">http://github.com/franciscosouza/farmacia</a>.</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2010/06/24/bdd-em-django-desenvolvimento-web-mais-divertido-com-qualidade-usando-freshen/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>O que muda com o Django 1.2?</title>
		<link>http://www.franciscosouza.com.br/2010/05/18/o-que-muda-com-o-django-1-2/</link>
		<comments>http://www.franciscosouza.com.br/2010/05/18/o-que-muda-com-o-django-1-2/#comments</comments>
		<pubDate>Wed, 19 May 2010 02:59:05 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[desenvolvimento de softwares]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[frameworks]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.franciscosouza.com.br/?p=835</guid>
		<description><![CDATA[Esta semana saiu o Django 1.2 e dentre as novidades desta versão estão recursos como o suporte a múltiplos bancos de dados, a validação dos Django Models, baseada na validação dos Django Forms, um framework para mensagens e uma nova &#8230; <a href="http://www.franciscosouza.com.br/2010/05/18/o-que-muda-com-o-django-1-2/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Esta semana saiu o Django 1.2 e dentre as novidades desta versão estão recursos como o <a title="Notas de lançamento para suporte a múltiplos bancos de dados no Django 1.2" rel="nofollow" href="http://docs.djangoproject.com/en/1.2/releases/1.2/#support-for-multiple-databases" target="_blank">suporte a múltiplos bancos de dados</a>, a <a title="Notas de lançamento para o model validation do Django 1.2" rel="nofollow" href="http://docs.djangoproject.com/en/1.2/releases/1.2/#model-validation" target="_blank">validação dos Django Models</a>, baseada na validação dos Django Forms, um <a title="Django 1.2 message framework" rel="nofollow" href="http://docs.djangoproject.com/en/1.2/releases/1.2/#messages-framework" target="_blank">framework para mensagens</a> e uma <a title="Notas de lançamento para a smart if template-tag do Django 1.2" rel="nofollow" href="http://docs.djangoproject.com/en/1.2/releases/1.2/#new-in-1-2-smart-if" target="_blank">nova versão da template-tag <em>if</em></a>. Existem ainda alguns outros recursos, mas vamos dar uma olhada nesses quatro anteriores com mais atenção&#8230;<span id="more-835"></span></p>
<p><strong>1. Suporte ao uso de vários bancos de dados:</strong> Como o nome indica, agora é possível utilizar vários bancos de dados no Django. Isso significa que a configuração do banco de dados no arquivo <em>settings.py </em>não acontece mais da mesma forma. Cada configuração de banco de dados é batizada com um nome, e tem seus próprios parâmetros e na hora de executar alguma tarefa no banco de dados, você especifica qual banco de dados deseja utilizar ao executar uma query através do método <em>using </em>da classe <em>QuerySet</em>, já na hora de gravar registros no banco de dados, você utiliza o <strong>parâmetro</strong> <em>using </em>para informar qual banco de dados utilizar. Não entendeu? Que tal um pouco de código?</p>
<p>Com Django 1.1:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">DATABASE_ENGINE = <span style="color: #483d8b;">'sqlite3'</span><br />
DATABASE_NAME = <span style="color: #483d8b;">'dados.db'</span><br />
DATABASE_USER = <span style="color: #483d8b;">''</span><br />
DATABASE_PASSWORD = <span style="color: #483d8b;">''</span><br />
DATABASE_HOST = <span style="color: #483d8b;">''</span><br />
DATABASE_PORT = <span style="color: #483d8b;">''</span></div></td></tr></tbody></table></div>
<p>Agora, utilizando o Django 1.2:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">DATABASES = <span style="color: black;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #483d8b;">'default'</span>: <span style="color: black;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'ENGINE'</span>: <span style="color: #483d8b;">'django.db.backends.sqlite3'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'NAME'</span>: <span style="color: #483d8b;">'dados.db'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'USER'</span>: <span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'PASSWORD'</span>: <span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'HOST'</span>: <span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'PORT'</span>: <span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; <span style="color: black;">&#125;</span>,<br />
&nbsp; &nbsp; <span style="color: #483d8b;">'alternative'</span> : <span style="color: black;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'ENGINE'</span> : <span style="color: #483d8b;">'django.db.backends.mysql'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'NAME'</span> : <span style="color: #483d8b;">'dados'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'USER'</span> : <span style="color: #483d8b;">'root'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'PASSWORD'</span> : <span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'HOST'</span> : <span style="color: #483d8b;">'localhost'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'PORT'</span> : <span style="color: #483d8b;">'3306'</span>,<br />
&nbsp; &nbsp; <span style="color: black;">&#125;</span><br />
<span style="color: black;">&#125;</span></div></td></tr></tbody></table></div>
<p>Note que configuramos dois bancos de dados, inclusive de tipos diferentes: um SQLite3, que identificamos como <em>default</em> e um MySQL, que identificamos como <em>alternative</em>.</p>
<p>Existem recursos mais &#8220;avançados&#8221;, como o roteamento automático do banco de dados (utilizar um banco de dados apenas para leitura e outro apenas para escrita, por exemplo), que podem ser conferidos na <a title="Documentação do suporte a múltiplos bancos de dados no Django" rel="nofollow" href="http://docs.djangoproject.com/en/1.2/topics/db/multi-db/" target="_blank">documentação oficial do Django</a>.</p>
<p><strong>2. Validação de modelos e introdução de validators: </strong>Agora os modelos são capazes de se <a title="Auto-validação dos modelos no Django 1.2" rel="nofollow" href="http://docs.djangoproject.com/en/1.2/ref/models/instances/#validating-objects" target="_blank">auto-validar-se a si mesmos</a> e suporte à construção de validadores personalizados (recomendo não usar esse termo jamais =P <em><a title="Custom validators no Django 1.2" rel="nofollow" href="http://docs.djangoproject.com/en/1.2/ref/validators/#ref-validators" target="_blank">custom validators</a> </em>soa bem melhor), que são configurados diretamente nos Models ou nos Forms.</p>
<blockquote><p>Os novos validators do Django funcionam de forma semelhante aos validators do <a title="Posts sobre WTForms" href="http://www.franciscosouza.com.br/tag/wtforms/" target="_self">WTForms</a>, que abordei no blogpost anterior. Assim, recomendo a leitura do blogpost de <a title="Formulários inteligentes no Pylons com WTForms" href="http://www.franciscosouza.com.br/2010/04/27/formularios-inteligentes-no-pylons-com-wtforms/" target="_self">integração do WTForms com o Pylons</a> para ver um pouco mais dos validators.</p></blockquote>
<p>Entendendo um pouco mais da validação de modelos, podemos criar um modelo qualquer e definir o <em>validate_even</em> (que valida se um número é par). Assim, vamos configurar nosso model para aceitar somente números pares em um de seus fields. Um <em>validator</em> nada mais é do que uma função que recebe um parâmetro e valida ele (!):</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">core</span>.<span style="color: #dc143c;">exceptions</span> <span style="color: #ff7700;font-weight:bold;">import</span> ValidationError<br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> validate_even<span style="color: black;">&#40;</span>value<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> value <span style="color: #66cc66;">%</span> <span style="color: #ff4500;">2</span> <span style="color: #66cc66;">!</span>= <span style="color: #ff4500;">0</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">raise</span> ValidationError<span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'%s não é um número par.'</span> <span style="color: #66cc66;">%</span> value<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>E no nosso <em>model</em> nós simplesmente passamos o objeto <em>validate_even</em> dentro de uma lista para o parâmetro <em>validators</em>:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">db</span> <span style="color: #ff7700;font-weight:bold;">import</span> models<br />
<br />
<span style="color: #ff7700;font-weight:bold;">class</span> MyModel<span style="color: black;">&#40;</span>models.<span style="color: black;">Model</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; even_field = models.<span style="color: black;">IntegerField</span><span style="color: black;">&#40;</span>validators=<span style="color: black;">&#91;</span>validate_even<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p><strong>Atenção:</strong> a validação dos objetos deve ser feita de forma explícita. O método save não executa a validação implicitamente.</p>
<p><strong>3. Framework de mensagens: </strong>O Django agora inclui um framework poderoso e personalizável para envio de mensagens, utilizadas em três níveis: <em>info, warning</em> e <em>error.</em> A configuração do framework de mensagens é um pouco mais trabalhosa, então recomendo fortemente a leitura da <a title="Documentação oficial para o framework de mensagens do Django 1.2" href="http://docs.djangoproject.com/en/1.2/ref/contrib/messages/" target="_blank">documentação oficial</a>.</p>
<p><strong>4. Nova template-tag &#8220;if&#8221;: </strong>O Django 1.2 trouxe uma melhoria na template tag if, que agora tornou-se mais poderosa. Esta melhoria pode ser um pouco polêmica, uma vez que facilita a implementação de lógica no template. A ideia aqui é substituir templates tags como <em>ifequal </em>e <em>ifnotequal</em>, além de introduzir o suporte ao uso de <em>template filters</em> com a tag <em>if</em>. Vamos ver um pouco de código&#8230;</p>
<p>No Django 1.1:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: black;">&#123;</span><span style="color: #66cc66;">%</span> ifnotequal a b <span style="color: #66cc66;">%</span><span style="color: black;">&#125;</span><br />
&nbsp;...<br />
<span style="color: black;">&#123;</span><span style="color: #66cc66;">%</span> endifnotequal <span style="color: #66cc66;">%</span><span style="color: black;">&#125;</span></div></td></tr></tbody></table></div>
<p>No Django 1.2:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: black;">&#123;</span><span style="color: #66cc66;">%</span> <span style="color: #ff7700;font-weight:bold;">if</span> a <span style="color: #66cc66;">!</span>= b <span style="color: #66cc66;">%</span><span style="color: black;">&#125;</span><br />
&nbsp;...<br />
<span style="color: black;">&#123;</span><span style="color: #66cc66;">%</span> endif <span style="color: #66cc66;">%</span><span style="color: black;">&#125;</span></div></td></tr></tbody></table></div>
<p>Ambos os códigos comparam se duas variáveis (a e b) são diferentes. A nova<em> template tag</em> trouxe o suporte ao uso de operadores, como demonstrado no exemplo acima, e também ao uso de <em>template filters</em>, como demonstrado abaixo:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&lt;</span>div<br />
&nbsp; <span style="color: black;">&#123;</span><span style="color: #66cc66;">%</span> <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #dc143c;">user</span>.<span style="color: #dc143c;">email</span>|lower == message.<span style="color: black;">recipient</span>|lower <span style="color: #66cc66;">%</span><span style="color: black;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">class</span>=<span style="color: #483d8b;">&quot;highlight&quot;</span><br />
&nbsp; <span style="color: black;">&#123;</span><span style="color: #66cc66;">%</span> endif <span style="color: #66cc66;">%</span><span style="color: black;">&#125;</span><br />
<span style="color: #66cc66;">&gt;</span><span style="color: black;">&#123;</span><span style="color: black;">&#123;</span> message <span style="color: black;">&#125;</span><span style="color: black;">&#125;</span><span style="color: #66cc66;">&lt;</span>/div<span style="color: #66cc66;">&gt;</span></div></td></tr></tbody></table></div>
<p>O código acima compara se dois objetos são equivalentes, mas antes da comparação, converte ambos para minúsculo utilizando o <em>template filter</em> <em>lower</em>.</p>
<p>Existem diversos outros recursos, como template caching, e-mail backends, melhorias no sistema de autenticação e autorização, dentre outras. Para mais detalhes, confira as <a title="Django 1.2 release notes" rel="nofollow" href="http://docs.djangoproject.com/en/1.2/releases/1.2/" target="_blank">notas de lançamento do Django 1.2</a> e a <a title="Documentação oficial do Django 1.2" rel="nofollow" href="http://docs.djangoproject.com/en/1.2/" target="_blank">documentação oficial</a>.</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2010/05/18/o-que-muda-com-o-django-1-2/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Behaviour Driven Development (BDD) em Django</title>
		<link>http://www.franciscosouza.com.br/2010/04/02/behaviour-driven-development-bdd-em-django/</link>
		<comments>http://www.franciscosouza.com.br/2010/04/02/behaviour-driven-development-bdd-em-django/#comments</comments>
		<pubDate>Sat, 03 Apr 2010 02:30:50 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[desenvolvimento de softwares]]></category>
		<category><![CDATA[agile]]></category>
		<category><![CDATA[BDD]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.franciscosouza.net/?p=680</guid>
		<description><![CDATA[BDD (Behavior Driven Development) é uma técnica de utilizada em metodologias ágeis de desenvolvimento de software que encoraja interação entre todas as partes envolvidas na construção de um software (desenvolvedores e cliente, basicamente) - adaptado da Wikipedia. No Django, é &#8230; <a href="http://www.franciscosouza.com.br/2010/04/02/behaviour-driven-development-bdd-em-django/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><em>BDD (Behavior Driven Development) é uma técnica de utilizada em metodologias ágeis de desenvolvimento de software que encoraja interação entre todas as partes envolvidas na construção de um software (desenvolvedores e cliente, basicamente) </em>- adaptado da <a title="BDD in Wikipedia" rel="nofollow" href="http://en.wikipedia.org/wiki/Behavior_Driven_Development" target="_blank">Wikipedia</a>.</p>
<p>No Django, é comum vermos pessoas falando sobre o uso de testes unitários e doctests, para um <a title="Posts sobre TDD" href="http://www.franciscosouza.com.br/tag/tdd/">desenvolvimento guiado por testes</a>, mas e como seria utilizar BDD no Django? O que já existe de BDD em Python?<span id="more-680"></span></p>
<p>Na última Python Brasil, Hugo Lopes apresentou uma palestra intitulada <a title="Palestra BDD em Python, por Hugo Lopes" rel="nofollow" href="http://www.pythonbrasil.org.br/2009/sobre-o-evento/inscricoes/00f25696178cf2f075617273aece2edd" target="_blank">&#8220;Behavior Driven Development (BDD) em Python&#8221;</a>, onde apresentou alguns conceitos de BDD e algumas ferramentas e projetos de BDD em Python. Quem quiser saber mais sobre a palestra, pode <a title="Vídeo da palestra BDD em Python, por Hugo Lopes" rel="nofollow" href="http://blip.tv/file/2889996" target="_blank">assistir a palestra na online no blip.tv</a>.</p>
<p>Ainda não existe algo como o RSpec e o Cucumber sendo utilizado em larga escala junto ao Django, mas vou tentar mostrar aqui um pouco do uso das ferramentas apresentadas pelo Hugo, em conjunto com Django. Os passos para fazer algo em BDD é semelhante aos passos do TDD:</p>
<ol>
<li>Escreva o comportamento desejado;</li>
<li>Escreva o código para atender ao comportamento desejado;</li>
<li>Teste se o código escrito realmente atende ao comportamento desejado;</li>
<li>Refatore;</li>
<li>Entre em loop com os passos anteriores :)</li>
</ol>
<p>Podemos ver um pouco mais disso em um exemplo mais prático. Imaginando que estejamos desenvolvendo um sistema acadêmico, e para o módulo de controle de matrícula haja a seguinte <span style="text-decoration: line-through;">especificação </span>história:</p>
<blockquote><p>Eu como secretário gostaria de cadastrar um aluno no sistema, informando seu nome e sua data de nascimento.</p></blockquote>
<p>Bom, aí está nossa história. Agora, vamos escrever o comportamento dessa história. Utilizando PyCukes, o comportamento fica definido desta forma:</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">História: Cadastro de Aluno<br />
&nbsp; &nbsp; &nbsp;Como um secretário<br />
&nbsp; &nbsp; &nbsp;Eu quero cadastrar um aluno informando nome e data de nascimento<br />
&nbsp; &nbsp; &nbsp;Para que ele possa ser matriculado em disciplinas<br />
<br />
&nbsp; &nbsp; &nbsp;Cenário 1: Cadastro de aluno sem nome<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dado que eu estou cadastrando um aluno<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Quando eu não digito o nome<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Então o cadastro não pode ser completado</div></td></tr></tbody></table></div>
<p>A especificação em português e bem bonitinha (poderia ser criada pelo seu cliente, com sua orientação). Este é o formato aceito pelo <em>PyCukes.</em> Agora basta traduzir os passos de cada cenário. Criamos apenas o primeiro cenário, que diz que o aluno não pode ser cadastrado sem nome. Então vamos fazer isso funcionar :)</p>
<p>Como é um projeto Django, devemos criar um model nosso alunos, certo? Errado, é BDD. Primeiro vem o comportamento, depois o código :) Depois de definirmos o comportamento em linguagem natural, precisamos ensinar ao PyCukes o que ele deve fazer com cada um dos passos do nosso cenário:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #808080; font-style: italic;">#coding:utf-8</span><br />
<span style="color: #ff7700;font-weight:bold;">from</span> pycukes <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span><br />
<span style="color: #ff7700;font-weight:bold;">from</span> should_dsl <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span><br />
<span style="color: #ff7700;font-weight:bold;">import</span> set_django<br />
<br />
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">db</span> <span style="color: #ff7700;font-weight:bold;">import</span> IntegrityError<br />
<span style="color: #ff7700;font-weight:bold;">from</span> matricula.<span style="color: black;">models</span> <span style="color: #ff7700;font-weight:bold;">import</span> Aluno<br />
<br />
@DadoQue<span style="color: black;">&#40;</span><span style="color: #483d8b;">'eu estou cadastrando um aluno'</span><span style="color: black;">&#41;</span><br />
<span style="color: #ff7700;font-weight:bold;">def</span> iniciar_cadastro_aluno<span style="color: black;">&#40;</span>contexto<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #66cc66;">&amp;</span>quot<span style="color: #66cc66;">;&amp;</span>quot<span style="color: #66cc66;">;&amp;</span>quot<span style="color: #66cc66;">;</span>docstring <span style="color: #ff7700;font-weight:bold;">for</span> iniciar_cadastro_aluno<span style="color: #66cc66;">&amp;</span>quot<span style="color: #66cc66;">;&amp;</span>quot<span style="color: #66cc66;">;&amp;</span>quot<span style="color: #66cc66;">;</span><br />
&nbsp; &nbsp; contexto._aluno = Aluno<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<br />
@Quando<span style="color: black;">&#40;</span><span style="color: #483d8b;">'eu não digito o nome'</span><span style="color: black;">&#41;</span><br />
<span style="color: #ff7700;font-weight:bold;">def</span> aluno_sem_nome<span style="color: black;">&#40;</span>contexto<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #66cc66;">&amp;</span>quot<span style="color: #66cc66;">;&amp;</span>quot<span style="color: #66cc66;">;&amp;</span>quot<span style="color: #66cc66;">;</span>docstring <span style="color: #ff7700;font-weight:bold;">for</span> aluno_sem_nome<span style="color: #66cc66;">&amp;</span>quot<span style="color: #66cc66;">;&amp;</span>quot<span style="color: #66cc66;">;&amp;</span>quot<span style="color: #66cc66;">;</span><br />
&nbsp; &nbsp; contexto._aluno.<span style="color: black;">nome</span> = <span style="color: #008000;">None</span><br />
<br />
@Entao<span style="color: black;">&#40;</span><span style="color: #483d8b;">'o cadastro não pode ser completado'</span><span style="color: black;">&#41;</span><br />
<span style="color: #ff7700;font-weight:bold;">def</span> cadastro_nao_pode_ser_completado<span style="color: black;">&#40;</span>contexto<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #66cc66;">&amp;</span>quot<span style="color: #66cc66;">;&amp;</span>quot<span style="color: #66cc66;">;&amp;</span>quot<span style="color: #66cc66;">;</span>docstring <span style="color: #ff7700;font-weight:bold;">for</span> cadastro_nao_pode_ser_completado<span style="color: #66cc66;">&amp;</span>quot<span style="color: #66cc66;">;&amp;</span>quot<span style="color: #66cc66;">;&amp;</span>quot<span style="color: #66cc66;">;</span><br />
&nbsp; &nbsp; IntegrityError |should_be.<span style="color: black;">thrown_by</span>| contexto._aluno.<span style="color: black;">save</span></div></td></tr></tbody></table></div>
<p>Note na linha 4 o código <em>import set_django</em>. Trata-se do módulo que configura para que o projeto do Django possa ser enxergado pelo PyCukes. O código deste módulo é o seguinte:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">core</span>.<span style="color: black;">management</span> <span style="color: #ff7700;font-weight:bold;">import</span> setup_environ<br />
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span><br />
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span><br />
<br />
abs_path = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">abspath</span><span style="color: black;">&#40;</span>__file__<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
abs_path = abs_path.<span style="color: black;">replace</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'stories/step_definitions'</span>, <span style="color: #483d8b;">''</span><span style="color: black;">&#41;</span><br />
<span style="color: #dc143c;">sys</span>.<span style="color: black;">path</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span>abs_path<span style="color: black;">&#41;</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">import</span> settings<br />
<br />
setup_environ<span style="color: black;">&#40;</span>settings<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Ao rodarmos o Pycukes, obteremos um erro, informando que a classe Aluno não existe:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ pycukes <span style="color: #660033;">-l</span> pt-br<br />
Traceback <span style="color: #7a0874; font-weight: bold;">&#40;</span>most recent call <span style="color: #c20cb9; font-weight: bold;">last</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:<br />
&nbsp; File <span style="color: #000000; font-weight: bold;">&amp;</span>quot;<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>pycukes<span style="color: #000000; font-weight: bold;">&amp;</span>quot;, line <span style="color: #000000;">8</span>, <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #000000; font-weight: bold;">&amp;</span>lt;module<span style="color: #000000; font-weight: bold;">&amp;</span>gt;<br />
&nbsp; &nbsp; load_entry_point<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">'pycukes==0.1.2'</span>, <span style="color: #ff0000;">'console_scripts'</span>, <span style="color: #ff0000;">'pycukes'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
&nbsp; File <span style="color: #000000; font-weight: bold;">&amp;</span>quot;<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>python2.6<span style="color: #000000; font-weight: bold;">/</span>dist-packages<span style="color: #000000; font-weight: bold;">/</span>pycukes-0.1.2-py2.6.egg<span style="color: #000000; font-weight: bold;">/</span>pycukes<span style="color: #000000; font-weight: bold;">/</span>console.py<span style="color: #000000; font-weight: bold;">&amp;</span>quot;, line <span style="color: #000000;">40</span>, <span style="color: #000000; font-weight: bold;">in</span> main<br />
&nbsp; &nbsp; steps_modules = find_steps_modules<span style="color: #7a0874; font-weight: bold;">&#40;</span>values.steps_dir or stories_dirname+<span style="color: #ff0000;">'/step_definitions'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
&nbsp; File <span style="color: #000000; font-weight: bold;">&amp;</span>quot;<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>python2.6<span style="color: #000000; font-weight: bold;">/</span>dist-packages<span style="color: #000000; font-weight: bold;">/</span>pycukes-0.1.2-py2.6.egg<span style="color: #000000; font-weight: bold;">/</span>pycukes<span style="color: #000000; font-weight: bold;">/</span>finder.py<span style="color: #000000; font-weight: bold;">&amp;</span>quot;, line <span style="color: #000000;">8</span>, <span style="color: #000000; font-weight: bold;">in</span> find_steps_modules<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> filename.endswith<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">'steps.py'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#93;</span><br />
&nbsp; File <span style="color: #000000; font-weight: bold;">&amp;</span>quot;stories<span style="color: #000000; font-weight: bold;">/</span>step_definitions<span style="color: #000000; font-weight: bold;">/</span>cadastro_aluno_steps.py<span style="color: #000000; font-weight: bold;">&amp;</span>quot;, line <span style="color: #000000;">7</span>, <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #000000; font-weight: bold;">&amp;</span>lt;module<span style="color: #000000; font-weight: bold;">&amp;</span>gt;<br />
&nbsp; &nbsp; from matricula.models import Aluno<br />
ImportError: cannot import name Aluno<br />
<br />
o shell devolveu <span style="color: #000000;">1</span></div></td></tr></tbody></table></div>
<p>Ainda não vale por que foi um erro do Python, e não do Pycukes, certo? Então vamos criar o model Aluno e rodar o Pycukes agora com o aluno certinho, para ver se funciona?</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">class</span> Aluno<span style="color: black;">&#40;</span>models.<span style="color: black;">Model</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; nome = models.<span style="color: black;">CharField</span><span style="color: black;">&#40;</span>max_length=<span style="color: #ff4500;">100</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; data_nascimento = models.<span style="color: black;">DateField</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Rodando o PyCukes agora, tudo funciona certinho:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">pycukes <span style="color: #660033;">-l</span> pt-br<br />
História: Cadastro de Aluno<br />
&nbsp; Como um secretário<br />
&nbsp; Eu quero cadastrar um aluno informando nome e data de nascimento<br />
&nbsp; Para que ele possa ser matriculado em disciplinas<br />
<br />
&nbsp; Cenário <span style="color: #000000;">1</span>: Cadastro de aluno sem nome<br />
&nbsp; &nbsp; Dado que eu estou cadastrando um aluno &nbsp; ... OK<br />
&nbsp; &nbsp; Quando eu não digito o nome &nbsp; ... OK<br />
&nbsp; &nbsp; Então o cadastro não pode ser completado &nbsp; ... OK<br />
<br />
&nbsp; Rodou <span style="color: #000000;">1</span> cenário com <span style="color: #000000;">0</span> falhas, <span style="color: #000000;">0</span> erros e <span style="color: #000000;">0</span> passos pendentes</div></td></tr></tbody></table></div>
<p>Note que a garantia de funcionalidade do comportamento é seguirmos o padrão do Django, dizendo que não aceitaremos null no atributo <em>nome</em> da classe <em>Aluno</em>.</p>
<p>Bom, aí está, um pouco de BDD, baseado no trio <em>Given, When</em> e <em>Then.</em> Quem quiser pode explorar mais o pycukes no <a title="Repositório do PyCukes" rel="nofollow" href="http://github.com/hugobr/pycukes" target="_blank">repositório do projeto no Github</a>.</p>
<p>Futuramente devo trazer um exemplo mais completo. O código do projeto deste post pode ser encontrado no Github: <a title="Repositório Git do projeto deste post" rel="nofollow" href="http://github.com/franciscosouza/post-bdd-django" target="_blank">http://github.com/franciscosouza/post-bdd-django</a>.</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2010/04/02/behaviour-driven-development-bdd-em-django/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Construindo uma API RESTful em Django e acessando com Java</title>
		<link>http://www.franciscosouza.com.br/2010/02/06/construindo-uma-api-restful-em-django-e-acessando-com-java/</link>
		<comments>http://www.franciscosouza.com.br/2010/02/06/construindo-uma-api-restful-em-django-e-acessando-com-java/#comments</comments>
		<pubDate>Sat, 06 Feb 2010 18:17:59 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[desenvolvimento de softwares]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[piston]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[REST]]></category>

		<guid isPermaLink="false">http://www.franciscosouza.net/?p=633</guid>
		<description><![CDATA[No post sobre aplicações RESTful no Django, fiz uma rápida introdução sobre o django-piston. O piston é um framework para construção de APIs REST utilizando Django. Vamos a um exemplo bem simples: o IBGE com uma API REST para consulta &#8230; <a href="http://www.franciscosouza.com.br/2010/02/06/construindo-uma-api-restful-em-django-e-acessando-com-java/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>No post sobre <a title="Aplicações RESTful no Django" href="http://www.franciscosouza.com.br/2009/12/30/aplicacoes-restful-no-django/">aplicações RESTful no Django</a>, fiz uma rápida introdução sobre o <a title="Django Piston" href="http://bitbucket.org/jespern/django-piston/" target="_blank">django-piston</a>. O piston é um <a title="Posts sobre frameworks" href="http://www.franciscosouza.com.br/tag/frameworks">framework</a> para construção de APIs REST utilizando Django. Vamos a um exemplo bem simples: o IBGE com uma API REST para consulta de informações sobre cidades e regiões metropolitanas, onde os dados serão servidos em formato JSON. Vamos implementar dois recursos básicos: A consulta de estados e a consulta de cidades de um estados. E para aplicar isso, que tal uma aplicação em Java Swing com dois combo boxes, um para cidade e outro para estado?<span id="more-633"></span></p>
<p>Bom, para começar, criamos o nosso projeto no Django, com a aplicação <em>ibge_cidades</em> (talvez o nome não seja melhor, mas imagine que seja uma nova implementação do IBGE Cidades xD). Três comandos básicos e estamos lá:</p>
<pre>$ django-admin.py startproject ibge_portal
$ cd ibge_portal
$ django-admin.py startapp ibge_cidades</pre>
<p>Agora, dentro da aplicação ibge_cidades, vamos definir nossos modelos no arquivo <em>models.py</em>:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">db</span> <span style="color: #ff7700;font-weight:bold;">import</span> models<br />
<br />
<span style="color: #808080; font-style: italic;"># Create your models here.</span><br />
<span style="color: #ff7700;font-weight:bold;">class</span> Estado<span style="color: black;">&#40;</span>models.<span style="color: black;">Model</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; sigla = models.<span style="color: black;">CharField</span><span style="color: black;">&#40;</span>max_length = <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; nome = models.<span style="color: black;">CharField</span><span style="color: black;">&#40;</span>max_length = <span style="color: #ff4500;">100</span><span style="color: black;">&#41;</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">class</span> Cidade<span style="color: black;">&#40;</span>models.<span style="color: black;">Model</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; nome = models.<span style="color: black;">CharField</span><span style="color: black;">&#40;</span>max_length = <span style="color: #ff4500;">100</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; estado = models.<span style="color: black;">ForeignKey</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Estado'</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Modelos simples para um exemplo bem simples =) Agora, vamos popular um pouco nosso banco de dados, apenas para ter uma &#8220;gigante&#8221; massa de dados:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ ./manage.<span style="color: black;">py</span> shell<br />
Python 2.6.4 <span style="color: black;">&#40;</span>r264:<span style="color: #ff4500;">75706</span>, Dec &nbsp;<span style="color: #ff4500;">7</span> <span style="color: #ff4500;">2009</span>, <span style="color: #ff4500;">18</span>:<span style="color: #ff4500;">43</span>:<span style="color: #ff4500;">55</span><span style="color: black;">&#41;</span><br />
<span style="color: black;">&#91;</span>GCC 4.4.1<span style="color: black;">&#93;</span> on linux2<br />
Type <span style="color: #483d8b;">&quot;help&quot;</span>, <span style="color: #483d8b;">&quot;copyright&quot;</span>, <span style="color: #483d8b;">&quot;credits&quot;</span> <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #483d8b;">&quot;license&quot;</span> <span style="color: #ff7700;font-weight:bold;">for</span> more information.<br />
<span style="color: black;">&#40;</span>InteractiveConsole<span style="color: black;">&#41;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> ibge_cidades.<span style="color: black;">models</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> es = Estado<span style="color: black;">&#40;</span>sigla = <span style="color: #483d8b;">'ES'</span>, nome = <span style="color: #483d8b;">'Espírito Santo'</span><span style="color: black;">&#41;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> es.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> rj = Estado<span style="color: black;">&#40;</span>sigla = <span style="color: #483d8b;">'RJ'</span>, nome = <span style="color: #483d8b;">'Rio de Janeiro'</span><span style="color: black;">&#41;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> rj.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> niteroi = Cidade<span style="color: black;">&#40;</span>nome = <span style="color: #483d8b;">'Niterói'</span>, estado = rj<span style="color: black;">&#41;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> niteroi.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> cachoeiro = Cidade<span style="color: black;">&#40;</span>nome = <span style="color: #483d8b;">'Cachoeiro de Itapemirim'</span>, estado = es<span style="color: black;">&#41;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> cachoeiro.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> vitoria = Cidade<span style="color: black;">&#40;</span>nome = <span style="color: #483d8b;">'Vitória'</span>, estado = es<span style="color: black;">&#41;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> vitoria.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> rio = Cidade<span style="color: black;">&#40;</span>nome = <span style="color: #483d8b;">'Rio de Janeiro'</span>, estado = rj<span style="color: black;">&#41;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> rio.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span></div></td></tr></tbody></table></div>
<p>Com o nosso banco de dados super populado e nossos modelos enfim definidos, podemos seguir em frente e construir nossa API :) A API será servida no diretório <em>api</em>, assim, basta criar um pacote Python chamado api na raiz do projeto:</p>
<pre>$ mkdir api
$ touch api/__init__.py</pre>
<p>Adicionamos ainda os arquivos <em>urls.py</em> e <em>handlers.py</em> ao nosso diretório api:</p>
<pre>$ touch api/urls.py
$ touch api/handlers.py</pre>
<p>O piston trabalha com resources, que são objetos modelados por uma classe que herda de <em>BaseHandler</em>. Cada resource pode estar relacionado diretamente com um model. Vamos definir dois handlers: EstadoHandler e CidadeHandler:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">class</span> EstadoHandler <span style="color: black;">&#40;</span>BaseHandler<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; allowed_methods = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'GET'</span>,<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; model = Estado<br />
<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> read<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, request<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">pass</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">class</span> CidadeHandler<span style="color: black;">&#40;</span>BaseHandler<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; allowed_methods = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'GET'</span>,<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; model = Cidade<br />
<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> read<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, request, sigla_estado<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">pass</span></div></td></tr></tbody></table></div>
<p>O método <em>read </em>de um <em>resource</em> responde a uma requisição do tipo GET, existem ainda os métodos <em>create</em>, <em>update</em> e <em>delete</em> para responder às requisições do tipo <em>POST, PUT</em> e <em>DELETE</em>, respectivamente. O método read do <em>EstadoHandler</em> retornará a lista com todos os estados, em formato JSON, já o método <em>read</em> do <em>resource CidadeHandler</em> receberá a sigla de um estado e listará todas as cidades daquele estado. A implementação disso é bem simples:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">class</span> EstadoHandler <span style="color: black;">&#40;</span>BaseHandler<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; allowed_methods = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'GET'</span>,<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; model = Estado<br />
<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> read<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, request<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; estados = Estado.<span style="color: black;">objects</span>.<span style="color: #008000;">all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> estados<br />
<br />
<span style="color: #ff7700;font-weight:bold;">class</span> CidadeHandler<span style="color: black;">&#40;</span>BaseHandler<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; allowed_methods = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'GET'</span>,<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; model = Cidade<br />
<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> read<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, request, sigla_estado<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; cidades = Cidade.<span style="color: black;">objects</span>.<span style="color: #008000;">filter</span><span style="color: black;">&#40;</span>estado__sigla = sigla_estado<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> cidades</div></td></tr></tbody></table></div>
<p>Duas linhas pra cada método e a API está quase pronta. O que falta? Apenas o mapeamento de URLs, que fica da seguinte forma:</p>
<ul>
<li>GET /api/estados: Retorna a lista de todos estados;</li>
<li>GET /api/cidades/&lt;sigla&gt;: Retorna a lista de todas as cidades do estado identificado por &lt;sigla&gt;.</li>
</ul>
<p>Temos um arquivo <em>urls.py</em> na raiz do projeto e outro no diretório <em>api</em>. Primeiro, editamos o arquivo da raiz do projeto, para adicionar um include ao outro arquivo:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span>.<span style="color: black;">urls</span>.<span style="color: black;">defaults</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span><br />
<br />
urlpatterns = patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^api/'</span>, include<span style="color: black;">&#40;</span><span style="color: #483d8b;">'ibge_portal.api.urls'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,<br />
<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Em seguida adicionamos ao <em>api/urls.py</em> o mapeamento para os <em>resources</em>:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span>.<span style="color: black;">urls</span>.<span style="color: black;">defaults</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span><br />
<span style="color: #ff7700;font-weight:bold;">from</span> piston.<span style="color: #dc143c;">resource</span> <span style="color: #ff7700;font-weight:bold;">import</span> Resource<br />
<span style="color: #ff7700;font-weight:bold;">from</span> ibge_portal.<span style="color: black;">api</span>.<span style="color: black;">handlers</span> <span style="color: #ff7700;font-weight:bold;">import</span> EstadoHandler, CidadeHandler<br />
<br />
estado_resource = Resource<span style="color: black;">&#40;</span>EstadoHandler<span style="color: black;">&#41;</span><br />
cidade_resource = Resource<span style="color: black;">&#40;</span>CidadeHandler<span style="color: black;">&#41;</span><br />
<br />
urlpatterns = patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^estados/'</span>, estado_resource<span style="color: black;">&#41;</span>,<br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^cidades/(?P&lt;sigla_estado&gt;[^/]+)'</span>, cidade_resource<span style="color: black;">&#41;</span>,<br />
<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Agora sim a API está pronta, e já podemos construir uma aplicação utilizando Java Swing para acessar a API :) O código da aplicação Java é bem simples (e pode estar despadronizado, desculpe programadores Java =/). Basicamente, existem dois métodos, um para preencher cada combo:</p>
<div class="codecolorer-container java twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">void</span> preencherComboCidades<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aioexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">IOException</span></a> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; Estado selecionado <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>Estado<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">comboEstados</span>.<span style="color: #006633;">getSelectedItem</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aurl+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">URL</span></a> url <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aurl+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">URL</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;http://localhost:8000/api/cidades/&quot;</span> <span style="color: #339933;">+</span> selecionado.<span style="color: #006633;">getSigla</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aurlconnection+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">URLConnection</span></a> urlConnection <span style="color: #339933;">=</span> url.<span style="color: #006633;">openConnection</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Abufferedreader+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">BufferedReader</span></a> reader <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Abufferedreader+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">BufferedReader</span></a><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Ainputstreamreader+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">InputStreamReader</span></a><span style="color: #009900;">&#40;</span>urlConnection.<span style="color: #006633;">getInputStream</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> linhas <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> linha <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>linha <span style="color: #339933;">=</span> reader.<span style="color: #006633;">readLine</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; linhas <span style="color: #339933;">+=</span> linha<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; reader.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; JSONArray array <span style="color: #339933;">=</span> JSONArray.<span style="color: #006633;">fromObject</span><span style="color: #009900;">&#40;</span>linhas<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aobject+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Object</span></a><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> objCidades <span style="color: #339933;">=</span> array.<span style="color: #006633;">toArray</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; Map<span style="color: #339933;">&lt;</span>String, Class<span style="color: #339933;">&gt;</span> classMap <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HashMap<span style="color: #339933;">&lt;</span>String, Class<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; classMap.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;estado&quot;</span>, Estado.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adefaultcomboboxmodel+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">DefaultComboBoxModel</span></a> model <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adefaultcomboboxmodel+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">DefaultComboBoxModel</span></a><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">comboCidades</span>.<span style="color: #006633;">getModel</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; model.<span style="color: #006633;">removeAllElements</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aobject+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Object</span></a> objCidade <span style="color: #339933;">:</span> objCidades<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; JSONObject object <span style="color: #339933;">=</span> JSONObject.<span style="color: #006633;">fromObject</span><span style="color: #009900;">&#40;</span>objCidade<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Cidade cidade <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>Cidade<span style="color: #009900;">&#41;</span> JSONObject.<span style="color: #006633;">toBean</span><span style="color: #009900;">&#40;</span>object, Cidade.<span style="color: #000000; font-weight: bold;">class</span>, classMap<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; model.<span style="color: #006633;">addElement</span><span style="color: #009900;">&#40;</span>cidade<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">void</span> preencherComboEstados<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aioexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">IOException</span></a> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aurl+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">URL</span></a> url <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aurl+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">URL</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;http://localhost:8000/api/estados&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aurlconnection+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">URLConnection</span></a> urlConnection <span style="color: #339933;">=</span> url.<span style="color: #006633;">openConnection</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Abufferedreader+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">BufferedReader</span></a> reader <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Abufferedreader+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">BufferedReader</span></a><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Ainputstreamreader+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">InputStreamReader</span></a><span style="color: #009900;">&#40;</span>urlConnection.<span style="color: #006633;">getInputStream</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> linhas <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> linha <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>linha <span style="color: #339933;">=</span> reader.<span style="color: #006633;">readLine</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; linhas <span style="color: #339933;">+=</span> linha<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; reader.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; JSONArray array <span style="color: #339933;">=</span> JSONArray.<span style="color: #006633;">fromObject</span><span style="color: #009900;">&#40;</span>linhas<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aobject+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Object</span></a><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> objEstados <span style="color: #339933;">=</span> array.<span style="color: #006633;">toArray</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adefaultcomboboxmodel+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">DefaultComboBoxModel</span></a> model <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adefaultcomboboxmodel+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">DefaultComboBoxModel</span></a><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; model.<span style="color: #006633;">addElement</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Selecione o estado&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aobject+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Object</span></a> objEstado <span style="color: #339933;">:</span> objEstados<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; JSONObject object <span style="color: #339933;">=</span> JSONObject.<span style="color: #006633;">fromObject</span><span style="color: #009900;">&#40;</span>objEstado<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Estado estado <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>Estado<span style="color: #009900;">&#41;</span> JSONObject.<span style="color: #006633;">toBean</span><span style="color: #009900;">&#40;</span>object, Estado.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; model.<span style="color: #006633;">addElement</span><span style="color: #009900;">&#40;</span>estado<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">comboEstados</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Ajcombobox+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">JComboBox</span></a><span style="color: #009900;">&#40;</span>model<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">comboEstados</span>.<span style="color: #006633;">addItemListener</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>O código completo dos dois projetos está no Bitbucket:</p>
<ul>
<li>Lado servidor, Django: <a title="Codigo do lado servidor" href="http://bitbucket.org/franciscosouza/exemplo-api-django/" target="_blank">http://bitbucket.org/franciscosouza/exemplo-api-django/</a>;</li>
<li>Lado cliente, Java Swing: <a title="Código do lado cliente" href="http://bitbucket.org/franciscosouza/exemplo-api-java-swing/" target="_blank">http://bitbucket.org/franciscosouza/exemplo-api-java-swing/</a>.</li>
</ul>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2010/02/06/construindo-uma-api-restful-em-django-e-acessando-com-java/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Uso de frameworks para desenvolvimento web e mitos que já deveriam ter desaparecido</title>
		<link>http://www.franciscosouza.com.br/2010/01/22/uso-de-frameworks-para-desenvolvimento-web-e-mitos-que-ja-deveriam-ter-desaparecido/</link>
		<comments>http://www.franciscosouza.com.br/2010/01/22/uso-de-frameworks-para-desenvolvimento-web-e-mitos-que-ja-deveriam-ter-desaparecido/#comments</comments>
		<pubDate>Fri, 22 Jan 2010 23:11:20 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[desenvolvimento de softwares]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[frameworks]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[preconceito]]></category>

		<guid isPermaLink="false">http://www.franciscosouza.net/?p=617</guid>
		<description><![CDATA[O desenvolvimento de aplicações web utilizando frameworks se expandiu de tal forma que tornou-se imprescindível o uso de frameworks para construção de sistemas voltados para internet/intranet/web. Pequenos e grandes; nacionais e internacionais; muitos são os cases atribuídos aos modernos e &#8230; <a href="http://www.franciscosouza.com.br/2010/01/22/uso-de-frameworks-para-desenvolvimento-web-e-mitos-que-ja-deveriam-ter-desaparecido/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>O desenvolvimento de aplicações web utilizando <a title="Posts sobre frameworks" href="http://www.franciscosouza.com.br/tag/frameworks/">frameworks</a> se expandiu de tal forma que tornou-se imprescindível o uso de frameworks para construção de sistemas voltados para internet/intranet/web. Pequenos e grandes; nacionais e internacionais; muitos são os cases atribuídos aos modernos e ágeis frameworks para desenvolvimento web.<span id="more-617"></span></p>
<p>O famoso padrão MVC (model view controller) encaixa-se como uma luva para aplicações web, e é melhor aproveitado quando explorado por um framework. Frameworks implementam o padrão MVC de forma realmente padronizada (o que às vezes varia, é a nomenclatura, como no <a title="Posts sobre Django" href="http://www.franciscosouza.com.br/tag/django">Django</a>), explorando ao máximo o padrão MVC.</p>
<p>Existem inúmeros benefícios alcançados ao utilizar frameworks, como o ganho de produtividade, a redução da possibilidade de erros (produtividade, de novo), maior nível de abstração (produtividade?), compatibilidade e integração entre aplicações (produtividade!), desenvolvimento de forma mais segura e prazerosa :) Além destes benefícios, há a vantagem de contar com o apoio da comunidade, já que os frameworks são usados em larga escala e geralmente são comunitários.</p>
<p>Contra estes benefícios, existem poucas desvantagens e muitos mitos. Em grande parte das discussões que envolvem o uso de frameworks, percebe-se no time “do contra” muito preconceito, argumentos recheados de mitos e, por vezes, confusões e conclusões baseadas em frustrações passadas. Alguns dos mitos e confusões mais comuns são:</p>
<ul>
<li><strong>Frameworks amputam o desenvolvedor</strong>. Algumas pessoas defendem que ao usarmos frameworks passamos mais tempo configurando do que programando. Em alguns casos, tais pessoas têm razão (experimente fazer algo bem simples em frameworks que não trazem convention over configuration), mas, na maioria dos casos, elas estão incorretas. Assim, defender o não-uso de frameworks argumentando que o desenvolvedor crescerá mais pessoal e profissionalmente fazendo tudo “na mão” é algo bastante errado, até por que os frameworks atuam principalmente nas partes mais chatas. Não é fazendo validação de formulário e tratamento de requisições com type cast que alguém se torna um excelente programador;</li>
<li><strong>Não é boa ideia usar os frameworks modernos, pois os antigos eram muito complexos</strong>. “Eu tenho um trauma com frameworks, usei isso um tempo atrás e não deu certo”. Preconceito discriminatório não é bom em informática nem em nenhum outro lugar. Hoje em dia, os frameworks são muito mais modernos e ágeis do que as ferramentas de anos atrás. Não faz sentido algum julgar uma ferramenta que você não conhece baseando em uma que você conhece (e não gosta), não da pra justificar a recusa do VRaptor 3 baseando-se numa má experiência com o Struts 1.1 em 2003, ou de um dos vários frameworks Python modernos por que em 2002 você testou o Zope e achou ele complicado;</li>
<li><strong>Frameworks provocam perda de desempenho</strong>. Sim, provocam, mas isso geralmente é imperceptível. Mesmo que haja uma gigante e complexa estrutura (o que é incomum nos frameworks mais modernos), a interpretação de uma linguagem de templates e mais algumas firulas que fazem com que se perca desempenho, dificilmente o usuário final perceberá a diferença. Além disso, os frameworks também fornecem recursos como cache em memória para que o desempenho com eles seja melhor do que sem eles;</li>
<li><strong>Se um framework tiver uma falha de segurança, minha aplicação fica vulneráve</strong>l. Sim, é verdade, mas frameworks raramente têm falhas de segurança (pesquise no Google sobre falhas de segurança em frameworks). Frameworks bons são testados, utilizados e desenvolvidos massivamente; e costumam ter grande parte do código coberta por testes, o que garante um alto índice de segurança e pequena possibilidade de falha.</li>
<li><strong>Usar framework? Eu não gosto de WordPress nem Joomla, são pesados!</strong> Por mais incrível que possa parecer, existem profissionais que atuam com desenvolvimento web e não sabem ao certo o que é framework. Esta falta de conhecimento é comum em alguns profissionais totalmente técnicos (geralmente 100% auto-didatas), desprovidos de alguns conceitos fundamentais. É um caso bem difícil de solucionar, mas o incentivo da comunidade e a exigência do mercado de um nível maior de conhecimento de conceitos pode, a longo prazo, solucionar este problema.</li>
</ul>
<p>Hoje em dia, dificilmente alguém consegue levantar argumentos válidos contra o uso de frameworks web. Cases grandes como Twitter, SourceForge e BitTorrent.com mostram que os “peixes grandes” acreditam e, consequentemente, investem em frameworks web.</p>
<p>Frameworks web são utilizados em larga escala. Não é moda, é uma necessidade comprovada pela comunidade e pelo meio corporativo, e alguns mitos têm que ser derrubados.</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2010/01/22/uso-de-frameworks-para-desenvolvimento-web-e-mitos-que-ja-deveriam-ter-desaparecido/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Aplicações RESTful no Django</title>
		<link>http://www.franciscosouza.com.br/2009/12/30/aplicacoes-restful-no-django/</link>
		<comments>http://www.franciscosouza.com.br/2009/12/30/aplicacoes-restful-no-django/#comments</comments>
		<pubDate>Wed, 30 Dec 2009 14:32:14 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[piston]]></category>
		<category><![CDATA[REST]]></category>

		<guid isPermaLink="false">http://www.franciscosouza.net/?p=572</guid>
		<description><![CDATA[O Django é um framework moderno, com muitos recursos &#8220;out of box&#8221; e módulos inclusos para fazer 54131998944535 coisas. Porém, diferente de frameworks como Pylons e VRaptor, o Django não possui no seu conjunto de módulos uma API RESTful prontinha &#8230; <a href="http://www.franciscosouza.com.br/2009/12/30/aplicacoes-restful-no-django/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>O <a title="Posts sobre Django" href="http://www.franciscosouza.com.br/tag/django/">Django</a> é um framework moderno, com muitos recursos &#8220;out of box&#8221; e <a title="Referência de módulos do Django" rel="nofollow" href="http://docs.djangoproject.com/en/1.1/modindex/" target="_blank">módulos inclusos para fazer 54131998944535 coisas</a>. Porém, diferente de frameworks como <a title="Posts sobre Pylons" rel="nofollow" href="http://www.franciscosouza.com.br/tag/pylons/" target="_self">Pylons</a> e <a rel="nofollow" href="http://vraptor.caelum.com.br" target="_blank">VRaptor</a>, o Django não possui no seu conjunto de módulos uma API RESTful prontinha pra usar, sem complicações. O que a comunidade geralmente faz nestes casos? Desenvolve a API que falta. Por interesse, curiosidade e aprendizado, fui atrás de algumas dessas APIs, para efetuar alguns testes.<span id="more-572"></span>Vasculhando pela internet, encontrei diversos artigos e projetos sobre o assunto. O básico do básico seria a definição de uma classe, que deveria ser estendida para a criação de um resource. Veja o código da classe, retirado do <a rel="nofollow" href="http://www.djangosnippets.org/snippets/1071/" target="_blank">Django snippets</a>:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">class</span> RestView<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #66cc66;">&amp;</span>quot<span style="color: #66cc66;">;&amp;</span>quot<span style="color: #66cc66;">;&amp;</span>quot<span style="color: #66cc66;">;</span><br />
&nbsp; &nbsp; Subclass this <span style="color: #ff7700;font-weight:bold;">and</span> add GET / POST / etc methods.<br />
&nbsp; &nbsp; <span style="color: #66cc66;">&amp;</span>quot<span style="color: #66cc66;">;&amp;</span>quot<span style="color: #66cc66;">;&amp;</span>quot<span style="color: #66cc66;">;</span><br />
&nbsp; &nbsp; allowed_methods = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'GET'</span>, <span style="color: #483d8b;">'PUT'</span>, <span style="color: #483d8b;">'POST'</span>, <span style="color: #483d8b;">'DELETE'</span>, <span style="color: #483d8b;">'HEAD'</span>, <span style="color: #483d8b;">'OPTIONS'</span><span style="color: black;">&#41;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__call__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, request, <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; method = nonalpha_re.<span style="color: black;">sub</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>, request.<span style="color: black;">method</span>.<span style="color: black;">upper</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> method <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">allowed_methods</span> <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, method<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">method_not_allowed</span><span style="color: black;">&#40;</span>method<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">getattr</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, method<span style="color: black;">&#41;</span><span style="color: black;">&#40;</span>request, <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> method_not_allowed<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, method<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; response = HttpResponse<span style="color: black;">&#40;</span><span style="color: #483d8b;">'Method not allowed: %s'</span> <span style="color: #66cc66;">%</span> method<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; response.<span style="color: black;">status_code</span> = <span style="color: #ff4500;">405</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> response</div></td></tr></tbody></table></div>
<p>Com um pouco de introspecção (bem pouco), o método <em>__call__</em> analisa o objeto <em>request</em> e faz a chamada a um método (do objeto <em>RestView</em>) de acordo com o método da requisição (HTTP, aqueles verbos legais, tipo <em>PUT, POST, GET, DELETE</em>). Basicamente, um <em>resource</em> seria uma classe descendente de RestView. Na nossa classe resource, implementaríamos um método chamado <em>GET</em> para tratar as requisições <em>GET</em>, um método <em>POST</em> para tratar as requisições <em>POST</em>, e assim sucessivamente. Veja um exemplo de <em>resource</em></p>
<p>:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">class</span> UserView<span style="color: black;">&#40;</span>RestView<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> GET<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, request, user_id<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'Este método obtém um usuário e renderiza um template passando tal usuário como parâmetro'</span><span style="color: #483d8b;">''</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #dc143c;">user</span> = get_object_or_404<span style="color: black;">&#40;</span>User, pk = user_id<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> render_to_response<span style="color: black;">&#40;</span><span style="color: #483d8b;">'ver_usuario.html'</span>, <span style="color: #008000;">locals</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, context_instance = RequestContext<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> PUT<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, request, user_id<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'Este método atualiza um usuário no banco de dados'</span><span style="color: #483d8b;">''</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #dc143c;">user</span> = get_object_or_404<span style="color: black;">&#40;</span>User, pk = user_id<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #dc143c;">user</span>.<span style="color: black;">name</span> = request.<span style="color: black;">POST</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'user_name'</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #dc143c;">user</span>.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponseRedirect<span style="color: black;">&#40;</span>reverse<span style="color: black;">&#40;</span><span style="color: #483d8b;">'users.views.list_users'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Assim, poderíamos fazer o seguinte mapeamento no <em>urls.py</em>, para a classe acima:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">urlpatterns = patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; ...<br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^user/(<span style="color: #000099; font-weight: bold;">\d</span>+)/$'</span>, UserView<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,<br />
&nbsp; &nbsp; ...<br />
<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Note que um objeto é passado por parâmetro, e não a classe em si.  Esta solução funciona, pelo menos para trabalhar com diferentes tipos de requisição a uma mesma URL. Mas e no caso de queremos explorar mais a REST, com uso de tecnologias como JSON e <a title="Posts sobre XML" href="http://www.franciscosouza.com.br/tag/xml/">XML</a>? Certamente, nossa classe <em>RestView</em> não é capaz de nos atender, seria necessário estendê-la, ou simplesmente procurar uma API completa para trabalhar com REST no Django. Existem duas ferramentas muito boas aqui: <a href="http://code.google.com/p/django-rest/" target="_blank">django-rest</a> e <a href="http://bitbucket.org/jespern/django-piston/" target="_blank">django-piston</a>, sendo a segunda uma incrível e completa ferramenta para trabalhar com diversos recursos, como integração com os <em>models </em>e <em>forms </em>do Django; autenticação plugável (incluindo uma interface transparente para trabalhar com <a href="http://oauth.net/" target="_blank">OAuth</a>. Pelas características, vemos que o Piston é muito mais do que uma API RESTful, é uma ferramenta indispensável ao desenvolvedor Django :)  Apesar de toda a empolgação com o Piston, vamos deixar ele parar depois. Antes, vamos ao django-rest. Trata-se de uma interface RESTful, quem fornece integração com os <em>models</em> e também algumas <em>generic views</em> inclusas no pacote, facilitando a criação de CRUDs, por exemplo. Existem ainda outros projetos interessantes, como o <a rel="nofollow" href="http://code.google.com/p/django-restful-model-views/" target="_blank">django-restful-models-views</a>, que é uma aplicação plugável, mas vou abordar aqui apenas as ferramentas citadas no parágrafo anterior.  Basicamente, o django-rest trabalha de duas formas: &#8220;semi-automático&#8221;, onde fornecemos o modelo e ele &#8220;se vira&#8221; (semelhante às <em>generic views</em>); ou de forma manual, onde configuramos os <em>resources</em> manualmente, muito comum quando não estamos trabalhando restritamente com <em>models</em>. Um exemplo de código ligado ao model <em>User</em>, que possui os atributos <em>name </em>e <em>age</em>, seria o seguinte (arquivo <em>urls.py</em></p>
<p>):</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span>.<span style="color: black;">urls</span>.<span style="color: black;">defaults</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span><br />
<span style="color: #ff7700;font-weight:bold;">from</span> django_restapi.<span style="color: black;">model_resource</span> <span style="color: #ff7700;font-weight:bold;">import</span> Collection<br />
<span style="color: #ff7700;font-weight:bold;">from</span> django_restapi.<span style="color: black;">responder</span> <span style="color: #ff7700;font-weight:bold;">import</span> TemplateResponder<br />
<span style="color: #ff7700;font-weight:bold;">from</span> users.<span style="color: black;">models</span> <span style="color: #ff7700;font-weight:bold;">import</span> User<br />
<br />
user_resource = Collection<span style="color: black;">&#40;</span><br />
&nbsp; &nbsp; queryset = User.<span style="color: black;">objects</span>.<span style="color: #008000;">all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>,<br />
<span style="display:block;background-color:#ffff66">&nbsp; &nbsp; permitted_methods = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'GET'</span>, <span style="color: #483d8b;">'POST'</span>, <span style="color: #483d8b;">'PUT'</span>, <span style="color: #483d8b;">'DELETE'</span><span style="color: black;">&#41;</span>,<br /></span>&nbsp; &nbsp; responder = TemplateResponder<span style="color: black;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; template_dir = <span style="color: #483d8b;">'users'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; template_object_name = <span style="color: #483d8b;">'my_user'</span>,<br />
&nbsp; &nbsp; <span style="color: black;">&#41;</span><br />
<span style="color: black;">&#41;</span><br />
<br />
urlpatterns = patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; url<span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^users/(.*?)/?$'</span>, user_resource, <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>, <span style="color: #483d8b;">'user_detail'</span><span style="color: black;">&#41;</span>,<br />
<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>O objeto <em>user_resource</em> armazena as configurações do nosso <em>resource</em>. Note o atributo <em>responder</em>, que armazena o tipo de resposta. Aqui, poderíamos utilizar além de <em>TemplateResponder</em>, <em>JSONResponder</em>, <em>XMLResponder</em>, dentre outros tipos de retorno. Na linha 8, definimos os métodos que serão permitidos. Assim, este <em>resource</em> responderá pelas seguintes requisições:</p>
<ul>
<li>GET /users: Uma lista com todos os usuários;</li>
<li>GET /users/&lt;id&gt;: Visualização dos detalhes de um usuário;</li>
<li>POST /users: Cria um usuário;</li>
<li>PUT /users/&lt;id&gt;: Atualiza os dados de um usuário;</li>
<li>DELETE /users/&lt;id&gt;: Apaga um usuário.</li>
</ul>
<p>A documentação do <em>django-rest</em> é bem pobre. Para entender alguns comportamentos básicos, tive que olhar o código fonte da ferramenta. Por isso, vamos agora para a parte mais legal e interessante: <em>django-piston</em>.</p>
<p>Diferente do <em>django-rest</em>, o <em>django-piston</em> possui <a title="Documentação do django-piston" href="http://bitbucket.org/jespern/django-piston/wiki/Home" target="_blank">excelente documentação</a>, e também uma <a title="Grupo de discussão django-piston" href="http://groups.google.com/group/django-piston" target="_blank">comunidade ativa</a>, sendo a melhor alternativa quando se trata de API RESTful. Vamos rapidamente ver como tratar o exemplo com o model <em>User</em> descrito acima. É importante notar que o <em>django-piston</em> é bastante aconselhável para a criação de APIs. Assim, ele fornece MUITA coisa para trabalhar com APIs, é totalmente voltado para isto. Vamos distorcê-lo um pouco e fazer com que ele transfira dados para os templates.</p>
<p>Precisamos criar um <em>resource</em>, e para a criação de um <em>resource</em> é necessário que antes seja criado um <em>handler</em>. Os <em>handlers</em> são utilizados pelos <em>resource</em> para tratar as requisições. Um <em>handler </em>é um objeto modelado pela classe <em>BaseHandler</em> (por uma descendente de <em>BaseHandler</em>, para ser mais exato). Veja um exemplo de <em>handler</em>:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">class</span> UserHandler<span style="color: black;">&#40;</span>BaseHandler<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; allowed_methods = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'GET'</span>,<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; model = User<br />
<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> read<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, request, user_id = <span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> user_id <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; users = User.<span style="color: black;">objects</span>.<span style="color: #008000;">all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; template = <span style="color: #483d8b;">'user_list.html'</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #dc143c;">user</span> = User.<span style="color: black;">objects</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span>pk = user_id<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; template = <span style="color: #483d8b;">'user_detail.html'</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; template = <span style="color: #483d8b;">'users/%s'</span> <span style="color: #66cc66;">%</span> template<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> render_to_response<span style="color: black;">&#40;</span>template, <span style="color: #008000;">locals</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, context_instance = RequestContext<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Este handler é salvo em um arquivo chamado <em>handlers.py</em>, dentro do diretório de nossa aplicação. Agora, basta adicionar o mapeamento da URL e um <em>resource</em> baseado no nosso <em>UserHandler</em> passa a tratar as requisições, de forma RESTful. Veja como ficaria o <em>urls.py</em>:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span>.<span style="color: black;">urls</span>.<span style="color: black;">defaults</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span><br />
<span style="color: #ff7700;font-weight:bold;">from</span> piston.<span style="color: #dc143c;">resource</span> <span style="color: #ff7700;font-weight:bold;">import</span> Resource<br />
<span style="color: #ff7700;font-weight:bold;">from</span> users.<span style="color: black;">handlers</span> <span style="color: #ff7700;font-weight:bold;">import</span> UserHandler<br />
<br />
user_resource = Resource<span style="color: black;">&#40;</span>handler = UserHandler<span style="color: black;">&#41;</span><br />
<br />
urlpatterns = patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; url<span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'users/(?P&amp;lt;user_id&amp;gt;<span style="color: #000099; font-weight: bold;">\d</span>*)/$'</span>, user_resource<span style="color: black;">&#41;</span>,<br />
<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>O <em>django-piston</em> é uma ferramenta incrível, com muitos recursos, que provavelmente voltará a aparecer aqui no blog. Recomendo que mergulhe nela e veja como é simples criar APIs RESTful usando Django. Em breve eu falo mais sobre <em>django-piston</em> focando no desenvolvimento de APIs :)</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2009/12/30/aplicacoes-restful-no-django/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Construindo um CRUD com frameworks Python, Parte IV: Django Remake</title>
		<link>http://www.franciscosouza.com.br/2009/12/23/construindo-um-crud-com-frameworks-python-parte-iv-django-remake/</link>
		<comments>http://www.franciscosouza.com.br/2009/12/23/construindo-um-crud-com-frameworks-python-parte-iv-django-remake/#comments</comments>
		<pubDate>Wed, 23 Dec 2009 11:40:11 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[desenvolvimento de softwares]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[frameworks]]></category>

		<guid isPermaLink="false">http://www.franciscosouza.net/?p=547</guid>
		<description><![CDATA[Na segunda parte desta sequência de tutoriais sobre frameworks Python, eu apresentei a criação do CRUD em Django, fazendo &#8220;tudo na mão&#8221;. Fui intimado recomendado por alguns membros da comunidade Django Brasil a usar as generic views, interessante recurso do &#8230; <a href="http://www.franciscosouza.com.br/2009/12/23/construindo-um-crud-com-frameworks-python-parte-iv-django-remake/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Na <a title="Construindo um CRUD com frameworks Python, Parte II: Django" href="http://www.franciscosouza.com.br/2009/12/16/construindo-um-crud-com-frameworks-python-parte-ii-django/" target="_blank">segunda parte desta sequência de tutoriais sobre frameworks Python</a>, eu apresentei a criação do CRUD em <a title="Posts sobre Django" href="http://www.franciscosouza.com.br/tag/django/">Django</a>, fazendo &#8220;tudo na mão&#8221;. Fui <span style="text-decoration: line-through;">intimado </span>recomendado por alguns membros da comunidade <a title="Comunidade Django Brasil" href="http://www.djangobrasil.org" target="_blank" rel="nofollow">Django Brasil</a> a usar as <em>generic views</em>, interessante recurso do framework que permite trabalhar de forma muito mais rápida para geração de tarefas comuns, como CRUDs. Vamos então ao uso das <em>generic views</em>&#8230;<span id="more-547"></span>Ao invés de aproveitar o antigo projeto, para provar que a coisa realmente é rápida, vamos começar do zero, com um outro exemplo (quase igual). Trata-se de um sistema acadêmico para a Faculdade ABCDEF. Assim, vamos criar o projeto abcdef_academico com o comando:</p>
<pre>$ django-admin.py startproject abcdef_academico</pre>
<p>Após executarmos este comando, acessamos o diretório abcdef_academico, para criar a nossa aplicação, que chamaremos de <em>alunos</em>:</p>
<pre>$ django-admin.py startapp alunos</pre>
<p>Como já aprendemos, agora que criamos nossa aplicação e nosso projeto, devemos criar os models. No nosso caso, a classe aluno vai ter apenas os campos <em>nome</em> e <em>idade</em>, igualzinho era com a classe Usuario no exemplo anterior. Assim, o código <a title="Posts sobre Python" href="http://www.franciscosouza.com.br/tag/python/">Python</a> do <em>models.py </em>fica da seguinte forma:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">db</span> <span style="color: #ff7700;font-weight:bold;">import</span> models<br />
<br />
<span style="color: #808080; font-style: italic;"># Create your models here.</span><br />
<span style="color: #ff7700;font-weight:bold;">class</span> Aluno<span style="color: black;">&#40;</span>models.<span style="color: black;">Model</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; nome = models.<span style="color: black;">CharField</span><span style="color: black;">&#40;</span>max_length = <span style="color: #ff4500;">100</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; idade = models.<span style="color: black;">IntegerField</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Como vamos trabalhar com <em>generic views</em>, não vamos precisar criar o ModelForm. Passaremos para a view apenas o nosso model e ela vai se virar para gerenciar tudo, legal né?! =) Vamos apenas acertar o arquivo settings.py, com as mesmas configurações do <em>settings.py </em>do post anterior, sem as generic views. Para utilizar as generic views, nada muda no <em>settings.py</em>.</p>
<p>Agora podemos começar a trabalhar aonde a coisa acontece: no arquivo <em>urls.py</em>. Lá que definimos que vamos usar uma view genérica, mapeando uma URL para uma view genérica, que recebe como parâmetro algumas informações. Vamos primeiro criar o formulário de cadastro de um novo aluno. Para isto, adicione as duas linhas de import ao início do arquivo:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">views</span>.<span style="color: black;">generic</span> <span style="color: #ff7700;font-weight:bold;">import</span> create_update<br />
<span style="color: #ff7700;font-weight:bold;">from</span> alunos.<span style="color: black;">models</span> <span style="color: #ff7700;font-weight:bold;">import</span> Aluno</div></td></tr></tbody></table></div>
<p>Em seguida, configure um dicionário, chamado <em>params_novo_aluno</em>, que contém todos os parâmetros que a generic view <em>django.views.generic.create_update.create_object</em> (que vamos utilizar) necessita. Este dicionário, fica desta forma:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">params_novo_aluno = <span style="color: black;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'model'</span> : Aluno,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">'post_save_redirect'</span> : <span style="color: #483d8b;">'/alunos/'</span>,<br />
<span style="color: black;">&#125;</span></div></td></tr></tbody></table></div>
<p>O primeiro parâmetro, chamado <em>model, </em>refere-se ao modelo para o qual será gerado o formulário, a validação e a inserção. Já o segundo parâmetro, <em>post_save_redirect</em>, indica para onde o usuário será redirecionado após o objeto ser salvo no banco de dados. A URL <em>/alunos/</em> será responsável por listar todos os alunos cadastrados.</p>
<p>Ainda no arquivo urls.py, falta apenas definir a URL pela qual será acessado o tal formulário. Vamos adotar o padrão <em>/alunos/novo</em>, assim, adicionamos à tupla <em>urlpatterns</em> o seguinte item:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'alunos/novo/$'</span>, create_update.<span style="color: black;">create_object</span>, params_novo_aluno, <span style="color: #483d8b;">'novo_aluno'</span><span style="color: black;">&#41;</span>,</div></td></tr></tbody></table></div>
<p>Desta forma, já temos o mapeamento. Falta apenas o template! Note que em momento algum especificamos qual template utilizaremos. Isto ocorre por que este <em>generic view</em> padroniza o nome do template (mas é possível alterar, passando o parâmetro <em>template_name</em>). Desta forma, o padrão é que o arquivo de template se chame <em>_form.html</em> e fique dentro de um diretório com o nome da aplicação, no diretório de templates. No nosso caso, teremos então<em> templates/alunos/aluno_form.html</em>. O código do template fica bem simples também:</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></div></td><td><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">{% extends &quot;base.html&quot; %}<br />
<br />
{% block &quot;titulo&quot; %}Cadastro de novo aluno - {{ block.super }}{% endblock &quot;titulo&quot; %}<br />
<br />
{% block &quot;conteudo&quot; %}<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/form.html"><span style="color: #000000; font-weight: bold;">form</span></a> <span style="color: #000066;">action</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;&quot;</span> <span style="color: #000066;">method</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;post&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/table.html"><span style="color: #000000; font-weight: bold;">table</span></a> <span style="color: #000066;">border</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;0&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;60%&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {{ form.as_table }}<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/tr.html"><span style="color: #000000; font-weight: bold;">tr</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/th.html"><span style="color: #000000; font-weight: bold;">th</span></a>&gt;</span> <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/th.html"><span style="color: #000000; font-weight: bold;">th</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/td.html"><span style="color: #000000; font-weight: bold;">td</span></a>&gt;&lt;<a href="http://december.com/html/4/element/input.html"><span style="color: #000000; font-weight: bold;">input</span></a> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;submit&quot;</span> <span style="color: #000066;">value</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;Cadastrar!&quot;</span> <span style="color: #66cc66;">/</span>&gt;&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/td.html"><span style="color: #000000; font-weight: bold;">td</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/tr.html"><span style="color: #000000; font-weight: bold;">tr</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/table.html"><span style="color: #000000; font-weight: bold;">table</span></a>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/form.html"><span style="color: #000000; font-weight: bold;">form</span></a>&gt;</span><br />
{% endblock &quot;conteudo&quot; %}</div></td></tr></tbody></table></div>
<p>Agora que já temos nosso formulário de cadastro funcionando, podemos passar para a página de leitura, o R do CRUD. Vamos criar a página com listagem de todos os alunos e a página de visualização dos detalhes de um aluno. Para isto, utilizamos outro outro conjunto de <em>generic views</em>, incluso no módulo<em>django.views.generic.list_detail</em>. Adicione, então, o seguinte import ao início do arquivo <em>urls.py</em>:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">views</span>.<span style="color: black;">generic</span> <span style="color: #ff7700;font-weight:bold;">import</span> list_detail</div></td></tr></tbody></table></div>
<p>E criamos um novo pattern, relativo à URL /alunos, que mostrará uma lista de alunos. Então, fica a seguinte entrada no <em>urls.py</em>:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'alunos/$'</span>, list_detail.<span style="color: black;">object_list</span>, <span style="color: black;">&#123;</span> <span style="color: #483d8b;">'queryset'</span> : Aluno.<span style="color: black;">objects</span>.<span style="color: #008000;">all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: black;">&#125;</span>, <span style="color: #483d8b;">'lista_alunos'</span><span style="color: black;">&#41;</span>,</div></td></tr></tbody></table></div>
<p>No caso desta generic view, o nome padrão para o template é <em>&lt;model&gt;_list.html</em>. Novamente, construímos nosso template, que fica no caminho <em>templates/alunos/aluno_list.html</em>:</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></div></td><td><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">{% extends &quot;base.html&quot; %}<br />
<br />
{% block &quot;titulo&quot; %}Listagem de alunos - {{ block.super }}{% endblock &quot;titulo&quot; %}<br />
<br />
{% block &quot;conteudo&quot; %}<br />
<br />
<span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/ul.html"><span style="color: #000000; font-weight: bold;">ul</span></a>&gt;</span><br />
{% for aluno in object_list %}<br />
<span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/li.html"><span style="color: #000000; font-weight: bold;">li</span></a>&gt;&lt;<a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;{% url ver_aluno aluno.id %}&quot;</span>&gt;</span>{{ aluno.nome }}<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a>&gt;&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/li.html"><span style="color: #000000; font-weight: bold;">li</span></a>&gt;</span><br />
{% endfor %}<br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/ul.html"><span style="color: #000000; font-weight: bold;">ul</span></a>&gt;</span><br />
<br />
<span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;{% url novo_aluno %}&quot;</span>&gt;</span>Cadastrar novo aluno<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a>&gt;</span><br />
<br />
{% endblock &quot;conteudo&quot; %}</div></td></tr></tbody></table></div>
<p>Agora que temos a listagem de alunos pronta, vamos visualizar os detalhes de cada aluno. Para isto, utilizaremos a generic view <em>django.views.generic.list_detail.object_detail</em>. Esta view também recebe como parâmetro um queryset do Django, além de um id, que vem como parâmetro na URL, chamado <em>object_id</em>. Esta view também está capacitada a trabalhar com slugs. Assim, teremos nossa view sendo acessada por este endereço: <em>/alunos/&lt;object_id&gt;</em>. Para fazer isso, bastam apenas dois passos: adicionar um pattern ao <em>urls.py</em> e criar o template <em>aluno_detail.html</em> dentro do subdiretório <em>alunos</em> no diretório de templates. O mapeamento do pattern fica da seguinte forma:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'alunos/(?P&amp;lt;object_id&amp;gt;<span style="color: #000099; font-weight: bold;">\d</span>+)/$'</span>, list_detail.<span style="color: black;">object_detail</span>, <span style="color: black;">&#123;</span> <span style="color: #483d8b;">'queryset'</span> : Aluno.<span style="color: black;">objects</span>.<span style="color: #008000;">all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: black;">&#125;</span>, <span style="color: #483d8b;">'ver_aluno'</span><span style="color: black;">&#41;</span>,</div></td></tr></tbody></table></div>
<p>É importante que o parâmetro da URL se chame <em>object_id</em>, pois é o nome que a view recebe. O template fica também bem simples de entender:</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br /></div></td><td><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">{% extends &quot;base.html&quot; %}<br />
<br />
{% block &quot;titulo&quot; %}Detalhes do aluno {{ object.nome }} - {{ block.super }}{% endblock &quot;titulo&quot; %}<br />
<br />
{% block &quot;conteudo&quot; %}<br />
<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/table.html"><span style="color: #000000; font-weight: bold;">table</span></a> <span style="color: #000066;">border</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;0&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;60%&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/tr.html"><span style="color: #000000; font-weight: bold;">tr</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/th.html"><span style="color: #000000; font-weight: bold;">th</span></a>&gt;</span>Nome:<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/th.html"><span style="color: #000000; font-weight: bold;">th</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/td.html"><span style="color: #000000; font-weight: bold;">td</span></a>&gt;</span>{{ object.nome }}<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/td.html"><span style="color: #000000; font-weight: bold;">td</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/tr.html"><span style="color: #000000; font-weight: bold;">tr</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/tr.html"><span style="color: #000000; font-weight: bold;">tr</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/th.html"><span style="color: #000000; font-weight: bold;">th</span></a>&gt;</span>Idade:<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/th.html"><span style="color: #000000; font-weight: bold;">th</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/td.html"><span style="color: #000000; font-weight: bold;">td</span></a>&gt;</span>{{ object.idade }}<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/td.html"><span style="color: #000000; font-weight: bold;">td</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/tr.html"><span style="color: #000000; font-weight: bold;">tr</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/tr.html"><span style="color: #000000; font-weight: bold;">tr</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/th.html"><span style="color: #000000; font-weight: bold;">th</span></a>&gt;</span>Opções:<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/th.html"><span style="color: #000000; font-weight: bold;">th</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/td.html"><span style="color: #000000; font-weight: bold;">td</span></a>&gt;&lt;<a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;{% url editar_aluno object.id %}&quot;</span>&gt;</span>Editar<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a>&gt;</span> | <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;{% url apagar_aluno object.id %}&quot;</span>&gt;</span>Apagar<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a>&gt;&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/td.html"><span style="color: #000000; font-weight: bold;">td</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/tr.html"><span style="color: #000000; font-weight: bold;">tr</span></a>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/table.html"><span style="color: #000000; font-weight: bold;">table</span></a>&gt;</span><br />
<br />
{% endblock &quot;conteudo&quot; %}</div></td></tr></tbody></table></div>
<p>Neste template já criamos a referência para as páginas de edição e remoção do objeto. Para editar, precisamos apenas adicionar a chamada à view <em>django.views.generic.create_update.update_object </em>sem a necessidade de um novo template, pois esta view utiliza por padrão o mesmo template da view <em>create_object</em>. Assim, basta adicionar um novo pattern ao <em>urls.py</em>:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'alunos/(?P&lt;object_id&gt;<span style="color: #000099; font-weight: bold;">\d</span>+)/editar/$'</span>, create_update.<span style="color: black;">update_object</span>, params_novo_aluno, <span style="color: #483d8b;">'editar_aluno'</span><span style="color: black;">&#41;</span>,</div></td></tr></tbody></table></div>
<p>E, para finalizar, vamos para a parte de apagar o objeto. O Django trabalha com o padrão de partir para uma página de confirmação, então aqui precisaremos de um template chamado <em>aluno_confirm_delete.html</em>. Antes, mapeamos a URL <em>/alunos/&lt;object_id&gt;/apagar</em> para nossa generic view <em>django.views.generic.delete_object</em> e, em seguida, criamos o template necessário.</p>
<p>Para seguir o padrão, vou deixar uma parte sem postar código aqui no blog, mas o <a title="Projeto completo do CRUD utilizando generic views" href="http://bitbucket.org/franciscosouza/tutorial-django-remake-crud/" target="_blank">projeto completo está disponível no BitBucket</a>. E essa foi uma rápida revisão da criação de CRUDs usando Django! =)</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2009/12/23/construindo-um-crud-com-frameworks-python-parte-iv-django-remake/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Construindo um CRUD com frameworks Python, Parte II: Django</title>
		<link>http://www.franciscosouza.com.br/2009/12/16/construindo-um-crud-com-frameworks-python-parte-ii-django/</link>
		<comments>http://www.franciscosouza.com.br/2009/12/16/construindo-um-crud-com-frameworks-python-parte-ii-django/#comments</comments>
		<pubDate>Wed, 16 Dec 2009 11:00:00 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[desenvolvimento de softwares]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[frameworks]]></category>

		<guid isPermaLink="false">http://www.franciscosouza.net/?p=514</guid>
		<description><![CDATA[O segundo framework a ser abordado na sequência de posts sobre CRUD&#8217;s usando frameworks Python é o Django, o mais badalado entre os frameworks Python, com comunidade mais ativa. Assim como foi com o Pylons, vamos ver como Django trabalha &#8230; <a href="http://www.franciscosouza.com.br/2009/12/16/construindo-um-crud-com-frameworks-python-parte-ii-django/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>O segundo framework a ser abordado na sequência de posts sobre CRUD&#8217;s usando frameworks Python é o Django, o mais badalado entre os frameworks Python, com comunidade mais ativa. Assim como foi com o Pylons, vamos ver como Django trabalha com URL&#8217;s, MVC (ou MTV&#8230; &#8211; veja mais a frente), abstração do banco de dados, etc. Vamos ao mesmo caso: no portal da empresa ABC Informática, desenvolveremos o cadastro de usuários (que, por incrível que pareça, não tem login, senha, essas coisas, apenas nome e idade hehe)&#8230;<span id="more-514"></span></p>
<p>A instalação do Django também é bem simples e se da pelo easy_install, assim como no Pylons. Então, basta acessar o terminal e digitar o comando:</p>
<pre># easy_install -U django</pre>
<p>O Django fornece a ferramenta de linha de comando django-admin para criação de projetos e aplicações. Projetos Django se dividem em aplicações e é importante <a title="&quot;Desmistificando o conceito de Django Apps&quot;, por Henrique Bastos" href="http://henriquebastos.net/2009/11/13/desmistificando-o-conceito-de-django-apps/" target="_blank">entender o conceito de Django Apps</a>, para evitar o uso inadequado do framework. Vamos chamar nosso projeto de dj_portal_abc, então, para criar o projeto, basta executar o comando:</p>
<pre>$ django-admin.py startproject dj_portal_abc</pre>
<p>Será criado o diretório dj_portal_abc, com estrutura semelhante à seguinte:</p>
<p style="text-align: center; "><img class="aligncenter size-full wp-image-516" title="Estrutura de arquivos de um projeto novo do Django" src="http://www.franciscosouza.com.br/wp-content/uploads/2009/12/estrutura_django.png" alt="Estrutura de arquivos de um projeto novo Django" width="145" height="115" /></p>
<p>Sim, a estrutura é muito mais simples que a estrutura do Pylons, mas a criança ainda vai crescer :) Agora que criamos o projeto, vamos configurá-lo. Faremos apenas alguns ajustes básicos: o banco de dados utilizado; o idioma padrão e também a timezone padrão. Abra o arquivo settings.py e encontre o seguinte trecho de configuração de banco de dados:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">DATABASE_ENGINE = <span style="color: #483d8b;">''</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.</span><br />
DATABASE_NAME = <span style="color: #483d8b;">''</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Or path to database file if using sqlite3.</span><br />
DATABASE_USER = <span style="color: #483d8b;">''</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Not used with sqlite3.</span><br />
DATABASE_PASSWORD = <span style="color: #483d8b;">''</span> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Not used with sqlite3.</span><br />
DATABASE_HOST = <span style="color: #483d8b;">''</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Set to empty string for localhost. Not used with sqlite3.</span><br />
DATABASE_PORT = <span style="color: #483d8b;">''</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Set to empty string for default. Not used with sqlite3.</span></div></td></tr></tbody></table></div>
<p>Altere a variável <em>DATABASE_ENGINE</em> para sqlite3 e a variável <em>DATABASE_NAME</em> para portal_abc.db, ficando assim (note as linhas em destaque):</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">DATABASE_ENGINE = <span style="color: #483d8b;">'sqlite3'</span><br />
DATABASE_NAME = <span style="color: #483d8b;">'portal_abc.db'</span><br />
DATABASE_USER = <span style="color: #483d8b;">''</span><br />
DATABASE_PASSWORD = <span style="color: #483d8b;">''</span><br />
DATABASE_HOST = <span style="color: #483d8b;">''</span><br />
DATABASE_PORT = <span style="color: #483d8b;">''</span></div></td></tr></tbody></table></div>
<p>Agora vamos alterar a <em>TIME_ZONE</em> para São Paulo e o idioma padrão para português brasileiro. Logo abaixo da configuração do banco de dados, você encontra as seguintes linhas no settings.py:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #808080; font-style: italic;"># Local time zone for this installation. Choices can be found here:</span><br />
<span style="color: #808080; font-style: italic;"># http://en.wikipedia.org/wiki/List_of_tz_zones_by_name</span><br />
<span style="color: #808080; font-style: italic;"># although not all choices may be available on all operating systems.</span><br />
<span style="color: #808080; font-style: italic;"># If running in a Windows environment this must be set to the same as your</span><br />
<span style="color: #808080; font-style: italic;"># system time zone.</span><br />
TIME_ZONE = <span style="color: #483d8b;">'America/Chicago'</span><br />
<br />
<span style="color: #808080; font-style: italic;"># Language code for this installation. All choices can be found here:</span><br />
<span style="color: #808080; font-style: italic;"># http://www.i18nguy.com/unicode/language-identifiers.html</span><br />
LANGUAGE_CODE = <span style="color: #483d8b;">'en-us'</span></div></td></tr></tbody></table></div>
<p>Configure a variável <em>TIME_ZONE</em> como America/Sao_Paulo e a variável <em>LANGUAGE_CODE</em> como pt-br, ficando assim:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">TIME_ZONE = <span style="color: #483d8b;">'America/Sao_Paulo'</span><br />
<br />
LANGUAGE_CODE = <span style="color: #483d8b;">'pt-br'</span></div></td></tr></tbody></table></div>
<p>Agora que terminamos de configurar o projeto, vamos criar nossa aplicação. Vamos novamente utilizar o django-admin.py para gerar uma aplicação. Como no caso de iniciar um projeto, usamos <em>startproject</em>, para iniciar uma aplicação, usamos <em>startapp</em>. Intuitivo, não?</p>
<pre>$ django-admin-py startapp usuarios</pre>
<p>Após executar este comando, temos um novo diretório e a estrutura mudou um pouco. O Django criou o diretório com o nome da aplicação, e colocou lá alguns arquivos: models.py, onde definimos nossos modelos; tests.py, onde definimos nossos testes unitários (e também doctests); e views.py, nossa controladora que tem nome estranho =P Vamos começar definindo nosso model. Diferente do SQL Alchemy, usado no Pylons, o Django implementa o modelo de ORM chamado ActiveRecord. <strong><span style="color: #ff0000;"><span style="font-weight: normal;"><span style="color: #000000;">Reinout van Rees</span></span> </span></strong>considera o pattern ActiveRecord excelente para pequenas queries, mas problemático para estruturas mais complexas. A disputa DataMapper x ActiveRecord, e a preferência por DataMapper, foi fator fundamental na decisão do SourceForge adotar Turbo Gears (outro framework Python, que também utiliza SQL Alchemy, muito influenciado pelo Pylons) ao invés Django, Ruby on Rails ou Cake PHP.</p>
<p>&#8220;Sem querer querendo&#8221;, eu vou apresentar um pouco uma comparação entre ActiveRecord e DataMapper em Python, estabelecida nas ferramentas Django ORM vs. SQL Alchemy. No meu exemplo mega simples, ActiveRecord será a melhor resposta sem sombra de dúvidas, mas não deixe de ler sobre o assunto para formar uma opinião.</p>
<p><strong>Definindo o Model</strong></p>
<p>No Django, os models são definidos dentro da aplicação, no módulo <em>models.py</em>. Cada model é uma classe que herda de <em>django.db.models.Model</em>. Abaixo segue nosso model Usuario:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">class</span> Usuario<span style="color: black;">&#40;</span>models.<span style="color: black;">Model</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; nome = models.<span style="color: black;">CharField</span><span style="color: black;">&#40;</span>max_length=<span style="color: #ff4500;">100</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; idade = models.<span style="color: black;">IntegerField</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Note que a classe ficou bem simples. Agora, vamos dizer ao Django que vamos utilizar a aplicação <em>usuarios</em> em nosso projeto <em>dj_portal_abc </em>e depois criar o banco de dados. Para isso, basta abrir o arquivo settings.py novamente e buscar a tupla <em>INSTALLED_APPS</em>. Adicione ao final da tupla o nome da nossa aplicação,  ficando desta forma a tupla:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">INSTALLED_APPS = <span style="color: black;">&#40;</span><br />
&nbsp; &nbsp; <span style="color: #483d8b;">'django.contrib.auth'</span>,<br />
&nbsp; &nbsp; <span style="color: #483d8b;">'django.contrib.contenttypes'</span>,<br />
&nbsp; &nbsp; <span style="color: #483d8b;">'django.contrib.sessions'</span>,<br />
&nbsp; &nbsp; <span style="color: #483d8b;">'django.contrib.sites'</span>,<br />
&nbsp; &nbsp; <span style="color: #483d8b;">'usuarios'</span>,<br />
<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Agora basta utilizar o <em>manage.py</em>, que permite gerenciar o banco de dados e também a execução da aplicação. Para criar as tabelas no banco de dados, rodamos o comando:</p>
<pre>$ python manage.py syncdb</pre>
<p>Como a aplicação <em>django.contrib.auth</em> está instalada, ele vai perguntar se desejamos criar um usuário. Já que este recurso não vai ser utilizado, podemos simplesmente responder &#8220;no&#8221;.</p>
<p><strong>&#8220;Controllers&#8221; e URL&#8217;s no Django</strong></p>
<p>Como visto no começo, controllers são chamados de views no Django. Assim, definimos nossas funções de controle no módulo <em>views.py</em> da nossa aplicação. O Django não fornece um padrão de acesso às URL&#8217;s, sendo necessário configurar todas as URLs para uso. A ideia de usar REST com Django fica como assunto de um próximo post. Neste CRUD, vamos seguir o padrão torto de trabalhar de maneira &#8220;não-RESTful&#8221;.</p>
<p>Vamos trabalhar na mesma ordem, criando primeiramente a view responsável por listar os usuários. Vamos chamá-la de <em>listar_usuarios</em>. Dentro do nosso arquivo <em>views.py</em>, da aplicação <em>usuarios</em>, adicionamos o seguinte código:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> listar_usuarios<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; usuarios = Usuario.<span style="color: black;">objects</span>.<span style="color: #008000;">all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> render_to_response<span style="color: black;">&#40;</span><span style="color: #483d8b;">'usuarios/listar.html'</span>, <span style="color: #008000;">locals</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, context_instance=RequestContext<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Após criar a view, precisamos mapeá-la na configuração de urls. Abra o módulo <em>urls.py</em> e adicione ao objeto <em>urlpatterns</em> o item respectivo à view criada. Ficará desta forma:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">urlpatterns = patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Example:</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># (r'^dj_portal_abc/', include('dj_portal_abc.foo.urls')),</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Uncomment the admin/doc line below and add 'django.contrib.admindocs'</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># to INSTALLED_APPS to enable admin documentation:</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># (r'^admin/doc/', include('django.contrib.admindocs.urls')),</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Uncomment the next line to enable the admin:</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># (r'^admin/', include(admin.site.urls)),</span><br />
<span style="display:block;background-color:#ffff66">&nbsp; &nbsp; <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^usuarios/$'</span>, <span style="color: #483d8b;">'usuarios.views.listar_usuarios'</span><span style="color: black;">&#41;</span>,<br /></span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Vemos na linha 11 (em destaque) a configuração: dizemos que o endereço <em>/usuarios/</em> será tratado pela view <em>listar_usuarios</em>. Por mais chato que isso possa parecer, tem que ser feito assim, infelizmente. Se executarmos o servidor agora, através do comando</p>
<pre>$ python manage.py runserver</pre>
<p>obteremos um erro: <em>TemplateDoesNotExist at /usuarios/</em>. Dentro da nossa view, utilizamos o atalho <em>render_to_response</em>, para renderizar nosso template &#8216;usuarios/listar.html&#8217;, passando para ele todas as variáveis locais (no caso, apenas a variável <em>usuarios</em>). Mas em que momento definimos este template? Em momento algum!</p>
<p>Vamos, antes de mais nada, configurar no settings.py qual será nosso diretório com os templates. Assim, criamos o diretório <em>templates</em> na raiz do nosso projeto (junto aos arquivos <em>manage.py</em> e <em>settings.py</em>), e abrimos o settings.py para indicar que aquele será nosso diretório de templates, na tupla <em>TEMPLATE_DIRS</em>. Para obter o caminho absoluto, fazemos uso do módulo os, da biblioteca padrão do Python. Assim, adiciona as duas linhas ao começo do arquivo settings.py:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span><br />
RAIZ_DO_PROJETO = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">abspath</span><span style="color: black;">&#40;</span>__file__<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Em seguida, altere a tupla <em>TEMPLATE_DIRS</em>, para que fique desta forma:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">TEMPLATE_DIRS = <span style="color: black;">&#40;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Put strings here, like &amp;quot;/home/html/django_templates&amp;quot; or &amp;quot;C:/www/django/templates&amp;quot;.</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Always use forward slashes, even on Windows.</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Don't forget to use absolute paths, not relative paths.</span><br />
&nbsp; &nbsp; <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>RAIZ_DO_PROJETO, <span style="color: #483d8b;">'templates'</span><span style="color: black;">&#41;</span><br />
<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Após isso, criamos o arquivo <em>base.html</em>, que é nosso template que servirá de base. Este arquivo deve ficar dentro do diretório <em>templates</em>, e tem simplesmente o seguinte código:</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/html.html"><span style="color: #000000; font-weight: bold;">html</span></a>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/head.html"><span style="color: #000000; font-weight: bold;">head</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/title.html"><span style="color: #000000; font-weight: bold;">title</span></a>&gt;</span>{% block &quot;titulo&quot; %}ABC Informática{% endblock &quot;titulo&quot; %}<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/title.html"><span style="color: #000000; font-weight: bold;">title</span></a>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/head.html"><span style="color: #000000; font-weight: bold;">head</span></a>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/body.html"><span style="color: #000000; font-weight: bold;">body</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; {% block &quot;conteudo&quot; %}<br />
&nbsp; &nbsp; &nbsp; &nbsp; {% endblock &quot;conteudo&quot; %}<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/body.html"><span style="color: #000000; font-weight: bold;">body</span></a>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/html.html"><span style="color: #000000; font-weight: bold;">html</span></a>&gt;</span></div></td></tr></tbody></table></div>
<p>Após esta definição, crie o template da listagem de usuários, dentro do diretório <em>templates/usuarios</em>, com o nome <em>listar.html</em>.  Este template fica com o seguinte código:</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></div></td><td><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">{% extends &quot;base.html&quot; %}<br />
<br />
{% block &quot;titulo&quot; %}Listagem de usuários - {{ block.super }}{% endblock &quot;titulo&quot; %}<br />
<br />
{% block &quot;conteudo&quot; %}<br />
<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/ul.html"><span style="color: #000000; font-weight: bold;">ul</span></a>&gt;</span><br />
&nbsp; &nbsp; {% for usuario in usuarios %}<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/li.html"><span style="color: #000000; font-weight: bold;">li</span></a>&gt;&lt;<a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;{% url usuarios.views.ver_usuario usuario.id %}&quot;</span>&gt;</span>{{ usuario.nome }}<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a>&gt;&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/li.html"><span style="color: #000000; font-weight: bold;">li</span></a>&gt;</span><br />
&nbsp; &nbsp; {% endfor %}<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/ul.html"><span style="color: #000000; font-weight: bold;">ul</span></a>&gt;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;{% url usuarios.views.novo %}&quot;</span>&gt;</span>Cadastrar novo usuário<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a>&gt;</span><br />
<br />
{% endblock &quot;conteudo&quot; %}</div></td></tr></tbody></table></div>
<p>Novamente, não vou postar o código de todos os templates, para evitar que o post cresça muito. Daqui pra frente, colocarei todos os templates no pastebin e todo o código estará disponível no Bitbucket.</p>
<p>Para não ficar abrindo e mapeando toda hora as URLs, vamos acessar o arquivo e mapear todas elas:</p>
<ul>
<li>/usuarios: Uma lista com todos os usuários;</li>
<li>/usuarios/novo: Cria um novo usuário (exibe o formulário e também processa o formulário);</li>
<li>/usuarios/{id}: Exibe os dados de um usuário (visualização);</li>
<li>/usuarios/{id}/apagar: Apaga um usuário do banco de dados;</li>
<li>/usuarios/{id}/editar: Edita os dados de um usuário.</li>
</ul>
<p>Assim, nosso arquivo <em>urls.py</em> fica assim:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span>.<span style="color: black;">urls</span>.<span style="color: black;">defaults</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span><br />
<br />
urlpatterns = patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>,<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Example:</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># (r'^dj_portal_abc/', include('dj_portal_abc.foo.urls')),</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Uncomment the admin/doc line below and add 'django.contrib.admindocs'</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># to INSTALLED_APPS to enable admin documentation:</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># (r'^admin/doc/', include('django.contrib.admindocs.urls')),</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Uncomment the next line to enable the admin:</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># (r'^admin/', include(admin.site.urls)),</span><br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^usuarios/$'</span>, <span style="color: #483d8b;">'usuarios.views.listar_usuarios'</span><span style="color: black;">&#41;</span>,<br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^usuarios/novo/$'</span>, <span style="color: #483d8b;">'usuarios.views.novo'</span><span style="color: black;">&#41;</span>,<br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^usuarios/(?P&lt;id&gt;<span style="color: #000099; font-weight: bold;">\d</span>+)/$'</span>, <span style="color: #483d8b;">'usuarios.views.ver_usuario'</span><span style="color: black;">&#41;</span>,<br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^usuarios/(?P&lt;id&gt;<span style="color: #000099; font-weight: bold;">\d</span>+)/apagar/$'</span>, <span style="color: #483d8b;">'usuarios.views.apagar'</span><span style="color: black;">&#41;</span>,<br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^usuarios/(?P&lt;id&gt;<span style="color: #000099; font-weight: bold;">\d</span>+)/editar/$'</span>, <span style="color: #483d8b;">'usuarios.views.editar'</span><span style="color: black;">&#41;</span>,<br />
<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Vamos agora criar todas essas views mapeadas. Vamos fazer na ordem: construir o formulário de cadastro, antes de tudo. Antes de criar a nossa view <em>novo</em>, definiremos o formulário, utilizando o recurso de formulário do Django (Django Forms). Para isto, crie um arquivo chamado <em>forms.py</em> dentro do diretório da aplicação <em>usuarios</em>. Este arquivo conterá nosso form, que é uma classe que herda da classe <em>django.forms.Form</em>. Além da classe <em>django.forms.Form</em>, o Django Forms fornece a classe <em>django.forms.ModelForm</em>, que se integra com os models e faz quase tudo de forma transparente. Veja como ficou a classe <em>UsuarioForm</em>:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">class</span> UsuarioForm<span style="color: black;">&#40;</span>ModelForm<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">class</span> Meta:<br />
&nbsp; &nbsp; &nbsp; &nbsp; model = Usuario</div></td></tr></tbody></table></div>
<p>Note que o Django faz tudo &#8220;por baixo dos panos&#8221;, relacionando a classe de modelo com o formulário. Também seria possível definir manualmente todos os campos. Para mais detalhes sobre Django Forms, consulte a <a title="Documentação oficial do Django Forms" href="http://docs.djangoproject.com/en/dev/topics/forms/" target="_blank">documentação oficial</a>.</p>
<p>Com a classe de formulário definida, podemos partir agora para nossa <em>view</em>, que fica com o seguinte código:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> novo<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> request.<span style="color: black;">method</span> == <span style="color: #483d8b;">'POST'</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; form = UsuarioForm<span style="color: black;">&#40;</span>request.<span style="color: black;">POST</span><span style="color: black;">&#41;</span><br />
<span style="display:block;background-color:#ffff66">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> form.<span style="color: black;">is_valid</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:<br /></span><span style="display:block;background-color:#ffff66">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; form.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /></span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponseRedirect<span style="color: black;">&#40;</span>reverse<span style="color: black;">&#40;</span><span style="color: #483d8b;">'usuarios.views.listar_usuarios'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; form = UsuarioForm<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> render_to_response<span style="color: black;">&#40;</span><span style="color: #483d8b;">'usuarios/novo.html'</span>, <span style="color: #008000;">locals</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, context_instance=RequestContext<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Note que o Django faz algumas &#8220;mágicas&#8221; nas linhas destacadas: validação automática e salva os dados no banco de dados. Tudo por causa da uma forte e acoplada integração com os models. Eu sei que isso de perguntar se o método do <em>request</em> é <em>POST</em> lembra um pouco PHP, mas é a forma como geralmente se trabalha nas views :)</p>
<p>Agora é só definir o template, que recebe o formulário pela variável <em>forms</em>. O código do template está aqui: <a rel="nofollow" href="http://pastebin.com/f1479663c" target="_blank">http://pastebin.com/f1479663c</a>. Nossa view e nosso template estão prontos, vamos seguir a ordem e criar agora a view de visualização dos dados, chamada <em>ver_usuario</em>. Seu código fica bem simples:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> ver_usuario<span style="color: black;">&#40;</span>request, <span style="color: #008000;">id</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; usuario = Usuario.<span style="color: black;">objects</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span>pk=<span style="color: #008000;">id</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> render_to_response<span style="color: black;">&#40;</span><span style="color: #483d8b;">'usuarios/ver.html'</span>, <span style="color: #008000;">locals</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, context_instance=RequestContext<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Depois de definir a view, basta construir o template. O código do template <em>usuarios/ver.html</em> é o seguinte: <a href="http://pastebin.com/f47a43b9a" target="_blank">http://pastebin.com/f47a43b9a</a>. Novamente, vou deixar a view <em>editar</em> por conta, e vou terminar na view <em>apagar</em>, que é a mais simples de toda:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> apagar<span style="color: black;">&#40;</span>request, <span style="color: #008000;">id</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; usuario = Usuario.<span style="color: black;">objects</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span>pk=<span style="color: #008000;">id</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; usuario.<span style="color: black;">delete</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponseRedirect<span style="color: black;">&#40;</span>reverse<span style="color: black;">&#40;</span><span style="color: #483d8b;">'usuarios.views.listar_usuarios'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>E pronto! =) Aí está, podemos rodar e testar nosso projeto. O código completo do projeto pode ser <a title="Projeto no Bitbucket" href="http://bitbucket.org/franciscosouza/tutorial-django-crud/" target="_blank">obtido no Bitbucket</a>.</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2009/12/16/construindo-um-crud-com-frameworks-python-parte-ii-django/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>Reduzindo a quantidade de acessos ao banco de dados no Django</title>
		<link>http://www.franciscosouza.com.br/2009/10/28/reduzindo-a-quantidade-de-acessos-ao-banco-de-dados-no-django/</link>
		<comments>http://www.franciscosouza.com.br/2009/10/28/reduzindo-a-quantidade-de-acessos-ao-banco-de-dados-no-django/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 02:13:00 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[desenvolvimento de softwares]]></category>
		<category><![CDATA[banco de dados]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://wp.franciscosouza.net/2009/10/28/reduzindo-a-quantidade-de-acessos-ao-banco-de-dados-no-django/</guid>
		<description><![CDATA[Um dos problemas que vemos com o uso do Django é a ausência do join nas consultas &#8220;padrões&#8221;. Por exemplo, se temos um model chamado Pessoa que tem um carro, fazemos dois selects (!) ao executar o seguinte código 12p &#8230; <a href="http://www.franciscosouza.com.br/2009/10/28/reduzindo-a-quantidade-de-acessos-ao-banco-de-dados-no-django/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Um dos problemas que vemos com o uso do Django é a ausência do join nas consultas &#8220;padrões&#8221;. Por exemplo, se temos um model chamado Pessoa que tem um carro, fazemos dois selects (!) ao executar o seguinte código<span id="more-133"></span></p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">p = Pessoa.<span style="color: black;">objects</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #008000;">id</span>=<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><br />
carro = p.<span style="color: black;">carro</span></div></td></tr></tbody></table></div>
<p>Na primeira linha é feito um select na tabela ligada à classe Pessoa pesquisando id = 1, e na segunda linha é feito um novo select na tabela ligada à classe Carros pesquisando o id da pessoa (fk) = 1.</p>
<p>Imagine que tenhamos o seguinte modelo de classes:</p>
<div class="separator" style="clear: both; text-align: center;"><a style="margin-left: 1em; margin-right: 1em;" href="http://4.bp.blogspot.com/_AewNgvR35uk/Suj82KfNEyI/AAAAAAAAAgQ/rJs4BfN_U_Y/s1600-h/class+diagram.png" target="_blank"><img src="http://4.bp.blogspot.com/_AewNgvR35uk/Suj82KfNEyI/AAAAAAAAAgQ/rJs4BfN_U_Y/s400/class+diagram.png" border="0" alt="" /></a></div>
<p>Basicamente o que eu quero é saber qual o continente de um cliente (id=1). Em Python/Django, basta fazer o seguinte:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">cliente = Cliente.<span style="color: black;">objects</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #008000;">id</span>=<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><br />
continente = cliente.<span style="color: black;">bairro</span>.<span style="color: black;">cidade</span>.<span style="color: black;">uf</span>.<span style="color: black;">pais</span>.<span style="color: black;">continente</span></div></td></tr></tbody></table></div>
<p>Mas e aí, quantas vezes eu vou no banco de dados fazendo isso? Vamos unir o interpretador interativo + o debug do Django! (:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&gt;&gt;&gt;</span> cliente = Cliente.<span style="color: black;">objects</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #008000;">id</span>=<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> continente = cliente.<span style="color: black;">bairro</span>.<span style="color: black;">cidade</span>.<span style="color: black;">uf</span>.<span style="color: black;">pais</span>.<span style="color: black;">continente</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">db</span> <span style="color: #ff7700;font-weight:bold;">import</span> connection<br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> q = connection.<span style="color: black;">queries</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> qq <span style="color: #ff7700;font-weight:bold;">in</span> q:<br />
... &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> qq<br />
...<br />
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'time'</span>: <span style="color: #483d8b;">'0.003'</span>, <span style="color: #483d8b;">'sql'</span>: u<span style="color: #483d8b;">'SELECT &quot;clientes_cliente&quot;.&quot;id&quot;, &quot;clientes_cliente&quot;.&quot;nome&quot;, &quot;clientes_cliente&quot;.&quot;idade&quot;, &quot;clientes_cliente&quot;.&quot;bairro_id&quot; FROM &quot;clientes_cliente&quot; WHERE &quot;clientes_cliente&quot;.&quot;id&quot; = 1 '</span><span style="color: black;">&#125;</span><br />
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'time'</span>: <span style="color: #483d8b;">'0.000'</span>, <span style="color: #483d8b;">'sql'</span>: u<span style="color: #483d8b;">'SELECT &quot;clientes_bairro&quot;.&quot;id&quot;, &quot;clientes_bairro&quot;.&quot;nome&quot;, &quot;clientes_bairro&quot;.&quot;cidade_id&quot; FROM &quot;clientes_bairro&quot; WHERE &quot;clientes_bairro&quot;.&quot;id&quot; = 1 '</span><span style="color: black;">&#125;</span><br />
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'time'</span>: <span style="color: #483d8b;">'0.000'</span>, <span style="color: #483d8b;">'sql'</span>: u<span style="color: #483d8b;">'SELECT &quot;clientes_cidade&quot;.&quot;id&quot;, &quot;clientes_cidade&quot;.&quot;nome&quot;, &quot;clientes_cidade&quot;.&quot;uf_id&quot; FROM &quot;clientes_cidade&quot; WHERE &quot;clientes_cidade&quot;.&quot;id&quot; = 1 '</span><span style="color: black;">&#125;</span><br />
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'time'</span>: <span style="color: #483d8b;">'0.000'</span>, <span style="color: #483d8b;">'sql'</span>: u<span style="color: #483d8b;">'SELECT &quot;clientes_uf&quot;.&quot;id&quot;, &quot;clientes_uf&quot;.&quot;sigla&quot;, &quot;clientes_uf&quot;.&quot;pais_id&quot; FROM &quot;clientes_uf&quot; WHERE &quot;clientes_uf&quot;.&quot;id&quot; = 1 '</span><span style="color: black;">&#125;</span><br />
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'time'</span>: <span style="color: #483d8b;">'0.000'</span>, <span style="color: #483d8b;">'sql'</span>: u<span style="color: #483d8b;">'SELECT &quot;clientes_pais&quot;.&quot;id&quot;, &quot;clientes_pais&quot;.&quot;nome&quot;, &quot;clientes_pais&quot;.&quot;continente_id&quot; FROM &quot;clientes_pais&quot; WHERE &quot;clientes_pais&quot;.&quot;id&quot; = 1 '</span><span style="color: black;">&#125;</span><br />
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'time'</span>: <span style="color: #483d8b;">'0.000'</span>, <span style="color: #483d8b;">'sql'</span>: u<span style="color: #483d8b;">'SELECT &quot;clientes_continente&quot;.&quot;id&quot;, &quot;clientes_continente&quot;.&quot;nome&quot; FROM &quot;clientes_continente&quot; WHERE &quot;clientes_continente&quot;.&quot;id&quot; = 1 '</span><span style="color: black;">&#125;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span></div></td></tr></tbody></table></div>
<p>Note: foram duas linhas de comando e <strong>SEIS</strong> acessos ao banco de dados. Foi feito um select para cada entidade. Mas e agora, tem como resolver isso? (: Graças a Deus, sim! Basta usar a ideia do <em><a href="http://docs.djangoproject.com/en/dev/ref/models/querysets/#id4" target="_blank">select_related</a></em>. Vamos fazer um novo teste usando select_related? Aí está:</p>
<div class="codecolorer-container python twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&gt;&gt;&gt;</span> cliente = Cliente.<span style="color: black;">objects</span>.<span style="color: black;">select_related</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #008000;">id</span>=<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> continente = cliente.<span style="color: black;">bairro</span>.<span style="color: black;">cidade</span>.<span style="color: black;">uf</span>.<span style="color: black;">pais</span>.<span style="color: black;">continente</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">db</span> <span style="color: #ff7700;font-weight:bold;">import</span> connection<br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> q = connection.<span style="color: black;">queries</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> qq <span style="color: #ff7700;font-weight:bold;">in</span> q:<br />
... &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> qq<br />
...<br />
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'time'</span>: <span style="color: #483d8b;">'0.010'</span>, <span style="color: #483d8b;">'sql'</span>: u<span style="color: #483d8b;">'SELECT &quot;clientes_cliente&quot;.&quot;id&quot;, &quot;clientes_cliente&quot;.&quot;nome&quot;, &quot;clientes_cliente&quot;.&quot;idade&quot;, &quot;clientes_cliente&quot;.&quot;bairro_id&quot;, &quot;clientes_bairro&quot;.&quot;id&quot;, &quot;clientes_bairro&quot;.&quot;nome&quot;, &quot;clientes_bairro&quot;.&quot;cidade_id&quot;, &quot;clientes_cidade&quot;.&quot;id&quot;, &quot;clientes_cidade&quot;.&quot;nome&quot;, &quot;clientes_cidade&quot;.&quot;uf_id&quot;, &quot;clientes_uf&quot;.&quot;id&quot;, &quot;clientes_uf&quot;.&quot;sigla&quot;, &quot;clientes_uf&quot;.&quot;pais_id&quot;, &quot;clientes_pais&quot;.&quot;id&quot;, &quot;clientes_pais&quot;.&quot;nome&quot;, &quot;clientes_pais&quot;.&quot;continente_id&quot;, &quot;clientes_continente&quot;.&quot;id&quot;, &quot;clientes_continente&quot;.&quot;nome&quot; FROM &quot;clientes_cliente&quot; INNER JOIN &quot;clientes_bairro&quot; ON (&quot;clientes_cliente&quot;.&quot;bairro_id&quot; = &quot;clientes_bairro&quot;.&quot;id&quot;) INNER JOIN &quot;clientes_cidade&quot; ON (&quot;clientes_bairro&quot;.&quot;cidade_id&quot; = &quot;clientes_cidade&quot;.&quot;id&quot;) INNER JOIN &quot;clientes_uf&quot; ON (&quot;clientes_cidade&quot;.&quot;uf_id&quot; = &quot;clientes_uf&quot;.&quot;id&quot;) INNER JOIN &quot;clientes_pais&quot; ON (&quot;clientes_uf&quot;.&quot;pais_id&quot; = &quot;clientes_pais&quot;.&quot;id&quot;) INNER JOIN &quot;clientes_continente&quot; ON (&quot;clientes_pais&quot;.&quot;continente_id&quot; = &quot;clientes_continente&quot;.&quot;id&quot;) WHERE &quot;clientes_cliente&quot;.&quot;id&quot; = 1 '</span><span style="color: black;">&#125;</span><br />
<span style="color: #66cc66;">&gt;&gt;&gt;</span></div></td></tr></tbody></table></div>
<p>Bem melhor: duas linhas de código, um select! Apenas um acesso ao banco, seu DBA não vai caçar você insanamente por acessar 800 milhões de vezes o banco de dados, e sua aplicação estará BEEEM mais rápida =D</p>
<p>Bom, aí fica a dica para os iniciantes (já que todos os blog tutorials ignoram isso de select_related). Good coding (:</p>
<p>O projeto deste exemplo está no Bitbucket: <a href="http://bitbucket.org/franciscosouza/exemplo_select/" target="_blank">http://bitbucket.org/franciscosouza/exemplo_select/</a>.</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2009/10/28/reduzindo-a-quantidade-de-acessos-ao-banco-de-dados-no-django/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Django com Admin e Flatpages no AppEngine</title>
		<link>http://www.franciscosouza.com.br/2009/10/19/django-com-admin-e-flatpages-no-appengine/</link>
		<comments>http://www.franciscosouza.com.br/2009/10/19/django-com-admin-e-flatpages-no-appengine/#comments</comments>
		<pubDate>Mon, 19 Oct 2009 14:00:00 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[desenvolvimento de softwares]]></category>
		<category><![CDATA[appengine]]></category>
		<category><![CDATA[cloud computing]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://wp.franciscosouza.net/2009/10/19/django-com-admin-e-flatpages-no-appengine/</guid>
		<description><![CDATA[No meu site (não no blog, apenas no site) estou utilizando Python + Django, na estrutura do Google AppEngine. Levar o Django do jeito &#8220;natural&#8221; para o AppEngine faz-nos perder alguns recursos interessantes, como o Admin e as Flatpages. Na &#8230; <a href="http://www.franciscosouza.com.br/2009/10/19/django-com-admin-e-flatpages-no-appengine/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>No meu site (não no blog, apenas no site) estou utilizando Python + Django, na estrutura do Google AppEngine. Levar o Django do jeito &#8220;natural&#8221; para o AppEngine faz-nos perder alguns recursos interessantes, como o Admin e as Flatpages.</p>
<p>Na página /sobre, por exemplo, eu estava fazendo algo bem escroto: escrevendo o conteúdo nu e cru no template. Isso não é bom, afinal de contas, qualquer alteração implicaria em um novo upload da aplicação. Eu precisava de algo dinâmico, sabia que existiam as Flatpages e tinha duas opções: buscar uma forma de usar as Flatpages (e o Admin) no AppEngine, ou desenvolver algo como um &#8220;gerenciador de conteúdos&#8221;, para que eu pudesse cadastrar minhas páginas e fazer todo o gerenciamento via web. Essas duas opções viraram passos: primeiro eu fui buscar, e encontrei&#8230;<span id="more-131"></span></p>
<p>O projeto <a href="http://code.google.com/p/app-engine-patch/" target="_blank">app-engine-patch</a> traz diversos recursos do Django para uso no AppEngine não presentes no Django padrão do Google App Engine (ou na versão SVN), como a interface do admin, o uso das funções de e-mail próprias do Django, uso da autenticação do Django, flatpages, o gerenciamento utilizando o <em>manage.py</em> (com manage.py upload, para enviar a aplicação, por exemplo) e <a href="http://code.google.com/p/app-engine-patch/wiki/GettingStarted" target="_blank">muito mais</a>!</p>
<p>Vou passar rapidamente pelo meu roteiro de migração, no começo tive dificuldades, mas no final foi muito de boa. Baixei o projeto exemplo, copiei o diretório <em>common</em> para dentro do meu projeto, fiz um &#8220;merge&#8221; do meu <em>settings.py </em>com o <em>settings.py</em> do projeto exemplo, substituí meu <em>manage.py</em> pelo <em>manage.py </em>de exemplo e estava lá, com suporte ao admin e às flatpages.</p>
<p>E agora a /sobre/ é uma flatpage. Não muda nada pra quem vê, mas pra quem gerencia, é um progresso e tanto (: Adicionalmente, resolvi disponibilizar o código do site no Bitbucket: <a href="http://bitbucket.org/franciscosouza/website/" target="_blank">http://bitbucket.org/franciscosouza/website/</a>.</p>
<p><strong>Observação: </strong>Um problema que tive foi o uso do meu e-mail no Google Apps, o app-engine-patch não permite fazer a migração do banco de dados ou qualquer acesso remoto usando um usuário de um domínio do Google Apps. Para migrar o banco de dados, você deve usar um Gmail ou outra conta Google (:</p>
<p><strong>Observação 2: </strong>Tive um outro problema com um índice para uso do admin. O AppEngine localmente não gerou o índice automaticamente, então tive que adicionar um índice ao <em>index.yaml</em>:</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">- kind: django_admin_log<br />
&nbsp; &nbsp; properties:<br />
&nbsp; &nbsp; - name: user<br />
&nbsp; &nbsp; - name: action_time<br />
&nbsp; &nbsp; direction: desc</div></td></tr></tbody></table></div>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2009/10/19/django-com-admin-e-flatpages-no-appengine/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>NASA escolhe Django para sua solução de cloud computing</title>
		<link>http://www.franciscosouza.com.br/2009/07/30/nasa-escolhe-django-para-sua-solucao-de-cloud-computing/</link>
		<comments>http://www.franciscosouza.com.br/2009/07/30/nasa-escolhe-django-para-sua-solucao-de-cloud-computing/#comments</comments>
		<pubDate>Thu, 30 Jul 2009 15:25:00 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[notícias]]></category>
		<category><![CDATA[cloud computing]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://wp.franciscosouza.net/2009/07/30/nasa-escolhe-django-para-sua-solucao-de-cloud-computing/</guid>
		<description><![CDATA[Uma excelente notícia para a comunidade Python: a NASA selecionou o Django como framework para sua plataforma de cloud computing, o Projeto NEBULA. De acordo com o site oficial, e uma tradução minha, mais ou menos feita ao pé da &#8230; <a href="http://www.franciscosouza.com.br/2009/07/30/nasa-escolhe-django-para-sua-solucao-de-cloud-computing/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Uma excelente notícia para a comunidade Python: a NASA selecionou o Django como framework para sua plataforma de cloud computing, o <a href="http://nebula.nasa.gov/" target="_blank">Projeto NEBULA</a>.</p>
<p>De acordo com o site oficial, e uma tradução minha, mais ou menos feita ao pé da letra, &#8220;o projeto NEBULA é um ambiente de cloud computing desenvolvido no NASA Ames Research Center, integrando um conjunto de soluções opensource. O objetivo é prover um ambiente de alta capacidade de processamento, armazenamento e conectividade, usando virtualização para ganho de escalabilidade e maior controle de custos&#8221;.<span id="more-117"></span></p>
<p>De acordo com o site oficial, o Django foi selecionado após um extensivo estudo de mercado, sendo considerado o framework de aplicações mais adequado para o projeto! :)</p>
<p>Para conhecer melhor o Projeto NEBULA, visite o <a href="http://nebula.nasa.gov/" target="_blank">site oficial</a>. Para conhecer melhor o Django, visite o <a href="http://www.djangoproject.com/" target="_blank">site oficial</a>, o <a href="http://www.djangobrasil.org/" target="_blank">site da comunidade brasileira</a> ou mesmo o livro <a href="http://www.aprendendodjango.com/" target="_blank">&#8220;Aprendendo Django no Planeta Terra&#8221;, </a>do <a href="http://www.marinhobrandao.com/" target="_blank">Marinho Brandão</a>.</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2009/07/30/nasa-escolhe-django-para-sua-solucao-de-cloud-computing/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Provedores brasileiros de hospedagem para Django</title>
		<link>http://www.franciscosouza.com.br/2009/07/16/provedores-brasileiros-de-hospedagem-para-django/</link>
		<comments>http://www.franciscosouza.com.br/2009/07/16/provedores-brasileiros-de-hospedagem-para-django/#comments</comments>
		<pubDate>Thu, 16 Jul 2009 11:00:00 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[open source]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[frameworks]]></category>
		<category><![CDATA[hospedagem]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://wp.franciscosouza.net/2009/07/16/provedores-brasileiros-de-hospedagem-para-django/</guid>
		<description><![CDATA[É sempre um assunto recorrente nas listas de discussão sobre Django e Python: provedores brasileiros com suporte a Django. Baseado nisto, gerei uma pequena lista, que pode ser incrementada com o tempo: Auriance Web Hosting: Suporta Django em todos os &#8230; <a href="http://www.franciscosouza.com.br/2009/07/16/provedores-brasileiros-de-hospedagem-para-django/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>É sempre um assunto recorrente nas listas de discussão sobre Django e Python: provedores brasileiros com suporte a Django. Baseado nisto, gerei uma pequena lista, que pode ser incrementada com o tempo:<span id="more-108"></span></p>
<ul>
<li><a href="http://www.auriance.net/" target="_blank">Auriance Web Hosting</a>: Suporta Django em todos os planos (mod_python);</li>
<li><a href="http://www.kinghost.com.br/" target="_blank">KingHost</a>: Suporta Django nos planos Linux Mega, Turbo e Nitro (mod_wsgi);</li>
<li><a href="http://www.locaweb.com.br/" target="_blank">Locaweb</a>: Suporta Django em todos os planos Linux (mod_wsgi);</li>
<li><a href="http://www.pytown.com/" target="_blank">PyTown</a>: Hospedagem especializada em Python. Suporta diversos frameworks (mais flexível);</li>
<li><a href="http://www.uolhost.com.br/" target="_blank">UOL Host</a>: Suporta Django em todos os planos Linux (mod_python);</li>
<li><a href="http://www.tehospedo.com.br/" target="_blank">TeHospedo</a>: Suporta Django em todos os planos Linux (FastCGI).</li>
</ul>
<p>Se você sabe algum, por favor <a href="http://www.franciscosouza.com.br/contato/" target="_blank">entre em contato comigo</a> e me passe! ;)</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2009/07/16/provedores-brasileiros-de-hospedagem-para-django/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Livro Aprendendo Django no Planeta Terra</title>
		<link>http://www.franciscosouza.com.br/2009/04/27/livro-aprendendo-django-no-planeta-terra/</link>
		<comments>http://www.franciscosouza.com.br/2009/04/27/livro-aprendendo-django-no-planeta-terra/#comments</comments>
		<pubDate>Mon, 27 Apr 2009 20:33:00 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[livros]]></category>

		<guid isPermaLink="false">http://wp.franciscosouza.net/2009/04/27/livro-aprendendo-django-no-planeta-terra/</guid>
		<description><![CDATA[Finalmente podemos baixar e comprar o livro Aprendendo Django no Planeta Terra, idealizado pelo Marinho Brandão! O livro, que é aberto, foi disponibilizado para download em PDF e também foi lançado em versão editada. Clique aqui para baixar e/ou aqui &#8230; <a href="http://www.franciscosouza.com.br/2009/04/27/livro-aprendendo-django-no-planeta-terra/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Finalmente podemos baixar e comprar o livro <a href="http://www.aprendendodjango.com/" target="_blank">Aprendendo Django no Planeta Terra</a>, idealizado pelo <a href="http://www.marinhobrandao.com/" target="_blank">Marinho Brandão</a>!<span id="more-72"></span></p>
<p>O livro, que é aberto, foi disponibilizado para download em PDF e também foi lançado em versão editada. <a href="http://www.aprendendodjango.com/download/" target="_blank">Clique aqui</a> para baixar e/ou <a href="http://www.aprendendodjango.com/comprar-o-livro/" target="_blank">aqui</a> para ver informações de compra.</p>
<p>Vale lembrar que o livro continua existindo em sua versão online, que pode ser acompanhada passo a passo no <a href="http://www.aprendendodjango.com/" target="_blank">site</a>.</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2009/04/27/livro-aprendendo-django-no-planeta-terra/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Flatpages no Django com debug desabilitado</title>
		<link>http://www.franciscosouza.com.br/2009/03/23/flatpages-no-django-com-debug-desabilitado/</link>
		<comments>http://www.franciscosouza.com.br/2009/03/23/flatpages-no-django-com-debug-desabilitado/#comments</comments>
		<pubDate>Mon, 23 Mar 2009 16:19:00 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[django]]></category>

		<guid isPermaLink="false">http://wp.franciscosouza.net/2009/03/23/flatpages-no-django-com-debug-desabilitado/</guid>
		<description><![CDATA[Quando saí do modo de desenvolvimento do Django, ainda brincando, nada sério. Tive um problema com as flatpages, que deixaram de aparecer. Futucando o settings.py, descobri que elas deixavam de aparecer somente quando o modo de Debug era desabilitado. Pesquisando &#8230; <a href="http://www.franciscosouza.com.br/2009/03/23/flatpages-no-django-com-debug-desabilitado/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Quando saí do modo de desenvolvimento do Django, ainda brincando, nada sério. Tive um problema com as flatpages, que deixaram de aparecer. Futucando o settings.py, descobri que elas deixavam de aparecer somente quando o modo de Debug era desabilitado.<span id="more-39"></span></p>
<div>Pesquisando na net e consultando o <a href="http://groups.google.com.br/group/django-brasil" target="_blank">django-brasil</a>, descobri que eu devo criar os arquivos 404.html e 500.html no diretório com os meus templates, pois o Django utiliza os mesmos. Estes arquivos representam erros de respectivos códigos (página não encontrada e erro interno do servidor).</div>
<div></div>
<div>Desta forma, você pode personalizar os erros facilmente. Mas lembre-se, você <span style="font-weight: bold;">sempre</span> deve ter os arquivos 404.html e 500.html no diretório dos templates!</div>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2009/03/23/flatpages-no-django-com-debug-desabilitado/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&quot;Brincando&quot; com o Django</title>
		<link>http://www.franciscosouza.com.br/2009/03/15/brincando-com-o-django/</link>
		<comments>http://www.franciscosouza.com.br/2009/03/15/brincando-com-o-django/#comments</comments>
		<pubDate>Sun, 15 Mar 2009 22:13:00 +0000</pubDate>
		<dc:creator>Francisco Souza</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[django]]></category>

		<guid isPermaLink="false">http://wp.franciscosouza.net/2009/03/15/brincando-com-o-django/</guid>
		<description><![CDATA[Nunca levei o Python a sério. Não quero ser perjorativo ao escrever isso. Quero dizer que nunca me imaginei ganhando dinheiro com a linguagem. Tinha interesse em conhecê-la, apenas, assim como recursos famosos e poderosos da linguagem (Zope, Django, dentre &#8230; <a href="http://www.franciscosouza.com.br/2009/03/15/brincando-com-o-django/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Nunca levei o Python a sério. Não quero ser perjorativo ao escrever isso. Quero dizer que nunca me imaginei ganhando dinheiro com a linguagem. Tinha interesse em conhecê-la, apenas, assim como recursos famosos e poderosos da linguagem (Zope, Django, dentre outros).<span id="more-37"></span></p>
<div>Agora o Django aparece como uma janela, uma oportunidade de inovar. Chutando uma estatística (e sendo generoso), creio que 90% dos desenvoldedores da minha cidade não sabem o que é Django. Ao que me proponho? Trazer o Django pra cá! Mostrar o quanto pode ser prazeroso ganhar dinheiro desenvolvendo softwares/sites e coisas do tipo. Prazos menores, preços compatíveis e pessoas (tanto clientes quanto desenvolvedores) satisfeitas! Taí, gostei da ideia&#8230;</div>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.franciscosouza.com.br/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.franciscosouza.com.br/2009/03/15/brincando-com-o-django/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 2.039 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2010-09-03 23:46:26 -->
