Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
143 views
in Technique[技术] by (71.8m points)

django - Is there a way to reference variable name as a string in that variable's declaration in Python?

For my Django application, I have a dictionary of field names (keys) mapped to help texts (values) (which I read in from a csv file). In models.py, I want to retrieve the appropriate help text for each field name.

If I have a sample dictionary like the following, with an entry for each field:

test_dict = {
    'host_name': 'The name of a host',
     ...
}

And my models.py looks like this:

class Host_main(models.Model):

    host_name = models.CharField(max_length=20, unique=True, help_text=test_dict['host_name'])
    
    def __str__(self):
        return self.host_name

Is there a way to call the variable name (host_name) dynamically in each help_text definition?

I do have the option to do something like the following:

from varname import nameof
host_name = models.CharField(max_length=20, unique=True, help_text=test_dict[nameof(host_name)])

But if possible, I'd like to reference the current variable name with something consistent to avoid typing out the field name a second time, like help_text=test_dict[nameof(**this**)] in pseudocode.

Thanks!

question from:https://stackoverflow.com/questions/66051086/is-there-a-way-to-reference-variable-name-as-a-string-in-that-variables-declara

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Let's simplify your question a little bit, and let's remove the django part first. Let's say you have a class with name A, then you can set an attribute on A with

class A: pass

A.foo = 'bar'

Alternatively, you can also do

setattr(A,'bar','baz')

You can verify that those are indeed equivalent by checking

print(A.foo) # bar
print(A.bar) # baz

So if you are defining a normal class, you can pretty much just loop through your dict and set things with setattr calls, in which case you have the control of the variable name.

And when we bring Django into the question, things are a bit more complicated...There are some very strange and magical things happening when you initialize a Model class. Basically it does a lookup on things already defined, and transforms all the defined fields through the pretty much public private _meta API. This means that adding class attributes outside of definition time won't work, and you might have to use a bit of a hack to construct a class directly through its metaclass (in case you are not familiar with Python's metaclasses, a class is basically an instance of its metaclass).

The basic syntax for dynamically constructing a class is through the type call with 3 arguments: type(name, bases, dict). In your example,

class Host_main(models.Model):

    host_name = models.CharField(max_length=20, unique=True, help_text=test_dict['host_name'])
    
    def __str__(self):
        return self.host_name

is the equivalent of

def Host_main_str(self): # the name here doesn't really matter unless you care about the __name__ attribute of the function, which you can overwrite.
    return self.host_name

Host_main = type('Host_main', (models.Model,), {
        '__str__': Host_main_str,
        'host_name': models.CharField(max_length=20, unique=True, help_text=test_dict['host_name'])
    })

It's actually how django constructs all their QuerySet classes (there were some more crazy things django did with dynamic class constructions if I remember correctly but I couldn't find a good example)

So, you can do things like


attr_dict = {'__str__':'Host_main_str'}
for name, help_text in test_dict.values():
    attr_dict[name] = models.CharField(max_length=20, unique=True, help_text=help_text)

Host_main = type('Host_main', (models.Model,), attr_dict)

if you really insist on loop through a dictionary.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...