Note that there are some explanatory texts on larger screens.

plurals
  1. PODynamically adding properties to a translatable Django model
    primarykey
    data
    text
    <p>So I want to add properties to a model resembling the attributes of another model, that holds translatable fields.</p> <p>My models:</p> <pre><code>class MyModel(models.Model): ... fields ... class MyModelTranslation(models.Model): ... the fields I want on MyModel ... name = models.CharField() city = models.CharField() language = models.CharField() mymodel = models.ForeignKey(MyModel) </code></pre> <p>So I wrote following <code>__init__</code></p> <pre><code>class MyModel(models.Model): ... def __init__(self, *args, **kwargs): super(Model, self).__init__(*args, **kwargs) # get_translation gets the object, that holds the translation fields for the # current active language trans = lambda c: c.get_translation() setattr(self.__class__, 'translation', property(trans)) fget = lambda c: getattr(trans(c), 'name') fset = lambda c, v: setattr(trans(c), 'name', v) setattr(self.__class__, 'name', property(fget, fset)) fget = lambda c: getattr(trans(c), 'city') fset = lambda c, v: setattr(trans(c), 'city', v) setattr(self.__class__, 'city', property(fget, fset)) </code></pre> <p>This works perfectly. When I then call <code>mymodel.name</code>, I get the <code>mymodeltranslation.name</code> for the active language. Setting this value is also possible.</p> <p>Since I want to have this being made dynamically so I can use it in a mixin, I added it to a for loop, like so:</p> <pre><code> def __init__(self, *args, **kwargs): super(Model, self).__init__(*args, **kwargs) trans = lambda c: c.get_translation() setattr(self.__class__, 'translation', property(trans)) # returns all fields of the translation model trans_fields = [field.name for field in [ related for related in self._meta.get_all_related_objects() if "translation" in related.name ][0].model._meta.fields] # should then assign all those fields dynamically for name in trans_fields: if not name == 'id' and not name == 'mymodel': fget = lambda c: getattr(trans(c), name) fset = lambda c, v: setattr(trans(c), name, v) setattr(self.__class__, name, property(fget, fset)) </code></pre> <p>So I thought, okay, since the <code>name</code> value resembles the name of the field, that I used to add manually before, it should then add a <code>property</code> with a name of the value of <code>name</code> on each run of the for loop. But it does not. When I call <code>mymodel.name</code> it returns the model instance (so basically <code>self</code>). I have no clue, what is different, when I do it in a forloop instead of all manually.</p> <p>Any ideas?</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload