2010-11-10 4 views
4

J'ai besoin d'une déclaration de classe d'exécution de classe à partir de la base de données.Changeur de classe Python

Certains champs ont besoin d'un champ de remplacement et d'une redéclaration.

models.py

 
class Staff(object): 
    name = StringField(verbose_name = "Full name") 
    age = IntegerField(verbose_name = "Age") 

utils.py

 
def class_changer(class_path, field_key, new_Field): 
    pass 
    ?????? 
>>> class_changer("models.Staff", "gender", BooleanField()) # Add new field to Staff 
>>> class_changer("models.Country", "name", StringField()) # Add new class with name field 
>>> class_changer("models.Staff", "country", ForeignKey("Country")) # Add new field to Staff 

résultat est

 
class Staff(object): 
    name = StringField(verbose_name = "Full name") 
    age = IntegerField(verbose_name = "Age") 
    gender = BooleanField() 
    country = ForeignKey("Country") 

class Country(object): 
    name = StringField() 

Comment mettre en œuvre class_changer?

+0

combinaison de 'setattr' &' eval' peut vous aider - pas robuste mais facile à mettre en œuvre – shahjapan

+0

J'ai trouvé trop de méthode. http://en.wikipedia.org/wiki/Aspect-oriented_programming eval, setattr, decorator .... Mais je ne suis pas sûr de savoir comment la méthode sorcière mieux ???. je n'ai pas beaucoup d'expérience. – Ankhaa

+1

Il est clair que vous faites cela avec django alors vous devriez être conscient que penser à faire ça me fait mal à cause de toutes les métaclasses qu'ils utilisent: tout est connecté à tout le reste. Normalement, je suis un programmeur chanceux, mais je vais juste m'éloigner de celui-ci. Je vous recommande de faire aussi bien et de penser à une meilleure architecture. Qu'est-ce que vous essayez d'accomplir réellement? – aaronasterling

Répondre

4

vous besoin d'une meilleure architecture pour cela, mais comme une solution de départ, vous pouvez essayer cela,

In [12]: class a1(object): 
    ...:  pass 

In [13]: def class_changer(cls_path, attr, val): 
    ....:  try: 
    ....:   obj = eval(cls_path) 
    ....:   setattr(obj, attr, val) 
    ....:  except: 
    ....:   raise 
    ....:  
In [14]: def getGender(self): 
    ...:  return True 


In [15]: class_changer('a1','getGender', getGender) 

In [16]: a1().getGender() 
Out[16]: True 
+0

Lire [cette question] (http://stackoverflow.com/questions/1832940/is-using-eval-in-python-a-bad-practice), en particulier la réponse acceptée et la discussion autour d'elle, pour comprendre certains des risques et mises en garde de 'eval'. Cela ne veut pas dire que la solution est mauvaise, mais vous devriez savoir dans quoi vous vous engagez. –

+0

ouais eval est nuisible c'est vérité tout devrait savoir, mais exactement quand l'entrée des utilisateurs va évaluer, si le programmeur écrit eval pour son propre but - alors indépendamment de la déclaration, il ne devrait pas être considéré comme un risque - il devrait être considéré comme flexibilité ou programmeur choix ou fonctionnalité quel que soit .... – shahjapan

1

Tout d'abord l'ajout de nouveaux attributs à une classe:

>>> class_changer("models.Staff", "gender", BooleanField()) # Add new field to Staff 
>>> class_changer("models.Staff", "country", ForeignKey("Country")) # Add new field to Staff 

Pour ces deux, allez-y et définir Staff directement:

models.Staff.gender = BooleanField() 
models.Staff.country = ForeignKey("Country") 

Ou pour le rendre générique:

def add_to_class(cls, name, attr): 
    setattr(cls, name, attr) 

add_to_class(models.Staff, "gender", BooleanField()) 
add_to_class(models.Staff, "country", ForeignKey("Country")) 

En second lieu, la création d'une nouvelle classe:

>>> class_changer("models.Country", "name", StringField()) # Add new class with name field 

Vous pouvez créer une classe dans une fonction et puis l'affecter à un module:

def new_class(mod, name): 
    class New(object): pass 
    setattr(mod, name, New) 

new_class(test, "Country") 
add_to_class(test, "Country", StringField()) 

Je ne suis pas sûr que vous Je veux combiner new_class et add_to_class, mais je suppose que vous pourriez faire:

def create_if_needed_and_add_to_class(mod, clsname, attrname, value): 
    if clsname not in dir(mod): 
     new_class(mod, clsname) 
    add_to_class(mod, attrname, value) 

puis enfin pour votre class_changer:

def class_changer(mod_clsname_string, attrname, value): 
    modname, clsname = '.'.split(mod_clsname_string) 
    create_if_needed_and_add_to_class(globals()[modname], clsname, attrname, value) 

Edit: fixe class_changer utiliser locals() pour le nom du module recherche, car il est une chaîne et non un module.

Editer: Oups, il devrait être globals().

+0

C'est génial. Très utile pour moi et Comprendre les fonctionnalités spéciales de python. – Ankhaa