def __new__(cls, name, bases, attrs): ### START - Build translation model # At first we build translation model so we can add it to attrs # Purpose is to not call 'add_to_class' after model is registered # We have to copy attributes because they change during creation of a model trans_attrs = attrs.copy() # Make a copy of Meta, so changes in it when creating a translation model does not affect # creation of multilingual model if attrs.has_key('Meta'): trans_attrs['Meta'] = classobj.__new__(classobj, 'Meta', (attrs['Meta'],), attrs['Meta'].__dict__.copy()) translation_name = name + "Translation" trans_attrs['multilingual_model_name'] = name c_trans_model = TranslationModelBase(translation_name, (TranslationModel, ), trans_attrs) ### END - Build translation model ### And some changes before we build multilingual model meta = attrs.get('Meta', None) abstract = getattr(meta, 'abstract', False) # Add translation model to attrs attrs['translation_model'] = c_trans_model if not abstract: # Add translation relations for language_code in [None] + get_all(): field = TranslationRelation(c_trans_model, base_name=TRANSLATION_FIELD_NAME, language_code=language_code) attrs[field.name] = field # Add proxies for translated fields into attrs for field in (c_trans_model._meta.fields + c_trans_model._meta.many_to_many): if field.name in ('id', 'language_code', 'master'): continue for language_code in get_all(): proxy = TranslationProxyField(field.name, language_code) attrs[proxy.name] = proxy proxy = TranslationProxyField(field.name, None) attrs[proxy.name] = proxy proxy = TranslationProxyField(field.name, None, fallback=True) attrs[proxy.name] = proxy # Handle manager if not 'objects' in attrs: # If there is no manager, set MultilingualManager as manager attrs['objects'] = MultilingualManager() elif not isinstance(attrs['objects'], MultilingualManager): # Make sure that if the class specifies objects then it is a subclass of our Manager. # Don't check other managers since someone might want to have a non-multilingual manager, but assigning # a non-multilingual manager to objects would be a common mistake. raise ValueError("Model %s specifies translations, so its 'objects' manager must be a subclass of "\ "multilingual.Manager." % name) # And now just create multilingual model return super(MultilingualModelBase, cls).__new__(cls, name, bases, attrs)
def __new__(cls, name, bases, attrs): # This only happens for base multilingual models if not attrs.has_key('Translation'): #TODO: CHECK attrs here super_new = super(TranslationModelBase, cls).__new__ return super_new(cls, name, bases, attrs) # multilingual meta attr_meta = attrs.pop('Meta', None) # Prepare attributes for translation model trans_attrs = attrs['Translation'].__dict__.copy() trans_attrs.pop('__doc__') # original Meta of Translation Model trans_meta = trans_attrs.pop('Meta', None) ### START - Create Meta for TranslationModel meta_attrs = getattr(trans_meta, '__dict__', {}) for key in META_INHERITES: if hasattr(attr_meta, key): meta_attrs[key] = getattr(attr_meta, key) # Append suffix to db_table of multilingual class if not meta_attrs.has_key('db_table') and hasattr(attr_meta, 'db_table'): meta_attrs['db_table'] = attr_meta.db_table + 'translation' # Handle unique constraints meta_attrs['unique_together'] = list(meta_attrs.get('unique_together', [])) meta_attrs['unique_together'] = [ tuple(list(item) + ['language_code']) for item in meta_attrs['unique_together'] ] # append all unique fields to unique_together with 'language_code' field # and remove their uniqueness for item_name, item in trans_attrs.items(): if isinstance(item, models.Field) and item.unique and not item.primary_key: meta_attrs['unique_together'].append((item_name, 'language_code')) trans_attrs[item_name]._unique = False # TODO: use TranslationModel.Meta instead of hardcoding # Appending necessary unique together meta_attrs['unique_together'].append(('language_code', 'master')) # TODO: enable related_name in Options related_name = meta_attrs.pop('related_name', 'translations') # TODO: use something already existing instead of BaseTranslationMeta trans_attrs['Meta'] = classobj.__new__(classobj, 'Meta', (BaseTranslationMeta,), meta_attrs) ### END - Create Meta for TranslationModel # Add 'master' field trans_attrs['master'] = models.ForeignKey( attrs['multilingual_model_name'], related_name=related_name ) return super(TranslationModelBase, cls).__new__(cls, name, bases, trans_attrs)
def __new__(cls, name, bases, attrs): ### START - Build translation model # At first we build translation model so we can add it to attrs # Purpose is to not call 'add_to_class' after model is registered # We have to copy attributes because they change during creation of a model trans_attrs = attrs.copy() # Make a copy of Meta, so changes in it when creating a translation model does not affect # creation of multilingual model if attrs.has_key("Meta"): trans_attrs["Meta"] = classobj.__new__(classobj, "Meta", (attrs["Meta"],), attrs["Meta"].__dict__.copy()) translation_name = name + "Translation" trans_attrs["multilingual_model_name"] = name c_trans_model = TranslationModelBase(translation_name, (TranslationModel,), trans_attrs) ### END - Build translation model ### And some changes before we build multilingual model # Add translation model to attrs attrs["translation_model"] = c_trans_model # Add proxies for translated fields into attrs for field in c_trans_model._meta.fields: if field.name in ("id", "language_code", "master"): continue for language_code in get_all(): proxy = TranslationProxyField(field.name, language_code) attrs[proxy.name] = proxy proxy = TranslationProxyField(field.name, None) attrs[proxy.name] = proxy proxy = TranslationProxyField(field.name, None, fallback=True) attrs[proxy.name] = proxy # Handle manager if not "objects" in attrs: # If there is no manager, set MultilingualManager as manager attrs["objects"] = MultilingualManager() elif not isinstance(attrs["objects"], MultilingualManager): # Make sure that if the class specifies objects then it is a subclass of our Manager. # Don't check other managers since someone might want to have a non-multilingual manager, but assigning # a non-multilingual manager to objects would be a common mistake. raise ValueError( "Model %s specifies translations, so its 'objects' manager must be a subclass of " "multilingual.Manager." % name ) # And now just create multilingual model return super(MultilingualModelBase, cls).__new__(cls, name, bases, attrs)