2012-11-27 6 views
5

sto usando django-tastypie e ho bisogno di creare classi di questo tipo dai miei modelli Django:pitone creare dinamicamente classe con classe interna

class MyModelResource(ModelResource): 
    class Meta: 
     queryset = MyModel.objects.all() 
     allowed_methods = ['get'] 

Dato che ho un sacco di modelli nel mio Django app che don Voglio ripetere me stesso e utilizzare la funzione type() per creare tutte le classi di risorse. Il problema è che non so come affrontare questa classe interna "Meta".

Puoi darmi un esempio di come creare dinamicamente una classe con inner class usando type()?

risposta

7
class MyModel(object) : pass 
modelClass = MyModel() 

class ModelResource(object): 
    def mymethod(self): 
     print('got here') 

Meta = type('Meta', (object,), {'allowed_methods': ['get']}) 

def add_mymethod(cls): 
    def mymethod(self): 
     super(cls, self).mymethod() 
    cls.mymethod = mymethod 
    return cls 

name = modelClass.__class__.__name__ + "Resource" 
MyModelResource = add_mymethod(type(name, (ModelResource,), 
            {'Meta':Meta, })) 

print(MyModelResource.Meta) 
# <class '__main__.Meta'> 

m = MyModelResource() 
m.mymethod() 
# got here 

La classe interna, Meta, è solo un altro attributo per quanto concerne MyModelResource.


metodi sono anche solo attributi per quanto MyModelResource è interessato. In realtà, si definisce una funzionein MyModelResource.__dict__, e il meccanismo di ricerca attributo pitone provoca inst.mymethod per restituire un vincolato metodo.

Non c'è nessun problema riferendosi alla MyModelResource nel super chiamata

super(MyModelResource, self).mymethod() 

prima MyModelResource è definito, perché le ricerche del nome vengono eseguite in fase di esecuzione, non è al momento mymethod è definito.


si è assolutamente corretto che

super(self.__class_, self).mymethod() 

è sbagliato. Questo rovinerà tutto ciò che è buono su super. Se MyModelResource dovessero essere sottoclasse e un'istanza della sottoclasse chiamasse mymethod, Python cadrà in un ciclo infinito.

+0

Questa è la risposta corretta. Ora, cosa succede se devo definire il metodo che chiama super() dentro? Voglio evitare di scrivere super (self .__ class__, self) perché apparentemente non è una buona idea ... – mnowotka

+0

il problema è che non conosco il nome della classe nel momento del metodo di definizione. Nel mio caso la creazione della classe ha questo aspetto: type (modelClass .__ class __.__ name__ + "Resource", (ModelResource,), {"Meta" ... Quindi non posso fare riferimento ad esso nel nome del metodo. – mnowotka

+0

Ok, quindi 'mymethod' non può essere definito fino a quando non viene definito' MyModelResource'. In tal caso, utilizzare un decoratore di classe. Ho aggiunto il decoratore di classi, ad esempio 'add_mymethod'. – unutbu