Inversão de controle em Django

74 views
Skip to first unread message

Vinicius Mendes

unread,
Jan 22, 2010, 3:48:18 PM1/22/10
to django...@googlegroups.com
Trabalho com Django para desenvolvimento de sites, e acaba que muita coisa é parecida de um site pro outro. Comecei a fazer algumas apps para prover as funcionalidades básicas de um site (notícias, enquetes, galeria de fotos, vídeos, etc) e comecei a ver que mudam apenas pequenos detalhes de um site para o outro.

Eu quero fazer algo que eu adicione no meu site como INSTALLED_APP, depois coloque a url para essa app, e crie os templates. Se precisar de alguma customização específica do projeto, colocaria isso em uma app extra.

Na minha especialização eu vi algo sobre o Spring do Java e a tal inversão de controle ou injeção de dependências. Achei bem interessante e talvez a solução do meu problema, já que eu posso sobrescrever alguma classe da minha app que já esta pronta e injetar novamente nela. Vi algumas coisas no Google sobre como implementar tal funcionalidade no python, mas todas as soluções são muito mais imitações do que existe para java e não são lá muito pythonicas.

Eu quero valorizar ao máximo a plugabilidade tanto defendida pelo Django, portanto, não gostaria de ter que alterar minhas classes. Gostei da idéia de injetar especializações dela.

Alguém saberia dizer se existe algo em python que me possibilite isso, ou teve alguma experiência nessa área?

Atenciosamente,
Vinícius Mendes
Solucione Sistemas

Luciano Ramalho

unread,
Jan 22, 2010, 4:00:01 PM1/22/10
to django...@googlegroups.com
Vinicius, talvez você se interesse em ler sobre a arquitetura de
componentes do Zope (ZCA). Embora a ZCA tenha nascido no Zope, ela é
implementada em bibliotecas que podem ser usadas sem o restante do
Zope, e tenho até um amigo que já usou ela num projeto em Django.

Uma boa introdução sobre o tema é esse texto:

http://regebro.wordpress.com/2007/11/16/a-python-component-architecture/

Fiz uma tradução deste texto e coloquei no Wiki da nossa comunidade:

http://www.python.org.br/wiki/ArquiteturaDeComponentes

[ ]s
Luciano


2010/1/22 Vinicius Mendes <vbme...@gmail.com>:

> --
> Django Brasil em Google Groups
> <http://groups.google.com.br/group/django-brasil>
> Associe-se à Python Brasil e suporte nossa comunidade!
> <http://associacao.python.org.br/>

--
"""
Many were increasingly of the opinion that they'd all made a big
mistake in coming down from the trees in the first place. And some
said that even the trees had been a bad move, and that no one should
ever have left the oceans. (DA/HHGTTG)
"""

Igor Sobreira

unread,
Jan 22, 2010, 4:36:56 PM1/22/10
to django...@googlegroups.com
Vinicius, já deu uma olhada no Pinax? Eles tão sempre buscando maneiras de deixar as apps o mais plugáveis possíveis. 

Ainda não conheço esse conceito que você citou de injeção de dependências, mas já vi implementações interessantes de "injetar" funcionalidades em apps externas. Um exemplo é como o django-diario usa ou não a app django-tagging [1]. Acho uma maneira interessante se injetar mais fields ao model em "tempo de syncdb". E existem vários outros hooks que o pessoal tem usado pra facilitar a customização (sinais, passagem de funções por parâmetros pra fazer algum processamento dentro de uma view, etc)

Se tiver algum exemplo específico seria interessante pra discutir também...

[]s

2010/1/22 Vinicius Mendes <vbme...@gmail.com>
--
Django Brasil em Google Groups <http://groups.google.com.br/group/django-brasil>
Associe-se à Python Brasil e suporte nossa comunidade! <http://associacao.python.org.br/>



--
Igor Sobreira
www.igorsobreira.com

marcos thomaz

unread,
Jan 22, 2010, 5:11:51 PM1/22/10
to django...@googlegroups.com
Vinicius, posso estar falando besteira, mas tipo, se você já tem essa classe, e usa com frequencia, o que poderia fazer é adiciona-la de forma "permanente" no path, e quando precisasse usá-la, se não precisasse de customização, bastaria adicioná-la nas INSTALLED_APPS, e se precisasse, bastaria extender essa classe, fazendo os ajustes necessários. Isso já não resolveria?

[]'s

Marcos Thomaz


De: Vinicius Mendes <vbme...@gmail.com>
Para: django...@googlegroups.com
Enviadas: Sexta-feira, 22 de Janeiro de 2010 18:48:18
Assunto: Inversão de controle em Django
--
Django Brasil em Google Groups <http://groups.google.com.br/group/django-brasil>
Associe-se à Python Brasil e suporte nossa comunidade! <http://associacao.python.org.br/>


Veja quais são os assuntos do momento no Yahoo! + Buscados: Top 10 - Celebridades - Música - Esportes

Herberth Amaral

unread,
Jan 23, 2010, 8:15:23 AM1/23/10
to django...@googlegroups.com
Fazer um container DI pra Python não é difícil. Eu trabalhei com DI em .NET (usando C#) e garanto que, por Python ser uma linguagem dinâmica, não deva ser difícil de fazer.

Aqui tem um exemplo básico: http://code.activestate.com/recipes/413268/

Pergunta: Monkey patch não ajudaria? Acho que dependendo do caso, poderia ser uma solução mais simples.


2010/1/22 marcos thomaz <marcos...@yahoo.com.br>

Luciano Ramalho

unread,
Jan 23, 2010, 3:47:19 PM1/23/10
to django...@googlegroups.com
2010/1/23 Herberth Amaral <herbert...@gmail.com>:

> Fazer um container DI pra Python não é difícil. Eu trabalhei com DI em .NET
> (usando C#) e garanto que, por Python ser uma linguagem dinâmica, não deva
> ser difícil de fazer.
> Aqui tem um exemplo básico: http://code.activestate.com/recipes/413268/
> Pergunta: Monkey patch não ajudaria? Acho que dependendo do caso, poderia
> ser uma solução mais simples.

Quem tiver interesse neste assunto e usa Python realmente deve ler o
texto do Lennart Regebro que eu citei. Vou reproduzir apenas os dois
primeiros parágrafos, para vocês avaliarem se é relevante ou não:

"""
Ao construir grandes frameworks você muitas vezes deseja que tudo seja
facilmente plugável e extensível. Os objetos precisam ser capazes de
interagir uns com os outros mesmo quando esta interação não está
prevista inicialmente. Criar este tipo de flexibilidade não é muito
difícil, especialmente em uma linguagem dinâmica como Python, mas se
você tem que criar um framework para plug-ins toda vez que precisa de
um, você acaba não fazendo isso a menos que seja realmente muito
necessário.

Assim, é bom ter uma forma padrão para a interação entre objetos e
para que eles possam se inspecionar, e uma forma que você possa usar
toda vez que precisar. Resumindo, você precisa de uma arquitetura de
componentes. Felizmente, já existe uma para Python, que foi bem
implementada, bem testada e vem sendo usada há anos. Seu nome é Zope
Component Architecture.
"""

O resto está aqui:

http://www.python.org.br/wiki/ArquiteturaDeComponentes

[ ]s
Luciano

Marcos Sousa

unread,
Jan 24, 2010, 5:15:02 PM1/24/10
to django...@googlegroups.com
Vinicius Mendes,

Há uma solução desenvolvida por brasileiros chamada Pyoc (http://github.com/heynemann/pyoc/). Vale a pena dar uma olhada.

Abraços,

2010/1/23 Luciano Ramalho <ram...@gmail.com>
--
Django Brasil em Google Groups <http://groups.google.com.br/group/django-brasil>
Associe-se à Python Brasil e suporte nossa comunidade! <http://associacao.python.org.br/>



--
Marcos Sousa
www.marcossousa.com

Vinicius Mendes

unread,
Jan 25, 2010, 9:36:54 AM1/25/10
to django...@googlegroups.com
Pessoal,

Desculpa pela demora em responder aqui, mas é que sexta feira eu viajei e fiquei sem acesso à internet. Obrigado a todos que responderam.

Luciano, obrigado pelo link, eu li o artigo, achei interessante, mas ainda me pareceu muito imitação do java, e implementado de uma forma que não me parece python nem java. Esse negocio de a interface ser um atributo da classe, e você ter que fazer casts, isso não é a cara do python e seu duck typing.

Igor, o que eu quero é mais ou menos isso: injetar atributos em models antes do syncdb. Por exemplo, eu tenho uma notícia e aí em um site a notícia tem foto e em outro ela não tem foto. Então eu queria fazer uma aplicação genérica que ela possibilitasse que eu inserisse o campo de foto na notícia. Eu consigo fazer isso hoje utilizando generic relations, mas acho que deixa a aplicação mais lenta. Pelo que vi do seu exemplo do django-diario integrando com o django-tagging, me pareceu muito trabalhosa a solução. Em vários lugares do código exitem ifs para decidir se vai incluir um trecho de código ou não. Eu fiz, também com generic relations, uma app que transforma integra qualquer model com o django-tagging, mas cai no mesmo problema: generic relation é mais lento. Se eu pudesse em tempo de execução alterar o model da app seria bem mais interessante. Extender o model atual e colocar o que eu criei no lugar dele, já que o django não foi pensado pra ser utilizado com injeção de dependências, isso se torna complicado.

Marcos, quanto ao que você falou, o problema não é tê-las no python path, o problema é conseguir alterá-las em tempo de execução.

Herbert, quanto o código que você citou, eu tinha visto exatamente ele no google, tô dando uma olhada mais a fundo nele, mas acredito que não vá funcionar para models.

Marcos, não consegui compreender o projeto que você referenciou, faltou-me documentação. Vou dar uma lida no código pra ver se entendo.

Obrigado a todos mais uma vez.


2010/1/24 Marcos Sousa <marcoscai...@gmail.com>

Klaus Laube

unread,
Jan 25, 2010, 9:49:22 AM1/25/10
to django...@googlegroups.com
Se você construir um modelo (ex.: Noticia), deixá-lo de forma abstrata e através de um outro modelo (ex.: NoticiaCliente1) que herda as características de "Noticia" criar as customizações (como campo imagem)... não resolveria?

2010/1/25 Vinicius Mendes <vbme...@gmail.com>

Vinicius Mendes

unread,
Jan 25, 2010, 10:18:25 AM1/25/10
to django...@googlegroups.com
Klaus,

Eu tenho views, tenho forms, tenho admin, tenho classes que se relacionam com notícias, etc. Se eu criar da forma que você falou, Todos esses componentes que eu falei irão referenciar a classe abstrata (Noticia), e não a especialização (NoticiaCliente1). Estou citando o problema dos models, mas gostaria de poder aplicar a qualquer classe. Deixar o mais plugável possível.

2010/1/25 Klaus Laube <kpl...@gmail.com>

marcos thomaz

unread,
Jan 25, 2010, 10:21:09 AM1/25/10
to django...@googlegroups.com
Vinícius, tipo, alterar características de modelos, eu ainda não consegui fazer em tempo de execução (tipo adicionar um campo, por exemplo), mas tipo, alterar visibilidade de um campo, alterar, adicionar ou remover campos (atributos) de um form, e coisas do tipo, isso já consegui fazer sem muito esforço. Não sei se ficou da forma mais correta e tal, mas funciona.

Por exemplo, tenho um modelo assim:

class Inscricao(models.Model):
concurso = models.ForeignKey(Concurso)
pessoa = models.ForeignKey(Pessoa)
curso = models.ForeignKey(CursoConcurso)
cidade_prova = models.ForeignKey(CidadeProva)
sala = models.ForeignKey(Sala, null=True, blank=True)
num_inscricao = models.IntegerField('Número de Inscrição')
treineiro = models.CharField(max_length=1,default='N',choices=choices.CHOICE_SIMNAO,null=True,blank=True)
...
pontuacaofinal = models.IntegerField('Total de Pontos - Final',editable=False, null=True, blank=True)
classificacaofinal = models.IntegerField('Classificação Final',editable=False, null=True, blank=True)


E o admin desse model:

class InscricaoAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs): 
if request.user.is_superuser:
Inscricao._meta.get_field('pontuacaofinal').editable = True
Inscricao._meta.get_field('classificacaofinal').editable = True
else:
Inscricao._meta.get_field('pontuacaofinal').editable = False
Inscricao._meta.get_field('classificacaofinal').editable = False
form = super(Inscricao.Admin, self).get_form(request, obj, **kwargs)
return form

Note que, quando coloco como editable = True/False deixo esse campo visível/invisível para edição e visualização. Dessa forma consigo, dependendo do nível do usuário ocultar campos e tal. Outra característica que tenho é que, nessa mesma aplicação, dependendo do concurso, tenho que ter uma forma diferente de alocação. Pensando dessa forma, usei a idéia dos backend's do django para fazer o módulo, ou seja, o módulo é carregado em tempo de execução, para só então realizar a operação.Verifico antes de tudo se existe um módulo com o nome do concurso (verifico se a pasta existe), se existir carrego desta pasta, senão, carrego da pasta padrão.  É assim que usei pra fazer o módulo de correção deste sistema (é um pequeno sistema de concursos).

Não sei se te ajuda, ou se é isso que você queria.

[]'s

Marcos Thomaz



Enviadas: Segunda-feira, 25 de Janeiro de 2010 11:36:54
Assunto: Re: Inversão de controle em Django

Klaus Laube

unread,
Jan 25, 2010, 10:48:00 AM1/25/10
to django...@googlegroups.com
Bom... em relação aos forms, lembro que já utilizei algo parecido com o que você precisa.

Através do pattern Observer. Tinha um core que coletava "partes" de forms em diferentes apps e criava uma instância unica... 

Talvez possa ajudar?!

2010/1/25 marcos thomaz <marcos...@yahoo.com.br>

Luciano Ramalho

unread,
Jan 25, 2010, 12:38:36 PM1/25/10
to django...@googlegroups.com
2010/1/25 Klaus Laube <kpl...@gmail.com>:

> Bom... em relação aos forms, lembro que já utilizei algo parecido com o que
> você precisa.
> Através do pattern Observer. Tinha um core que coletava "partes" de forms em
> diferentes apps e criava uma instância unica...
> Talvez possa ajudar?!

Klaus, isso é interessante e pode ser útil no projeto que estou programando.

Você pode dar uma referência mais precisa ou um link?

Valeu!

[ ]s
Luciano

Igor Sobreira

unread,
Jan 25, 2010, 12:40:07 PM1/25/10
to django...@googlegroups.com


2010/1/25 Vinicius Mendes <vbme...@gmail.com>

Pessoal,

Desculpa pela demora em responder aqui, mas é que sexta feira eu viajei e fiquei sem acesso à internet. Obrigado a todos que responderam.

Luciano, obrigado pelo link, eu li o artigo, achei interessante, mas ainda me pareceu muito imitação do java, e implementado de uma forma que não me parece python nem java. Esse negocio de a interface ser um atributo da classe, e você ter que fazer casts, isso não é a cara do python e seu duck typing.

Igor, o que eu quero é mais ou menos isso: injetar atributos em models antes do syncdb. Por exemplo, eu tenho uma notícia e aí em um site a notícia tem foto e em outro ela não tem foto. Então eu queria fazer uma aplicação genérica que ela possibilitasse que eu inserisse o campo de foto na notícia. Eu consigo fazer isso hoje utilizando generic relations, mas acho que deixa a aplicação mais lenta. Pelo que vi do seu exemplo do django-diario integrando com o django-tagging, me pareceu muito trabalhosa a solução. Em vários lugares do código exitem ifs para decidir se vai incluir um trecho de código ou não. Eu fiz, também com generic relations, uma app que transforma integra qualquer model com o django-tagging, mas cai no mesmo problema: generic relation é mais lento. Se eu pudesse em tempo de execução alterar o model da app seria bem mais interessante. Extender o model atual e colocar o que eu criei no lugar dele, já que o django não foi pensado pra ser utilizado com injeção de dependências, isso se torna complicado.


Vinicius, realmente sair colocando IFs não é muito bom, eu que eu tinha pensado era evoluir essa abordagem do diário pra chamar uma função que retorna fields, algo assim... mas no corpo do model não daria certo.

Dando uma olhada na metaclasse django.db.models.base.ModelBase vi que antes de finalizar a criação do model ele chama um método "privado" _prepare(), que adiciona alguns métodos utilitários no model. Enfim, eu fiz um rascunho de uma idéia:


uma metaclasse customizada que tem um hook na criação do model que procura em algum lugar fields extras a serem adicionados...
o problema é, se a gente quer adicionar fields sem mecher no fonte do model, como adicionar o atributo __metaclass__?
Bem, foi só uma idéia que tive agora, testei, vi o SQL pelo manage.py sqlall, rodei o syncdb, registrei o model no admin, inseri um objeto pelo admin.

O que vocês acham? Eu coloquei a função get_extra_fields() hard-coded, mas poderia ter uma API parecida com o registro de models no admin, você registra seu model como dinâmico, com uma configuração pra ele...

--
Igor Sobreira
www.igorsobreira.com

Vinicius Mendes

unread,
Jan 25, 2010, 1:18:29 PM1/25/10
to django...@googlegroups.com
Igor,

Eu andei conversando com o Marinho Brandão sobre esse assunto e ele me apresentou essa solução. Talvez ela seja realmente boa pra adicionar campos aos modelos. Eu queria algo mais abrangente, que pudesse utilizar em várias classes do projeto, mas pelo que eu tô vendo, não vai ser tão simples assim.

Assisti a palestra do Marinho na PythoBrasil[5] e gostei da dica que ele deu de criar um ProjectModel do qual todos os seus models herdariam, onde você colocaria coisas específicas do seu projeto e pensei que ele seria um bom lugar para fazer essa alteração. Poderíamos criar essa metaclasse lá e criar um signal que poderia ser capturado por alguma função que adicionasse esses campos ou alguma outra solução.

2010/1/25 Igor Sobreira <ig...@igorsobreira.com>

Klaus Laube

unread,
Jan 25, 2010, 1:51:30 PM1/25/10
to django...@googlegroups.com
Luciano,

Eu não tenho acesso ao fontes (agora)... mas lembro que me baseei nos links abaixo: 



2010/1/25 Vinicius Mendes <vbme...@gmail.com>
Reply all
Reply to author
Forward
0 new messages