Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 838
user3541631 Avatar asked Dec 20 '17 13:12

user3541631


2 Answers

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})
like image 193
user2390182 Avatar answered Oct 30 '22 23:10

user2390182


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
like image 29
Hai Vu Avatar answered Oct 30 '22 23:10

Hai Vu