user3541631
user3541631

Reputation: 4008

How do I pass a string as an argument name?

I have the following function:

def create_act(user, verb, fk_name=None, fk_value=None):
    fk = getattr(Action, fk_name)
    action = Action(user=user, verb=verb, fk=fk_value)
    action.save()

Action is a class. The class has multiple attributes, and I don't know at the beginning, which attribute will get a value.

I get the attribute name dynamic.

I want the kwarg fk, to be an actual attribute of the class action. FK can be account or company.

class Action(models.Model):

account = models.ForeignKey(Account, blank=True, null=True, related_name='activity', on_delete=models.CASCADE)
company = models.ForeignKey(Company, blank=True, null=True, related_name='activity', on_delete=models.CASCADE)

I found on the forums some answers but nothing relevant to me, or in python. I saw some suggestion on other sites to use eval, but eval is not safe.

Upvotes: 13

Views: 7582

Answers (2)

user2390182
user2390182

Reputation: 73498

Use dict unpacking with **. Note that -- if fk_name is the name of a ForeignKey -- fk will not be a string, but a ForwardManyToOneDescriptor. You'd probably still want to set the attribute named fk_name:

action = Action(user=user, verb=verb, **{fk_name: fk_value})

Upvotes: 21

Hai Vu
Hai Vu

Reputation: 40773

The idea is to dynamically pass to the class creation a pair of attribute name and value, to do that, create a dictionary using the name/value attribute and pass it along using dictionary unpacking:

def create_act(user, verb, name, value):
    attrs = {name: value}
    action = Action(user=user, verb=verb, **attrs)
    action.save()
    return action

Upvotes: 2

Related Questions