def __call__(self, cls): """run the filter on the class to be decorated""" if hasattr(cls, 'model'): self.model = cls.model elif not self.model: raise AttributeError(L10n.error_no_model % (cls.__name__) ) # gather names of fields added by I18n added_fields = [] for field in self.model.localized_fields: for language in get_all_language_codes(): added_fields.append(get_real_fieldname(field, language)) # determine name of the permission to edit untranslated fields permisson_name = "%s.can_edit_untranslated_fields_of_%s" % ( self.model._meta.app_label, self.model.__name__.lower() ) # make sure that fields become read_only when no permission is given. def get_readonly_fields(self, request, obj=None): if not request.user.has_perm(permisson_name): fields = self.fields or map(lambda x: x.name, self.model._meta.fields) # remove primary key because we don't show that, not even uneditable fields.pop(self.model._meta.pk_index()) prohibited_fields = compute_prohibited(fields, self.exclude, self.model.localized_fields) return set(self.readonly_fields).union(prohibited_fields) return self.readonly_fields cls.get_readonly_fields = get_readonly_fields # override some views to hide fields which are not localized if hasattr(cls, 'change_view'): # BaseModelAdmin.__init__ will mess up our lazy lists if the following is # not allready defined if 'action_checkbox' not in cls.list_display and cls.actions is not None: cls.list_display = ['action_checkbox'] + list(cls.list_display) if not cls.list_display_links: for name in cls.list_display: if name != 'action_checkbox': cls.list_display_links = [name] break # Make certain properties lazy and internationalized cls.list_display_links = all_lazy_localized_list(cls.list_display_links, self.model.localized_fields) cls.list_display = all_lazy_localized_list(cls.list_display, self.model.localized_fields) cls.list_editable = all_lazy_localized_list(cls.list_editable, self.model.localized_fields) cls.search_fields = all_lazy_localized_list(cls.search_fields, self.model.localized_fields) return cls
def localize_fields(cls, localized_fields): """ For each field name in localized_fields, for each language in settings.LANGUAGES, add fields to cls, and remove the original field, instead replace it with a DefaultFieldDescriptor, which always returns the field in the current language. """ # never do this twice if hasattr(cls, 'localized_fields'): return cls # MSGID_LANGUAGE is the language that is used for the gettext message id's. # If it is not available, because the site isn't using subsites, the # LANGUAGE_CODE is good too. MSGID_LANGUAGE gives the opportunity to # specify a language not available in the site but which is still used for # the message id's. msgid_language = getattr(settings, 'MSGID_LANGUAGE', settings.LANGUAGE_CODE) # set the localized fields property cls.localized_fields = localized_fields for field in localized_fields: original_attr = get_field_from_model_by_name(cls, field) for cnt, language_code in enumerate(get_all_language_codes()): i18n_attr = copy.copy(original_attr) # add support for south introspection. i18n_attr._south_introspects = True i18n_attr.original_fieldname = field i18n_attr.include_in_xml = False lang_attr_name = get_real_fieldname(field, language_code) i18n_attr.name = lang_attr_name i18n_attr.creation_counter = i18n_attr.creation_counter + .01 * cnt # null must be allowed for the message id language because this # language might not be available at all in the backend if not i18n_attr.null and i18n_attr.default is NOT_PROVIDED: i18n_attr.null = True if language_code != msgid_language: # no validation for the fields that are language specific if not i18n_attr.blank: i18n_attr.blank = True if i18n_attr.verbose_name: i18n_attr.verbose_name = translation.string_concat( i18n_attr.verbose_name, u' (%s)' % language_code) cls.add_to_class(lang_attr_name, i18n_attr) # delete original field del cls._meta.local_fields[cls._meta.local_fields.index(original_attr)] # copy some values and functions from the original_attr # so the field can emulate the original_attr as good as possible kwargs = { 'serialize': getattr(original_attr, 'serialize', True), 'extra_attrs': getattr(original_attr, 'extra_attrs', None), 'max_length': getattr(original_attr, 'max_length', None), 'min_length': getattr(original_attr, 'min_length', None), 'form_field': original_attr.formfield(**FORMFIELD_FOR_DBFIELD_DEFAULTS.get( original_attr.__class__, {})), 'get_internal_type': original_attr.get_internal_type, 'unique': getattr(original_attr, 'unique', False), 'to_python': original_attr.to_python, } # copy __serialize__ if it was defined on the original attr if hasattr(original_attr, '__serialize__'): kwargs['__serialize__'] = original_attr.__serialize__ # add the DefaultFieldDescriptor where the original_attr was. cls.add_to_class(field, DefaultFieldDescriptor(field, **kwargs)) # update fields cache cls._meta._fill_fields_cache() # return the finished product return cls
def __restoreBlank(self, cls, blankFlags): for field, blank in zip(self.localizedFields, blankFlags): for code in get_all_language_codes(): i18n_attr = get_field_from_model_by_name( cls, getLocalizedFieldName(field, code)) i18n_attr.blank = blank
def localize_fields(cls, localized_fields): """ For each field name in localized_fields, for each language in settings.LANGUAGES, add fields to cls, and remove the original field, instead replace it with a DefaultFieldDescriptor, which always returns the field in the current language. """ # never do this twice if hasattr(cls, 'localized_fields'): return cls # MSGID_LANGUAGE is the language that is used for the gettext message id's. # If it is not available, because the site isn't using subsites, the # LANGUAGE_CODE is good too. MSGID_LANGUAGE gives the opportunity to # specify a language not available in the site but which is still used for # the message id's. msgid_language = getattr(settings, 'MSGID_LANGUAGE', settings.LANGUAGE_CODE) # set the localized fields property cls.localized_fields = localized_fields for field in localized_fields: original_attr = get_field_from_model_by_name(cls, field) for cnt, language_code in enumerate(get_all_language_codes()): i18n_attr = copy.copy(original_attr) # add support for south introspection. i18n_attr._south_introspects = True i18n_attr.original_fieldname = field i18n_attr.include_in_xml = False lang_attr_name = get_real_fieldname(field, language_code) i18n_attr.name = lang_attr_name i18n_attr.creation_counter = i18n_attr.creation_counter + .01 * cnt # null must be allowed for the message id language because this # language might not be available at all in the backend if not i18n_attr.null and i18n_attr.default is NOT_PROVIDED: i18n_attr.null = True if language_code != msgid_language: # no validation for the fields that are language specific if not i18n_attr.blank: i18n_attr.blank = True if i18n_attr.verbose_name: i18n_attr.verbose_name = translation.string_concat( i18n_attr.verbose_name, u' (%s)' % language_code) cls.add_to_class(lang_attr_name, i18n_attr) # delete original field del cls._meta.local_fields[cls._meta.local_fields.index(original_attr)] # copy some values and functions from the original_attr # so the field can emulate the original_attr as good as possible kwargs = { 'serialize': getattr(original_attr, 'serialize', True), 'extra_attrs': getattr(original_attr, 'extra_attrs', None), 'max_length': getattr(original_attr, 'max_length', None), 'min_length': getattr(original_attr, 'min_length', None), 'form_field': original_attr.formfield( **FORMFIELD_FOR_DBFIELD_DEFAULTS.get( original_attr.__class__, {})), 'get_internal_type': original_attr.get_internal_type, 'unique': getattr(original_attr, 'unique', False), 'to_python': original_attr.to_python, } # copy __serialize__ if it was defined on the original attr if hasattr(original_attr, '__serialize__'): kwargs['__serialize__'] = original_attr.__serialize__ # add the DefaultFieldDescriptor where the original_attr was. cls.add_to_class(field, DefaultFieldDescriptor(field, **kwargs)) # update fields cache try: cls._meta._fill_fields_cache() except AttributeError: # Django 1.8 removed _fill_fields_cache cls._meta._expire_cache() cls._meta._get_fields(reverse=False) # return the finished product return cls
def __restoreBlank(self, cls, blankFlags): for field, blank in zip(self.localizedFields, blankFlags): for code in get_all_language_codes(): i18n_attr = get_field_from_model_by_name(cls, getLocalizedFieldName(field, code)) i18n_attr.blank = blank
def __call__(self, cls): """run the filter on the class to be decorated""" if hasattr(cls, 'model'): self.model = cls.model elif not self.model: raise AttributeError(L10n.error_no_model % (cls.__name__)) # gather names of fields added by I18n added_fields = [] for field in self.model.localized_fields: for language in get_all_language_codes(): added_fields.append(get_real_fieldname(field, language)) # hide added fields from form and admin cls.exclude = added_fields cls.form = forms.make_localised_form(self.model, cls.form, exclude=added_fields) # determine name of the permission to edit untranslated fields permisson_name = "%s.can_edit_untranslated_fields_of_%s" % ( self.model._meta.app_label, self.model.__name__.lower()) # make sure that fields become read_only when no permission is given. def get_readonly_fields(self, request, obj=None): if not request.user.has_perm(permisson_name): fields = self.fields or map(lambda x: x.name, self.model._meta.fields) # remove primary key because we don't show that, not even uneditable fields.pop(self.model._meta.pk_index()) prohibited_fields = compute_prohibited( fields, self.exclude, self.model.localized_fields) return set(self.readonly_fields).union(prohibited_fields) return self.readonly_fields cls.get_readonly_fields = get_readonly_fields # override some views to hide fields which are not localized if hasattr(cls, 'change_view'): # BaseModelAdmin.__init__ will mess up our lazy lists if the following is # not allready defined if 'action_checkbox' not in cls.list_display and cls.actions is not None: cls.list_display = ['action_checkbox'] + list(cls.list_display) if not cls.list_display_links: for name in cls.list_display: if name != 'action_checkbox': cls.list_display_links = [name] break # Make certain properties lazy and internationalized cls.list_display_links = lazy_localized_list( cls.list_display_links, self.model.localized_fields) cls.list_display = lazy_localized_list(cls.list_display, self.model.localized_fields) cls.list_editable = lazy_localized_list( cls.list_editable, self.model.localized_fields) cls.search_fields = lazy_localized_list( cls.search_fields, self.model.localized_fields) else: def get_formset(self, request, obj=None, **kwargs): if self.declared_fieldsets: fields = flatten_fieldsets(self.declared_fieldsets) else: fields = None if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) exclude = exclude or None if not hasattr(self, 'ct_fk_field'): return super(cls, self).get_formset(request, obj, **kwargs) else: # TODO: # this code can be deleted if django fixes GenericInlineModelAdmin it's # get_formset signature so it looks like InlineModelAdmin defaults = { "ct_field": self.ct_field, "fk_field": self.ct_fk_field, "form": self.form, "formfield_callback": self.formfield_for_dbfield, "formset": self.formset, "extra": self.extra, "can_delete": self.can_delete, "can_order": False, "fields": fields, "max_num": self.max_num, "exclude": exclude } defaults.update(kwargs) # the BaseGenericInlineFormSet does not work too well # with modified models, so use LocalizableGenericInlineFormSet. if self.formset is BaseGenericInlineFormSet \ or self.formset.__class__ is BaseGenericInlineFormSet: defaults['formset'] = LocalizableGenericInlineFormSet return generic_inlineformset_factory( self.model, **defaults) cls.get_formset = get_formset return cls
def __call__(self, cls): """run the filter on the class to be decorated""" if hasattr(cls, 'model'): self.model = cls.model elif not self.model: raise AttributeError(L10n.error_no_model % (cls.__name__) ) # gather names of fields added by I18n added_fields = [] for field in self.model.localized_fields: for language in get_all_language_codes(): added_fields.append("%s_%s" % (field, language)) # hide added fields from form and admin cls.exclude = added_fields cls.form = forms.make_localised_form(self.model, cls.form, exclude=added_fields) # determine name of the permission to edit untranslated fields permisson_name = "%s.can_edit_untranslated_fields_of_%s" % ( self.model._meta.app_label, self.model.__name__.lower() ) # make sure that fields become read_only when no permission is given. def get_readonly_fields(self, request, obj=None): if not request.user.has_perm(permisson_name): fields = self.fields or map(lambda x: x.name, self.model._meta.fields) # remove primary key because we don't show that, not even uneditable fields.pop(self.model._meta.pk_index()) prohibited_fields = compute_prohibited(fields, self.exclude, self.model.localized_fields) return set(self.readonly_fields).union(prohibited_fields) return self.readonly_fields cls.get_readonly_fields = get_readonly_fields # override some views to hide fields which are not localized if hasattr(cls, 'change_view'): # BaseModelAdmin.__init__ will mess up our lazy lists if the following is # not allready defined if 'action_checkbox' not in cls.list_display and cls.actions is not None: cls.list_display = ['action_checkbox'] + list(cls.list_display) if not cls.list_display_links: for name in cls.list_display: if name != 'action_checkbox': cls.list_display_links = [name] break # Make certain properties lazy and internationalized cls.list_display_links = lazy_localized_list(cls.list_display_links, self.model.localized_fields) cls.list_display = lazy_localized_list(cls.list_display, self.model.localized_fields) cls.list_editable = lazy_localized_list(cls.list_editable, self.model.localized_fields) cls.search_fields = lazy_localized_list(cls.search_fields, self.model.localized_fields) else: def get_formset(self, request, obj=None, **kwargs): if self.declared_fieldsets: fields = flatten_fieldsets(self.declared_fieldsets) else: fields = None if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) exclude = exclude or None if not hasattr(self, 'ct_fk_field'): return super(cls, self).get_formset(request, obj, **kwargs) else: # TODO: # this code can be deleted if django fixes GenericInlineModelAdmin it's # get_formset signature so it looks like InlineModelAdmin defaults = { "ct_field": self.ct_field, "fk_field": self.ct_fk_field, "form": self.form, "formfield_callback": self.formfield_for_dbfield, "formset": self.formset, "extra": self.extra, "can_delete": self.can_delete, "can_order": False, "fields": fields, "max_num": self.max_num, "exclude": exclude } defaults.update(kwargs) # the BaseGenericInlineFormSet does not work too well # with modified models, so use LocalizableGenericInlineFormSet. if self.formset is BaseGenericInlineFormSet \ or self.formset.__class__ is BaseGenericInlineFormSet: defaults['formset'] = LocalizableGenericInlineFormSet return generic_inlineformset_factory(self.model, **defaults) cls.get_formset = get_formset return cls