New Post

Rss

Showing posts with label Django. Show all posts
Showing posts with label Django. Show all posts
Thursday, March 8, 2012
no image

Migrations em Django com South

E quem nunca precisou adicionar ou remover alguma coluna, nas tabelas do seu banco de dados, depois que a aplicação já estava em produção? Os riscos existem (e são altos), e podem ser diminuidos através de processos automatizados.

Em um mundo ideal, o procedimento de deploy (para entregas contínuas) deve ser automatizado. Com o South, “migrar” a estrutura e os dados da sua base de dados para a versão presente em seu novo deploy, é simples, prático e 100% integrado ao Django.

O South é muito, mas muito simples de instalar. Utilizando o pip, basta o seguinte comando para termos os eggs em nosso PYTHONPATH:

$ pip install south

Não podemos esquecer de adicioná-lo ao INSTALLED_APPS do settings.py (afinal, trata-se de uma app Django):

INSTALLED_APPS = ( 'django.contrib.auth', ... 'south',)

Pronto! Você acabou de ganhar alguns comandos para construir as suas migrations.

Sem perder tempo, vamos construir uma app Django para que possamos demonstrar o uso doSouth:

$ python manage.py startapp blog# settings.pyINSTALLED_APPS = ( 'django.contrib.auth', ... 'south', 'blog',)

Vamos criar um modelo bem básico, com alguns campos (posteriormente, incrementaremos esta estrutura):

# blog/models.pyfrom django.db import modelsclass Blog(models.Model): titulo = models.CharField('Titulo', max_length=100) texto = models.TextField('Texto')

Através do comando schemamigration, com parâmetro –-initial, criaremos a nossa primeira migration:

$ python manage.py schemamigration blog --initial

Vale notar que o comando acima não cria nenhuma tabela no banco de dados. O que ele faz é criar um conjunto de instruções que representa este modelo. Na medida que são feitas alterações no modelo, é necessário gerar novas migrations, que serão sempre baseados nas estruturas já criadas.

Por exemplo, vamos de fato criar a tabela blog no banco de dados:

$ python manage.py migrate blogRunning migrations for blog: - blog:0001_initial - Loading initial data for blog. No fixtures found.

Se houvesse alguma fixture, o South faria o insert das informações para você.

A primeira migration foi criada. Como mencionado antes, a partir de agora toda migration criada será baseada na migration “anterior” (podemos deduzir a ordem das migrations através do prefixo numérico, no caso acima, o 0001 indica que esta é a primeira).

Vamos adicionar um campo no modelo (que equivale a uma coluna no banco de dados), para ilustrar a criação de novas migrations:

# blog/models.pyclass Blog(models.Model): titulo = models.CharField('Titulo', max_length=100) resumo = models.TextField('Resumo', blank=True, null=True) texto = models.TextField('Texto')

Não é mais necessário o uso do parâmetro -–initial, de agora em diante precisaremos do parâmetro –-auto (que construirá a migration automaticamente, de acordo com a primeira já existente):

$ python manage.py schemamigration blog --auto + Added field resumo on blog.BlogCreated 0002_auto__add_field_blog_resumo.py. You can now apply this migrationwith: ./manage.py migrate blog

Pronto! Uma nova migration foi criada… e com um nome bem intuitivo (repare no prefixo numérico). Basta darmos a ordem de replicar estas instruções no banco de dados:

$ python manage.py migrate blogRunning migrations for blog: - Migrating forwards to 0002_auto__add_field_blog_resumo. - blog:0002_auto__add_field_blog_resumo - Loading initial data for blog.No fixtures found.

A nova coluna foi inserida na tabela blog, sem necessitar de nenhuma intervenção manual. Se você ficou curioso para saber como essa “mágica” acontece, basta abrir as migrations e ver que são instruções escritas em Python, que interagem com o banco de dados “por trás” do ORM doDjango.

O South possui mais alguns recursos interessantes (como data migrations), que você pode conferir neste tutorial.

Tecnólogo em Análise e Desenvolvimento de Sistemas pelo Centro Universitário de Jaraguá do Sul (UNERJ), Técnico em Informática com ênfase em Sistemas de Informação pelo Centro Politécnico Geraldo Werninghaus (CEPEG). Desenvolvedor Web defensor dos padrões Web. Usuário Linux, apaixonado por Python e alucinado por Django. Escreve quando pode no http://www.klauslaube.com.br.

Veja perfil e 80 post(s)

Tuesday, August 16, 2011
no image

Ferramentas de testes em Django – Parte 1

Dando continuidade à série de posts sobre Django, vou indicar algumas ferramentas de testes para que você também possa deixar com que os testes guiem o desenvolvimento de suas aplicações.


Afinal, testar é preciso ;)


Sem dúvida nenhuma! Mas não espere que o framework adeque-se a você, você precisa ter a iniciativa de tentar compreender as melhores maneiras para escrever testes em Django.


Por exemplo, se você tem por hábito isolar os modelos para testá-los de forma unitária, pode passar por certa dor de cabeça com o Python/Django. Não que seja impossível, mas o comportamento default do framework é criar uma base de dados “fake” para você não precisar ter este trabalho.


Enfim, talvez a forma de utilizar estas ferramentas caiba em um outro post, o objetivo deste é apenas apresentá-las.


A unittest é uma biblioteca padrão do Python que ajuda (e muito) a escrever testes automatizados com a linguagem.


Os testes são escritos através de classes, onde utilizamos os esquemas de assertions para garantir o comportamento do código testado (nenhuma novidade até aqui). Para quem utiliza testes unitários no Java não vai sentir grandes mudanças na abordagem, já que a unittest é inspirada na JUnit (sendo muitas vezes até chamada de PyUnit):

import unittestfrom myapp.models import Animal class AnimalTestCase(unittest.TestCase): def setUp(self): self.lion = Animal.objects.create(name="lion", sound="roar") self.cat = Animal.objects.create(name="cat", sound="meow")  def testSpeaking(self): self.assertEquals(self.lion.speak(), 'The lion says "roar"') self.assertEquals(self.cat.speak(), 'The cat says "meow"')

O test runner padrão do Django irá procurar por subclasses de unittest.TestCase nos arquivos models.py e tests.py. A suíte de testes tenta facilitar ao máximo a sua vida… execute a seguinte instrução e confira se a sua aplicação está ok ou não:


Peraí que não acabou! Apresentando a TestCase


Testar aplicações Web com a unittest pode ser dureza. Pensando nisso o Django disponibiliza a TestCase, que estende a unittest adicionando funcionalidades como carregamento de fixtures, roteamento de urls e um client para fazer requisições Web e testar as suas views (o TestClient, detalhado mais abaixo).


Admito que escrever documentação de software não é o meu forte… mas com doctests pode-se documentar métodos ao mesmo tempo em que escreve-se testes!


A doctest é uma biblioteca padrão do Python que procura e interpreta docstrings na aplicação. A sintaxe nesses trechos de docstrings é diferenciada, simulando um interpretador interativo do Python:

# models.py from django.db import models class Animal(models.Model): """ An animal that knows how to make noise  # Create some animals >>> lion = Animal.objects.create(name="lion", sound="roar") >>> cat = Animal.objects.create(name="cat", sound="meow")  # Make 'em speak >>> lion.speak() 'The lion says "roar"' >>> cat.speak() 'The cat says "meow"' """ name = models.CharField(max_length=20) sound = models.CharField(max_length=20)  def speak(self): return 'The %s says "%s"' % (self.name, self.sound)

Assim como com a unittest, o test runner padrão do Django procurará por ocorrências de docstests em models.py e tests.py.


E como fazer para testar requisições Web? Por exemplo, você não quer testar a sua view de forma isolada, quer testar desde a parte de roteamento ao comportamento com o banco de dados, como se você se estivesse realmente visitando a página. Neste caso entra a test client.


Toda a classe TestCase possui uma instância da Django Test Client. Então escrever testes com requisições à sua aplicação fica muito simples utilizando classes:

from django.test import TestCase class SimpleTest(TestCase): def test_details(self): response = self.client.get('/customer/details/') self.assertEqual(response.status_code, 200)  def test_index(self): response = self.client.get('/customer/index/') self.assertEqual(response.status_code, 200)

É perfeitamente possível utilizar a test client em doctests também:

""">>> from django.test.client import Client>>> c = Client()>>> response = c.post('/login/', {'username': 'john',... 'password': 'smith'})>>> response.status_code200"""

Particularmente, tive a oportunidade de implementar testes unitários já no início do meu aprendizado em Django. Deixar os testes te guiarem é uma prática excelente!


Tudo parte do bom senso, óbvio. Nenhum processo ou ferramenta deveria substituir o “feeling” do profissional… também não é muito sadio ser extremamente “by the book“. Mas se puder utilizar testes para guiar o seu desenvolvimento, use-os!


Na segunda parte deste post pretendo apresentar algumas ferramentas que irão turbinar ainda mais o seu desenvolvimento orientado a testes.


Até lá!


Fonte: Klaus Laube

Saturday, August 13, 2011
no image

Ferramentas de testes em Django – Parte 2

No post anterior, conhecemos as ferramentas default para construção de testes automatizados em Django. Acontece que você pode “sair um pouco da caixa” e usufruir de ferramentas “third-party“, que enriquecerão o seu ambiente de desenvolvimento e lhe trarão maior segurança em seus testes de software.

É perfeitamente possível criar testes de aceitação em Django com a TestClient e lxml. Mas vamos ser sinceros, é deveras trabalhoso “parsear” os resultados das suas views.

Com a Splinter, uma ferramenta para testes de aplicações web, você pode automatizar ações executadas por navegadores, como visitar uma página, preencher um formulário ou clicar em um link; tudo isso sem preocupar-se com parsing, nós, DOM, nem nada do tipo:

from splinter.browser import Browserbrowser = Browser()# Visitar uma URLurl = "http://search.twitter.com"browser.visit(url)browser.fill('q', "#cobrateam")  # Procurar e clicar no botão 'search'button = browser.find_by_css("#searchButton input").first  # Interagir com os elementosbutton.click()if browser.is_text_present("No results for #cobrateam"): print "nobody likes us =("else: print "we're popular =)"

O que eu acho mais bacana nesta ferramenta são os seletores, facilitam muito na hora de checar resultados e comportamentos.

A comunidade em volta desta ferramenta está em constante crescimento e atividade. Portanto, caso você queira contribuir com o projeto, vá agora mesmo para o repositório no GitHub e colabore.

E quando queremos fugir da regra? Aposto que chegará um momento em que a estrutura de diretórios padrão, necessária para a execução dos seus testes em Django, não te satisfará mais. O que fazer neste caso? Simples, recorra ao Nose!

O Nose estende os recursos da unittest e facilita a escrita e carregamento dos testes em projetos Python. De uma forma mais detalhada, ele percorre o seu projeto (ou uma determinada região de seu escolha) executando subclasses da unittest.TestCase ou funções que contenham “test”. Por exemplo:

# test_subclasse.pyimport unittest class SubclasseTest(unittest.TestCase): def test_um_eh_verdadeiro(self): self.assertTrue(1) # test_funcao.pydef test_zero_eh_falso(): assert 0 == False

Ao executar o comando nosetests o nose se encarregará de procurar e carregar os testes:

$ nosetests..----------------------------------------------------------------------Ran 2 tests in 0.005s OK

É claro que existe uma “mágica” aí. Na verdade o nose pesquisará por arquivos Python com “test” em seu nome, por funções com “test” em seu enunciado, e por classes com métodos “test” em sua declaração. Ele age mesmo como um “runner“, tendo a capacidade de lidar com testes escritos com unittest ou não.

Essa é só a ponta do iceberg. É possível construir plugins para o nose, permitindo melhorar ainda mais o seu ambiente de testes (como por exemplo, permitir que o nose funcione em subprocess separados).

Caçando testes em seu projeto (Django)

Para facilitar ainda mais a escrita de testes em Django existem plugins como o django-nose, que permite que você substitua o Test Runner padrão da framework por um específico que utiliza o nose, unindo assim a facilidade e “add-ons” do nose com o ambiente de testes do Django.

E se você estava se perguntando sobre BDD em Django, eu apresento a Lettuce!

Esta ferramenta, baseada na Cucumber, permite com que você escreva estórias utilizando linguagem ubíqua, mais próxima da área de negócios do que da área técnica, e automatize a validação delas.

O mais bacana é que ela já vem preparada para o Django, permitindo que a gente execute os testes de comportamento de forma fácil e rápida:

Feature: Rocking with lettuce and django  Scenario: Simple Hello World Given I access the url "/" Then I see the header "Hello World"  Scenario: Hello + capitalized name Given I access the url "/some-name" Then I see the header "Hello Some Name"Estória escrita, vamos escrever o script Python que validará se está tudo de acordo:

from lettuce import *from lxml import htmlfrom django.test.client import Client @before.alldef set_browser(): world.browser = Client() @step(r'I access the url "(.*)"')def access_url(step, url): response = world.browser.get(url) world.dom = html.fromstring(response.content) @step(r'I see the header "(.*)"')def see_header(step, text): header = world.dom.cssselect('h1')[0] assert header.text == text

Basta executá-lo da seguinte maneira:

Confira mais informações sobre como utilizar o lettuce com Django.

O Fudge é um módulo Python que auxilia na construção de objetos “dublês” (mocks e stubs), que permitem escrever testes sem necessariamente possuir um serviço ativo ou um objeto construído.

Um caso comum: Você está construindo uma API que autentica via OAuth ao Twitter e está utilizando testes para guiar o seu desenvolvimento. Não é interessante que nossos testes sejam dependentes da disponibilidade do serviço do Twitter, portanto, escrevemos um “objeto mentiroso”, que simulará este serviço, aceitando uma entrada e gerando um saída:

import fudge@fudge.patch('oauthtwitter.OAuthApi')def test(FakeOAuthApi): (FakeOAuthApi.expects_call() .with_args('', '', '', '') .returns_fake() .expects('UpdateStatus').with_arg_count(1)) post_msg_to_twitter("hey there fellow testing freaks!")

Pronto! Sabendo que valores serão passados, e quais os resultados, podemos simular o comportamento daquele serviço. Prático, não?

Estas são as ferramentas que eu costumo utilizar em meus projetos Python/Django. É claro que existem outras, na verdade existem várias. Tenha em mente que a ferramenta é apenas um meio de garantir, através de testes, que você está guiando a sua aplicação para o lugar certo. Os testes automatizados no final servem para garantir que ela ainda segue este caminho, que contribuições realizadas tardiamente não “quebraram” o comportamento que você escreveu no início do desenvolvimento.

Tenho a intenção de escrever um post mais prático sobre testes e Django. Fiquem no aguardo ;)

E você? Tem alguma ferramenta para recomendar? Utilize os comentários abaixo para compartilhá-la.

Até a próxima…

Fonte: Klaus Laube

Thursday, August 11, 2011
no image

Ferramentas de testes em Django – Parte 1

Dando continuidade à série de posts sobre Django, vou indicar algumas ferramentas de testes para que você também possa deixar com que os testes guiem o desenvolvimento de suas aplicações.

Afinal, testar é preciso ;)

Sem dúvida nenhuma! Mas não espere que o framework adeque-se a você, você precisa ter a iniciativa de tentar compreender as melhores maneiras para escrever testes em Django.

Por exemplo, se você tem por hábito isolar os modelos para testá-los de forma unitária, pode passar por certa dor de cabeça com o Python/Django. Não que seja impossível, mas o comportamento default do framework é criar uma base de dados “fake” para você não precisar ter este trabalho.

Enfim, talvez a forma de utilizar estas ferramentas caiba em um outro post, o objetivo deste é apenas apresentá-las.

A unittest é uma biblioteca padrão do Python que ajuda (e muito) a escrever testes automatizados com a linguagem.

Os testes são escritos através de classes, onde utilizamos os esquemas de assertions para garantir o comportamento do código testado (nenhuma novidade até aqui). Para quem utiliza testes unitários no Java não vai sentir grandes mudanças na abordagem, já que a unittest é inspirada na JUnit (sendo muitas vezes até chamada de PyUnit):

import unittestfrom myapp.models import Animal class AnimalTestCase(unittest.TestCase): def setUp(self): self.lion = Animal.objects.create(name="lion", sound="roar") self.cat = Animal.objects.create(name="cat", sound="meow")  def testSpeaking(self): self.assertEquals(self.lion.speak(), 'The lion says "roar"') self.assertEquals(self.cat.speak(), 'The cat says "meow"')

O test runner padrão do Django irá procurar por subclasses de unittest.TestCase nos arquivos models.py e tests.py. A suíte de testes tenta facilitar ao máximo a sua vida… execute a seguinte instrução e confira se a sua aplicação está ok ou não:

Peraí que não acabou! Apresentando a TestCase

Testar aplicações Web com a unittest pode ser dureza. Pensando nisso o Django disponibiliza a TestCase, que estende a unittest adicionando funcionalidades como carregamento de fixtures, roteamento de urls e um client para fazer requisições Web e testar as suas views (o TestClient, detalhado mais abaixo).

Admito que escrever documentação de software não é o meu forte… mas com doctests pode-se documentar métodos ao mesmo tempo em que escreve-se testes!

A doctest é uma biblioteca padrão do Python que procura e interpreta docstrings na aplicação. A sintaxe nesses trechos de docstrings é diferenciada, simulando um interpretador interativo do Python:

# models.py from django.db import models class Animal(models.Model): """ An animal that knows how to make noise  # Create some animals >>> lion = Animal.objects.create(name="lion", sound="roar") >>> cat = Animal.objects.create(name="cat", sound="meow")  # Make 'em speak >>> lion.speak() 'The lion says "roar"' >>> cat.speak() 'The cat says "meow"' """ name = models.CharField(max_length=20) sound = models.CharField(max_length=20)  def speak(self): return 'The %s says "%s"' % (self.name, self.sound)

Assim como com a unittest, o test runner padrão do Django procurará por ocorrências de docstests em models.py e tests.py.

E como fazer para testar requisições Web? Por exemplo, você não quer testar a sua view de forma isolada, quer testar desde a parte de roteamento ao comportamento com o banco de dados, como se você se estivesse realmente visitando a página. Neste caso entra a test client.

Toda a classe TestCase possui uma instância da Django Test Client. Então escrever testes com requisições à sua aplicação fica muito simples utilizando classes:

from django.test import TestCase class SimpleTest(TestCase): def test_details(self): response = self.client.get('/customer/details/') self.assertEqual(response.status_code, 200)  def test_index(self): response = self.client.get('/customer/index/') self.assertEqual(response.status_code, 200)

É perfeitamente possível utilizar a test client em doctests também:

""">>> from django.test.client import Client>>> c = Client()>>> response = c.post('/login/', {'username': 'john',... 'password': 'smith'})>>> response.status_code200"""

Particularmente, tive a oportunidade de implementar testes unitários já no início do meu aprendizado em Django. Deixar os testes te guiarem é uma prática excelente!

Tudo parte do bom senso, óbvio. Nenhum processo ou ferramenta deveria substituir o “feeling” do profissional… também não é muito sadio ser extremamente “by the book“. Mas se puder utilizar testes para guiar o seu desenvolvimento, use-os!

Na segunda parte deste post pretendo apresentar algumas ferramentas que irão turbinar ainda mais o seu desenvolvimento orientado a testes.

Até lá!

Fonte: Klaus Laube

Tuesday, June 7, 2011
no image

Como versionar projetos Django com o Mercurial – Parte 1

Olá pessoas!

Se você está começando em Django, e nunca utilizou uma ferramenta de controle de versão (as vezes por trauma do SVN ou por simples desinteresse) esta será uma grande oportunidade para você conhecer o Mercurial, e saber a forma que venho utilizando para versionar meus projetos Django.

Sem dúvida o Git é a ferramenta do momento em se tratando de controle de versões, e vem sendo muito utilizada por rubistas e pythonistas (eu incluso nessa última galera).

Por que não falar de Git aqui? Simples! Você vai ouvir falar sobre Git em todo o lugar. O Google vai te trazer toneladas de informações sobre Git. Você vai “ouvir” o pessoal falando que Git é melhor do que qualquer outra ferramenta. Você vai até enjoar de tanto ouvir falar sobre Git.

O Mercurial foi o primeiro DVCS que utilizei (de verdade). Na minha opinião, ele é mais simples que o Git, é feito em Python, e me atende no desenvolvimento dos meus projetos pessoais.

Concordo com o pessoal que diz que o Git é bom, e concordo com o pessoal que fala que o Mercurial é bom. É perfeitamente possível utilizar estas duas ferramentas, não precisamos ser radicais e iniciar um flame em cima deste assunto. A opção é melhor que não ter opção…

Agora uma coisa eu não posso deixar de concordar: O GitHub é (na minha opinião) melhor que o Bitbucket.

Ambos são repositórios de código na nuvem, o primeiro usando Git e o segundo usando Mercurial. O detalhe é que o Git tem algumas funções mais apuradas que o Bitbucket, principalmente as funcionalidades que tornam a ferramenta muito mais “social”.

Embora o Bitbucket recentemente tenha sido adquirido pela Atlassian e tenha recebido uma forte injencão de melhorias… o GitHub ainda é, para mim, a melhor forma de compartilhar código que existe no momento.

Venho utilizando o Bitbucket pela opção de poder manter repositórios de código “fechados”. Coisa que com o “rival” só é possível através de uma conta paga.

Mais uma vez… é perfeitamente possível viver utilizando as duas ferramentas.

Na próxima parte deste post vamos abordar o básico do Mercurial, e também pretendo mostrar como organizo os meus projetos Django “versionando-os” com o Mercurial e Bitbucket.

Até a próxima…

Fonte: Blog Klaus Laube