Search code examples
pythondjangodjango-modelseval

How to pass a class name with a string in Django models


I want to get all of objects that are related to an instance of models. Because my code is kinda generic, I pass the related table as an string and use eval() function to convert it to the related table class. But I got an error. Suppose that we have an instance of a table like self.casefile; this is a part of my code:

 def related_models_migration(self):
        opts = self.casefile._meta
        table_name = 'Files'
        for f in opts.many_to_many:
            name = ''.join(f.name.split('_'))
            table_name += name.capitalize()
            objects = self.casefile.eval(table_name).all()

and I got this error:

AttributeError                            Traceback (most recent call last)
<ipython-input-6-025484eeba97> in <module>
----> 1 obj.related_models_migration()

~/Documents/kangaroo/etl/data_migration.py in related_models_migration(self)
     28             name = ''.join(f.name.split('_'))
     29             table_name += name.capitalize()
---> 30             objects = self.casefile.eval(table_name).all()
     31 
     32             for d in dir(etl.models):

AttributeError: 'FilesCasefiles' object has no attribute 'eval'

How can I pass the class name?


Solution

  • You can not use eval(..) for that. What you probably want to use here is getattr(..):

    def related_models_migration(self):
        opts = self.casefile._meta
        table_name = 'Files'
        for f in opts.many_to_many:
            name = ''.join(f.name.split('_'))
            table_name += name.capitalize()
            objects = getattr(self.casefile, table_name).all()

    I am not sure you should use table_name += … here however, since it will each time add more content to the table_name. You likely want to use something like table_name = 'Files{}'.format(name.capitalize()).

    Note: normally related fields are not capitalized. One writes users or user_set, not Users.