Olivier Pons
Olivier Pons

Reputation: 15796

How to pass argument name as a parameter?

I have this code:

hobbies2 = form.cleaned_data.pop('hobbies2')
PersonneHobby.objects.filter(personne=obj).delete()
for pk_str in hobbies2:
    try:
        hobby = TagTraduit.objects.get(pk=int(pk_str))
        p = PersonneHobby.objects.create(personne=obj,
                                         hobby=hobby)
        p.save()
    except ValueError:
        break  # hack in the POST
    except LookupError:
        break  # hack in the POST

I will have the same code for 4 different fields, exemple with programme:

programmes2 = form.cleaned_data.pop('programmes2')
PersonneProgramme.objects.filter(personne=obj).delete()
for pk_str in programmes2:
    try:
        programme2 = TagTraduit.objects.get(pk=int(pk_str))
        p = PersonneProgramme.objects.create(personne=obj,
                                             programme=programme2)
        p.save()
    except ValueError:
        break  # hack = tout stopper
    except LookupError:
        break  # hack = tout stopper

Exactly the same code, only name of the field change. So I'd like to make a generic function and call it like this:

def update_field(post_field, class_field, **kwargs):
    try:
        values = form.cleaned_data.pop(post_field)
        class_field.objects.filter(personne=obj).delete()
        for pk_str in values:
            try:
                v = TagTraduit.objects.get(pk=int(pk_str))
                p = class_field.objects.create(**{'personne': obj,
                                                  field_name: v})
                p.save()
            except ValueError:
                break  # hack = tout stopper
            except LookupError:
                break  # hack = tout stopper
    except KeyError:
        pass
update_field('programmes2', PersonneProgramme, 'programme')
update_field('hobbies2', PersonneHobby, 'hobby')

My main problem is the last parameter, which is the name of the field to use when creating the record in the database.

How to do it?

Upvotes: 4

Views: 94

Answers (3)

MSeifert
MSeifert

Reputation: 152725

You could do it with an arbitary number of keyword-arguments (**) and insert calculated additional parameters inside the function:

def update_field(field, update_this, **kwargs):
     ...
     kwargs[update_this] = TagTraduit.objects.get(pk=int(pk_str))
     p = field.objects.create(**kwargs)
     ...

this allows you to call it like that:

update_field(PersonneHobby, 'hobby', personne=obj)
update_field(PersonneProgramme, 'programme', personne=obj)

Upvotes: 4

C Panda
C Panda

Reputation: 3415

I will go with what @MSeifert said. If you want whatever you have written to work, I mean with positional arguments alone.

def f(a,b,c):
    a.func(b=b, c=c)  # this is perfectly legal

But the better way to go about it is,

def f(a, **kwargs):
    a.func(**kwargs)  # kwargs is passed as a dict. **kwargs is
                      # unpacking it into key1=val1, key2=val2, ... 

Upvotes: 1

Selcuk
Selcuk

Reputation: 59315

You can do this:

def update_field(..., field_name):
   ...
   tag = TagTraduit.objects.get(pk=int(pk_str))
   p = PersonneProgramme.objects.create(**{'personne': obj, field_name: tag})

Upvotes: 3

Related Questions