<s> import django <EOL> from django . conf import settings <EOL> from django . core . exceptions import FieldError , ValidationError <EOL> from django . forms . fields import CharField <EOL> from django . forms . formsets import formset_factory <EOL> from django . forms . models import ( ModelForm , BaseModelForm , ModelFormMetaclass , <EOL> fields_for_model , model_to_dict , construct_instance , BaseInlineFormSet , BaseModelFormSet , <EOL> modelform_factory , inlineformset_factory ) <EOL> if django . VERSION >= ( <NUM_LIT:1> , <NUM_LIT:7> ) : <EOL> from django . forms . utils import ErrorList <EOL> else : <EOL> from django . forms . util import ErrorList <EOL> from django . forms . widgets import Select <EOL> from django . utils . translation import get_language , ugettext as _ <EOL> from hvad . compat import with_metaclass <EOL> from hvad . models import TranslatableModel , BaseTranslationModel <EOL> from hvad . utils import ( set_cached_translation , get_cached_translation , load_translation ) <EOL> try : <EOL> from collections import OrderedDict <EOL> except ImportError : <EOL> from django . utils . datastructures import SortedDict as OrderedDict <EOL> import warnings <EOL> veto_fields = ( '<STR_LIT:id>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ) <EOL> class TranslatableModelFormMetaclass ( ModelFormMetaclass ) : <EOL> '''<STR_LIT>''' <EOL> def __new__ ( cls , name , bases , attrs ) : <EOL> meta = attrs . get ( '<STR_LIT:Meta>' ) <EOL> if meta is None : <EOL> base_meta = next ( ( ( base . Meta , ) for base in bases if hasattr ( base , '<STR_LIT:Meta>' ) ) , ( ) ) <EOL> meta = attrs [ '<STR_LIT:Meta>' ] = type ( '<STR_LIT:Meta>' , base_meta + ( object , ) , { } ) <EOL> model = getattr ( meta , '<STR_LIT>' , None ) <EOL> fields = getattr ( meta , '<STR_LIT>' , None ) <EOL> exclude = meta . exclude = list ( getattr ( meta , '<STR_LIT>' , ( ) ) ) <EOL> if fields is not None and '<STR_LIT>' in fields : <EOL> raise FieldError ( '<STR_LIT>' ) <EOL> if model : <EOL> if not issubclass ( model , TranslatableModel ) : <EOL> raise TypeError ( '<STR_LIT>' <EOL> '<STR_LIT>' % model . __name__ ) <EOL> exclude . append ( model . _meta . translations_accessor ) <EOL> if fields is not None and model . _meta . translations_accessor in fields : <EOL> raise FieldError ( '<STR_LIT>' , model . _meta . translations_accessor ) <EOL> tfields = fields_for_model ( <EOL> model . _meta . translations_model , <EOL> fields = fields , <EOL> exclude = exclude + list ( veto_fields ) , <EOL> widgets = getattr ( meta , '<STR_LIT>' , None ) , <EOL> formfield_callback = attrs . get ( '<STR_LIT>' ) <EOL> ) <EOL> if fields is not None : <EOL> meta . fields = [ field for field in fields if tfields . get ( field ) is None ] <EOL> new_class = super ( TranslatableModelFormMetaclass , cls ) . __new__ ( cls , name , bases , attrs ) <EOL> if model : <EOL> if fields is None : <EOL> for name , field in tfields . items ( ) : <EOL> if field is not None : <EOL> new_class . base_fields [ name ] = field <EOL> else : <EOL> new_class . base_fields = OrderedDict ( <EOL> item for item in ( <EOL> ( name , new_class . base_fields . get ( name , tfields . get ( name ) ) ) <EOL> for name in fields <EOL> ) <EOL> if item [ <NUM_LIT:1> ] is not None <EOL> ) <EOL> new_class . _meta . fields = meta . fields = fields <EOL> return new_class <EOL> class BaseTranslatableModelForm ( BaseModelForm ) : <EOL> '''<STR_LIT>''' <EOL> def __init__ ( self , data = None , files = None , auto_id = '<STR_LIT>' , prefix = None , <EOL> initial = None , error_class = ErrorList , label_suffix = '<STR_LIT::>' , <EOL> empty_permitted = False , instance = None ) : <EOL> object_data = { } <EOL> enforce = hasattr ( self , '<STR_LIT>' ) <EOL> language = getattr ( self , '<STR_LIT>' , None ) or get_language ( ) <EOL> if instance is not None : <EOL> translation = load_translation ( instance , language , enforce ) <EOL> if translation . pk : <EOL> exclude = ( tuple ( self . _meta . exclude or ( ) ) + veto_fields ) <EOL> object_data . update ( <EOL> model_to_dict ( translation , self . _meta . fields , exclude ) <EOL> ) <EOL> if initial is not None : <EOL> object_data . update ( initial ) <EOL> super ( BaseTranslatableModelForm , self ) . __init__ ( <EOL> data , files , auto_id , prefix , object_data , <EOL> error_class , label_suffix , empty_permitted , instance <EOL> ) <EOL> def clean ( self ) : <EOL> '''<STR_LIT>''' <EOL> data = super ( BaseTranslatableModelForm , self ) . clean ( ) <EOL> if hasattr ( self , '<STR_LIT>' ) : <EOL> data [ '<STR_LIT>' ] = self . language <EOL> return data <EOL> def _post_clean ( self ) : <EOL> '''<STR_LIT>''' <EOL> enforce = '<STR_LIT>' in self . cleaned_data <EOL> language = self . cleaned_data . get ( '<STR_LIT>' ) or get_language ( ) <EOL> translation = load_translation ( self . instance , language , enforce ) <EOL> exclude = self . _get_validation_exclusions ( ) <EOL> translation = construct_instance ( self , translation , self . _meta . fields , exclude ) <EOL> set_cached_translation ( self . instance , translation ) <EOL> result = super ( BaseTranslatableModelForm , self ) . _post_clean ( ) <EOL> return result <EOL> def _get_validation_exclusions ( self ) : <EOL> exclude = super ( BaseTranslatableModelForm , self ) . _get_validation_exclusions ( ) <EOL> for f in self . instance . _meta . translations_model . _meta . fields : <EOL> if f . name in veto_fields : <EOL> pass <EOL> elif ( ( f . name not in self . fields ) or <EOL> ( self . _meta . fields and f . name not in self . _meta . fields ) or <EOL> ( self . _meta . exclude and f . name in self . _meta . exclude ) or <EOL> ( f . name in self . _errors ) ) : <EOL> exclude . append ( f . name ) <EOL> else : <EOL> form_field = self . fields [ f . name ] <EOL> field_value = self . cleaned_data . get ( f . name , None ) <EOL> if not f . blank and not form_field . required and field_value in form_field . empty_values : <EOL> exclude . append ( f . name ) <EOL> return exclude <EOL> def save ( self , commit = True ) : <EOL> '''<STR_LIT>''' <EOL> assert self . is_valid ( ) , ( '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> enforce = '<STR_LIT>' in self . cleaned_data <EOL> language = self . cleaned_data . get ( '<STR_LIT>' ) or get_language ( ) <EOL> translation = load_translation ( self . instance , language , enforce ) <EOL> excludes = list ( self . _meta . exclude ) + [ '<STR_LIT>' , '<STR_LIT>' ] <EOL> translation = construct_instance ( self , translation , <EOL> self . _meta . fields , excludes ) <EOL> set_cached_translation ( self . instance , translation ) <EOL> return super ( BaseTranslatableModelForm , self ) . save ( commit = commit ) <EOL> if django . VERSION >= ( <NUM_LIT:1> , <NUM_LIT:7> ) : <EOL> class TranslatableModelForm ( with_metaclass ( TranslatableModelFormMetaclass , <EOL> BaseTranslatableModelForm ) ) : <EOL> pass <EOL> else : <EOL> class TranslatableModelForm ( with_metaclass ( TranslatableModelFormMetaclass , <EOL> BaseTranslatableModelForm , ModelForm ) ) : <EOL> __metaclass__ = TranslatableModelFormMetaclass <EOL> def translatable_modelform_factory ( language , model , form = TranslatableModelForm , * args , ** kwargs ) : <EOL> if not issubclass ( form , TranslatableModelForm ) : <EOL> raise TypeError ( '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> klass = modelform_factory ( model , form , * args , ** kwargs ) <EOL> klass . language = language <EOL> return klass <EOL> def translatable_modelformset_factory ( language , model , form = TranslatableModelForm , <EOL> formfield_callback = None , formset = BaseModelFormSet , <EOL> extra = <NUM_LIT:1> , can_delete = False , can_order = False , <EOL> max_num = None , fields = None , exclude = None , ** kwargs ) : <EOL> form_kwargs , formset_kwargs = { } , { } <EOL> for key in ( '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ) : <EOL> if key in kwargs : <EOL> form_kwargs [ key ] = kwargs . pop ( key ) <EOL> for key in ( '<STR_LIT>' , ) : <EOL> if key in kwargs : <EOL> formset_kwargs [ key ] = kwargs . pop ( key ) <EOL> if kwargs : <EOL> raise TypeError ( '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' % tuple ( kwargs . keys ( ) ) ) <EOL> form = translatable_modelform_factory ( <EOL> language , model , form = form , fields = fields , exclude = exclude , <EOL> formfield_callback = formfield_callback , ** form_kwargs <EOL> ) <EOL> FormSet = formset_factory ( form , formset , extra = extra , max_num = max_num , <EOL> can_order = can_order , can_delete = can_delete , ** formset_kwargs ) <EOL> FormSet . model = model <EOL> return FormSet <EOL> def translatable_inlineformset_factory ( language , parent_model , model , form = TranslatableModelForm , <EOL> formset = BaseInlineFormSet , fk_name = None , <EOL> fields = None , exclude = None , extra = <NUM_LIT:3> , <EOL> can_order = False , can_delete = True , <EOL> max_num = None , formfield_callback = None , ** kwargs ) : <EOL> from django . forms . models import _get_foreign_key <EOL> fk = _get_foreign_key ( parent_model , model , fk_name = fk_name ) <EOL> if fk . unique : <EOL> max_num = <NUM_LIT:1> <EOL> FormSet = translatable_modelformset_factory ( language , model , <EOL> form = form , formfield_callback = formfield_callback , formset = formset , <EOL> extra = extra , can_delete = can_delete , can_order = can_order , <EOL> fields = fields , exclude = exclude , max_num = max_num , ** kwargs ) <EOL> FormSet . fk = fk <EOL> return FormSet <EOL> class BaseTranslationFormSet ( BaseInlineFormSet ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , * args , ** kwargs ) : <EOL> super ( BaseTranslationFormSet , self ) . __init__ ( * args , ** kwargs ) <EOL> self . queryset = self . order_translations ( self . queryset ) <EOL> def order_translations ( self , qs ) : <EOL> return qs . order_by ( '<STR_LIT>' ) <EOL> def clean ( self ) : <EOL> super ( BaseTranslationFormSet , self ) . clean ( ) <EOL> master = self . instance <EOL> stashed = get_cached_translation ( master ) <EOL> for form in self . forms : <EOL> set_cached_translation ( master , form . instance ) <EOL> exclusions = form . _get_validation_exclusions ( ) <EOL> exclusions . extend ( f . name for f in master . _meta . fields ) <EOL> try : <EOL> master . clean ( ) <EOL> except ValidationError as e : <EOL> form . _update_errors ( e ) <EOL> set_cached_translation ( master , stashed ) <EOL> forms_to_delete = self . deleted_forms <EOL> provided = [ form for form in self . forms <EOL> if ( getattr ( form . instance , '<STR_LIT>' , None ) is not None or <EOL> form . has_changed ( ) ) <EOL> and not form in forms_to_delete ] <EOL> if len ( provided ) < <NUM_LIT:1> : <EOL> raise ValidationError ( _ ( '<STR_LIT>' ) , <EOL> code = '<STR_LIT>' ) <EOL> def _save_translation ( self , form , commit = True ) : <EOL> obj = form . save ( commit = False ) <EOL> assert isinstance ( obj , BaseTranslationModel ) <EOL> if commit : <EOL> stashed = set_cached_translation ( self . instance , obj ) <EOL> self . instance . save ( ) <EOL> if hasattr ( obj , '<STR_LIT>' ) : <EOL> obj . save_m2m ( ) <EOL> set_cached_translation ( self . instance , stashed ) <EOL> return obj <EOL> def save_new ( self , form , commit = True ) : <EOL> return self . _save_translation ( form , commit ) <EOL> def save_existing ( self , form , instance , commit = True ) : <EOL> return self . _save_translation ( form , commit ) <EOL> def add_fields ( self , form , index ) : <EOL> super ( BaseTranslationFormSet , self ) . add_fields ( form , index ) <EOL> if not '<STR_LIT>' in form . fields : <EOL> form . fields [ '<STR_LIT>' ] = CharField ( <EOL> required = True , initial = form . instance . language_code , <EOL> widget = Select ( choices = ( ( '<STR_LIT>' , '<STR_LIT>' ) , ) + settings . LANGUAGES ) <EOL> ) <EOL> try : <EOL> form . _meta . fields . append ( '<STR_LIT>' ) <EOL> except AttributeError : <EOL> form . _meta . fields += ( '<STR_LIT>' , ) <EOL> if '<STR_LIT>' in form . fields : <EOL> del form . fields [ '<STR_LIT>' ] <EOL> def translationformset_factory ( model , ** kwargs ) : <EOL> """<STR_LIT>""" <EOL> defaults = { <EOL> '<STR_LIT>' : BaseTranslationFormSet , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> } <EOL> defaults . update ( kwargs ) <EOL> return inlineformset_factory ( model , model . _meta . translations_model , ** defaults ) </s>
