Quem assina a lista django-brasil recebeu essa mensagem do Luciano Ramalho sobre metaprogramação. Achei muito interressante e demonstra perfeitamente o quão poderosa é a linguagem Python.
Estou reproduzindo o texto sem alterações:
Em geral não é tedioso programar com o Django, mas às vezes é, veja só quanta repetição:
# http://pastebin.com/f2fc7b238
class DescriptorInline(admin.TabularInline):
model = Descriptor
class RecruitmentCountryInline(admin.TabularInline):
model = RecruitmentCountry
class OutcomeInline(admin.StackedInline):
model = Outcome
class TrialInterventionCodeInline(admin.TabularInline):
model = TrialInterventionCode
class SecondaryNumberInline(admin.TabularInline):
model = TrialNumber
class TrialContactInline(admin.TabularInline):
model = TrialContact
class TrialInstitutionInline(admin.TabularInline):
model = TrialInstitution
class ClinicalTrialAdmin(admin.ModelAdmin):
inlines = [SecondaryNumberInline, RecruitmentCountryInline,
OutcomeInline, TrialContactInline, TrialInstitutionInline,
DescriptorInline, TrialInterventionCodeInline]
No código acima, cada nome de modelo aparece três vezes… (uma vez ao
declarar a classe XXXInline, no atributo model do inline, e mais uma
vez no atributo inlines).
Além disso, quase todas as declarações de inlines são idênticas… E o
princípio DRY, como fica?
Felizmente Django é Python. Então aquilo pode ser reescrito de uma
maneira mais legal assim:
# http://pastebin.com/f5af2bd28
tabular_inline_models = [Descriptor, RecruitmentCountry, TrialInterventionCode,
TrialNumber, TrialContact, TrialInstitution]
tabular_inlines = []
for model in tabular_inline_models:
cls_name = model.__name__+'Inline'
cls = type(cls_name, (admin.TabularInline,), {'model':model})
tabular_inlines.append(cls)
class OutcomeInline(admin.StackedInline):
model = Outcome
class ClinicalTrialAdmin(admin.ModelAdmin):
inlines = tabular_inlines + [OutcomeInline]
O truque aqui foi usar a função type(), que pode ser usada para criar
classes dinamicamente. Para isso a gente passa três argumentos para a
função type():
- uma string que será o __name__ da classe
- uma tupla de super-classes (importante: a vírgula dentro do
parêntesis indica que é uma tupla de um elemento)
- um dicionário com os atributos da classe (métodos e variáveis)
Não tente fazer isso em Java
.
[ ]s
Luciano