Ghazaleh Kharadpoor
Ghazaleh Kharadpoor

Reputation: 146

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?

Upvotes: 2

Views: 1336

Answers (2)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477685

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.

Upvotes: 2

nigel222
nigel222

Reputation: 8222

Django provides a way to do this, although you do need to specify the name of the app in which the moodel is defined (because it's possible to have two models with the same name in different apps).

apps.get_model(app_label, model_name, require_ready=True)¶

Returns the Model with the given app_label and model_name. As a shortcut, this method also accepts a single argument in the form app_label.model_name. model_name is case-insensitive.

Upvotes: 1

Related Questions