def update_object(instance: Model, new_data: Dict[str, Any], **kwargs): new_data = dict(new_data) new_data.update(kwargs) for field in instance._meta.fields: if field.name in new_data: setattr(instance, field.name, new_data[field.name]) instance.save()
def handle(self, *args, **options): dry_run = options['dry_run'] #verbosity = options['verbosity'] stale_cts = {} for ct in ContentType.objects.all(): if ct.model_class() is None: stale_cts[ct.pk] = ct items = (ContentItem.objects .non_polymorphic() # very important, or polymorphic skips them on fetching derived data .filter(polymorphic_ctype__in=list(stale_cts.keys())) .order_by('polymorphic_ctype', 'pk') ) if not items: self.stdout.write("No stale items found.") return if dry_run: self.stdout.write("The following content items are stale:") else: self.stdout.write("The following content items were stale:") for item in items: ct = stale_cts[item.polymorphic_ctype_id] self.stdout.write("- #{id} points to removed {app_label}.{model}".format(id=item.pk, app_label=ct.app_label, model=ct.model)) if not dry_run: try: item.delete() except PluginNotFound: Model.delete(item)
def post(self, request, *args, **kwargs): context = self.get_context_data(**kwargs) if not request.user.has_perm('agenda.can_manage_agenda'): messages.error(request, _('You are not authorized to manage the agenda.')) return self.render_to_response(context) transaction.commit() for item in Item.objects.all(): form = ItemOrderForm(request.POST, prefix="i%d" % item.id) if form.is_valid(): try: parent = Item.objects.get(id=form.cleaned_data['parent']) except Item.DoesNotExist: parent = None item.weight = form.cleaned_data['weight'] item.parent = parent Model.save(item) else: transaction.rollback() messages.error(request, _('Errors when reordering of the agenda')) return self.render_to_response(context) Item.objects.rebuild() # TODO: assure, that it is a valid tree transaction.commit() return self.render_to_response(context)
def save_group_on_m2m_changed( sender: Union[PersonGroupThrough, Group.owners.through], instance: models.Model, action: str, reverse: bool, model: models.Model, pk_set: Optional[set], **kwargs, ) -> None: """Ensure user and group data is synced to Django's models. AlekSIS maintains personal information and group meta-data / membership in its Person and Group models. As third-party libraries have no knowledge about this, we need to keep django.contrib.auth in sync. This signal handler triggers a save of group objects whenever a membership changes. The save() code will decide whether to update the Django objects or not. """ if action not in ("post_add", "post_remove", "post_clear"): # Only trigger once, after the change was applied to the database return if reverse: # Relationship was changed on the Person side, saving all groups # that have been touched there for group in model.objects.filter(pk__in=pk_set): group.save(force=True) else: # Relationship was changed on the Group side instance.save(force=True)
def _test_same_user(self, cls: type, obj: Model, ref: Model, key: str, is_list: bool): """ Tests that adding a reference to another user's object should fail :param cls: Serializer class :param obj: Object to be serialized :param ref: Reference to add, with the same user as obj :param key: Attribute field name for the reference :param is_list: Whether to treat it as a single reference or single-item list of references """ obj.save() ref.save() request = HttpRequest() request.user = self.user if is_list: data = {key: [ref.pk]} else: data = {key: ref.pk} serializer = cls(obj, data=data, partial=True, context={'request': request}) self.assertTrue(serializer.is_valid()) obj = serializer.save() if is_list: self.assertEqual(getattr(obj, key).get(pk=ref.pk), ref) else: self.assertEqual(getattr(obj, key), ref)
def _test_cross_user(self, cls: type, obj: Model, ref: Model, key: str, is_list: bool): """ Tests that adding a reference to another user's object should fail :param cls: Serializer class :param obj: Object to be serialized :param ref: Reference to add, with a different user than obj :param key: Attribute field name for the reference :param is_list: Whether to treat it as a single reference or single-item list of references """ obj.save() ref.save() request = HttpRequest() request.user = self.user if is_list: data = {key: [ref.pk]} else: data = {key: ref.pk} serializer = cls(obj, data=data, partial=True, context={'request': request}) self.assertFalse(serializer.is_valid()) self.assertEqual(serializer.errors.keys(), {key}) self.assertEqual(len(serializer.errors[key]), 1) self.assertIn("forbidden", serializer.errors[key][0])
def save(self, *args, **kwargs): if not self.pk and self.is_active(self.instance): raise RequestLimitExceeded( "The number of open requests for " "instance %s has been exceeded." % self.instance.provider_alias) Model.save(self, *args, **kwargs)
def update(self, instance: models.Model, validated_data: Any) -> Any: # Update current_organization and current_team current_organization = validated_data.pop("set_current_organization", None) current_team = validated_data.pop("set_current_team", None) if current_organization: if current_team and not current_organization.teams.filter(pk=current_team.pk).exists(): raise serializers.ValidationError( {"set_current_team": ["Team must belong to the same organization in set_current_organization."]} ) validated_data["current_organization"] = current_organization validated_data["current_team"] = current_team if current_team else current_organization.teams.first() elif current_team: validated_data["current_team"] = current_team validated_data["current_organization"] = current_team.organization # Update password current_password = validated_data.pop("current_password", None) password = self.validate_password_change( cast(User, instance), current_password, validated_data.pop("password", None) ) updated_attrs = list(validated_data.keys()) instance = cast(User, super().update(instance, validated_data)) if password: instance.set_password(password) instance.save() update_session_auth_hash(self.context["request"], instance) updated_attrs.append("password") report_user_updated(instance, updated_attrs) return instance
def save(self, *args, **kwargs): if not self.pk and self.is_active(self.instance): raise RequestLimitExceeded( "The number of open requests for " "instance %s has been exceeded." % self.instance.provider_alias ) Model.save(self, *args, **kwargs)
def delete_object(self, obj: Model): """Deletes model object Args: obj (Model): model object """ obj.delete()
def post(self, request, *args, **kwargs): if not request.user.has_perm('agenda.can_manage_agenda'): messages.error( request, _('You are not authorized to manage the agenda.')) context = self.get_context_data(**kwargs) return self.render_to_response(context) transaction.commit() for item in Item.objects.all(): form = ItemOrderForm(request.POST, prefix="i%d" % item.id) if form.is_valid(): try: parent = Item.objects.get(id=form.cleaned_data['parent']) except Item.DoesNotExist: parent = None item.weight = form.cleaned_data['weight'] item.parent = parent Model.save(item) else: transaction.rollback() messages.error( request, _('Errors when reordering of the agenda')) break else: Item.objects.rebuild() # TODO: assure, that it is a valid tree context = self.get_context_data(**kwargs) transaction.commit() if get_active_slide()['callback'] == 'agenda': update_projector() context = self.get_context_data(**kwargs) transaction.commit() return self.render_to_response(context)
def merge(self, alias_object: Model): primary_object = self.primary_object if not isinstance(alias_object, primary_object.__class__): raise TypeError('Only models of the same class can be merged') #logger.debug(f'Merging {self.model_meta.model_name}[pk={alias_object.pk}]') model_meta = ModelMeta(primary_object) for related_field in model_meta.related_fields: if related_field.one_to_many: self._handle_o2m_related_field(related_field, alias_object) elif related_field.one_to_one: self._handle_o2o_related_field(related_field, alias_object) elif related_field.many_to_many: self._handle_m2m_related_field(related_field, alias_object) for field in model_meta.editable_fields: primary_value = getattr(primary_object, field.name) alias_value = getattr(alias_object, field.name) #logger.debug(f'Primary {field.name} has value: {primary_value}, ' # f'Alias {field.name} has value: {alias_value}') if primary_value in field.empty_values and alias_value not in field.empty_values: #logger.debug(f'Setting primary {field.name} to alias value: {alias_value}') setattr(primary_object, field.name, alias_value) if not self.keep_old: #logger.debug(f'Deleting alias object {self.model_meta.model_name}[pk={alias_object.pk}]') alias_object.delete() primary_object.save()
def update_or_create_chat_from_raw( *, model: models.Model, field_name: str, raw_chat: types.Chat ): field = getattr(model, field_name, None) if field and not isinstance(field, Chat): return if field: if raw_chat: field.update_fields_from_raw(raw_chat=raw_chat) else: setattr(model, field_name, None) model.save() else: setattr( model, field_name, Chat.chats.update_or_create_from_raw( raw_chat=raw_chat ) ) model.save()
def __new__(cls, name, bases, attrs): module = attrs.pop("__module__") parents = [b for b in bases if isinstance(b, ModelMetaClass)] if parents: for obj_name, obj in attrs.items(): Model.add_to_class(obj_name, obj) return super(ModelMetaClass, cls).__new__(cls, name, bases, attrs)
def update_or_create_admin_log_analyzer( model: models.Model, field_name: str, chat_id: int, enabled: bool, create: bool = True, delete: bool = False, **kwargs, ): if chat_id is None: return field = getattr(model, field_name, None) if field and not isinstance(field, AdminLogAnalyzerMetaData): return if field: if delete: field.delete() model.save() else: field.update_fields(**{'enabled': enabled, **kwargs}) else: if create and not delete: setattr( model, field_name, AdminLogAnalyzerMetaData.objects.update_or_create_analyzer( chat_id=chat_id, enabled=enabled)) model.save()
def recache_lat_long(apps, schema_editor): from issues.models import Issue as CurrentIssue Issue = apps.get_model('issues', 'Issue') for issue in Issue.objects.filter(location__isnull=False): issue._cache_location = CurrentIssue._cache_location issue._cache_location() Model.save(self=issue, update_fields=('lat', 'long'))
def validate_and_update_object(obj: models.Model, **kwargs) \ -> Tuple[models.Model, List[str]]: """ :raises ValueError :return obj, is_updated """ assert isinstance(obj, models.Model) model = type(obj) m2m_kwargs, kwargs = _get_m2m_kwargs(model, **kwargs) updated_keys = {} for key, value in kwargs.items(): old_value = getattr(obj, key) if old_value == value: continue setattr(obj, key, value) updated_keys[key] = old_value if updated_keys: try: obj.full_clean() obj.save() if m2m_kwargs: _update_m2m_fields(obj, **m2m_kwargs) except (ValidationError, IntegrityError) as exc: for key, old_value in updated_keys.items(): setattr(obj, key, old_value) LOGGER.warning('Update %s error: %r (kwargs=%r)', model.__name__, exc, kwargs) raise ValueError(str(exc)) from exc return obj, list(updated_keys.keys())
def update_all_items(self, data: DefaultDict, owner: base, instance: Model = None): nested_data = dict() for item in self.nested_entities(): try: coll = data.pop(item['name']) nested_data[item['name']] = coll except KeyError: pass if instance is None: instance = owner(**data) else: # instance.__dict__.update(**data) for attr, value in data.items(): setattr(instance, attr, value) instance.save() for item in self.nested_entities(): items = nested_data[item['name']] entity_model = item['model'] serializer = item['serializer'] if 'serializer' in item else None m2m = getattr(instance, item['name']) if item['m2m'] is True else None self.update_items(items, entity_model, serializer, instance, m2m) instance.save() return instance
def update_or_create_message_views_analyzer( model: models.Model, field_name: str, chat_id: int, enabled: bool, create: bool = True, **kwargs, ): if chat_id is None: return field = getattr(model, field_name, None) if field and not isinstance(field, ChatMessageViewsAnalyzerMetaData): return if field: if len(kwargs) or enabled is not None: field.update_fields(**{'enabled': enabled, **kwargs}) else: field.delete() model.save() else: if create and enabled is not None: setattr( model, field_name, ChatMessageViewsAnalyzerMetaData. objects.update_or_create_analyzer(chat_id=chat_id, enabled=enabled)) model.save()
def update(cls, instance: Model, data: dict) -> Model: for key, value in data.items(): setattr(instance, key, value) instance.save() return instance
def remove_stale_items(self, stale_cts): """ See if there are items that point to a removed model. """ stale_ct_ids = list(stale_cts.keys()) items = (ContentItem.objects .non_polymorphic() # very important, or polymorphic skips them on fetching derived data .filter(polymorphic_ctype__in=stale_ct_ids) .order_by('polymorphic_ctype', 'pk') ) if not items: self.stdout.write("No stale items found.") return if self.dry_run: self.stdout.write("The following content items are stale:") else: self.stdout.write("The following content items were stale:") for item in items: ct = stale_cts[item.polymorphic_ctype_id] self.stdout.write("- #{id} points to removed {app_label}.{model}".format( id=item.pk, app_label=ct.app_label, model=ct.model )) if not self.dry_run: try: item.delete() except PluginNotFound: Model.delete(item)
def update_or_create_message_from_raw( *, model: models.Model, field_name: str, raw_message: types.Message, chat_id: int, logger_account: "tg_models.TelegramAccount" = None): from .message import Message field = getattr(model, field_name, None) if field and not isinstance(field, Message): return if field: if raw_message: field.update_fields_from_raw(raw_message=raw_message, chat_id=chat_id, logger_account=logger_account) else: setattr(model, field_name, None) model.save() else: if raw_message: setattr( model, field_name, Message.objects.update_or_create_from_raw( raw_user=raw_message, chat_id=chat_id, logger_account=logger_account)) model.save()
def rename_files_of_created_instances(cls, instance: models.Model, created, raw, update_fields: Optional[Collection], **kwargs): """ This signal receiver renames the files belonging to ``FileField``s (or subclasses) of model instances when they're created, if the filename matches the token regex used by ``get_pk_prefixed_filename_func()``. """ if raw or not created: return for field in instance._meta.fields: # `update_fields` having a value of `None` means that all the fields should be updated if (update_fields is not None and field.name not in update_fields or not isinstance(field, models.FileField)): continue field_value: FieldFile = getattr(instance, field.name) old_name = field_value.name if not cls.REPLACEABLE_TOKEN_REGEX.search(old_name): continue first_part, _token, last_part = cls.REPLACEABLE_TOKEN_REGEX.split( old_name) new_name = f"{first_part}{instance.pk}{last_part}" # Rename the actual file old_file_path = Path(field_value.path) new_file_path = old_file_path.with_name(Path(new_name).name) old_file_path.rename(new_file_path) # Save the new filename for the field field_value.name = new_name instance.save(update_fields=[field.name])
def remove_stale_items(self, stale_cts): """ See if there are items that point to a removed model. """ stale_ct_ids = list(stale_cts.keys()) items = ( ContentItem.objects.non_polymorphic( ) # very important, or polymorphic skips them on fetching derived data .filter(polymorphic_ctype__in=stale_ct_ids).order_by( 'polymorphic_ctype', 'pk')) if not items: self.stdout.write("No stale items found.") return if self.dry_run: self.stdout.write("The following content items are stale:") else: self.stdout.write("The following content items were stale:") for item in items: ct = stale_cts[item.polymorphic_ctype_id] self.stdout.write( "- #{id} points to removed {app_label}.{model}".format( id=item.pk, app_label=ct.app_label, model=ct.model)) if not self.dry_run: try: item.delete() except PluginNotFound: Model.delete(item)
def save(self, *args, **kwargs): if self.name is None: try: self.name = getservbyport(self.port) except OSError: self.name = 'port-%d' % self.port Model.save(self, *args, **kwargs)
def clone_object(obj: models.Model, **kwargs: Any) -> models.Model: """ Clones a django model instance.""" obj = deepcopy(obj) obj.pk = None for k, v in kwargs.items(): setattr(obj, k, v) obj.save(force_insert=True) return obj
def enlarged_create(Model, filter_kwargs, commit=True): filter_kwargs, m2m_kwargs = separate_m2m_kwargs(Model, filter_kwargs) obj = Model(**filter_kwargs) if commit: obj.save() for k, v in m2m_kwargs.items(): getattr(obj, k).add(*v) return obj
def delete(self, model: models.Model) -> None: """Immediately deletes the specified model instance. Args: model (models.Model): the model instance to delete """ self._isinstance(model) model.delete()
def clone(self, obj: Model, overrides: Dict = None) -> Model: logger.info(f"Cloning: #{obj.id}: {obj}") m2ms = self._get_m2m(obj) obj.pk = None self._set_overrides(obj, overrides) obj.save() self._set_m2m(obj, m2ms) return obj
def save_model(self, request: HttpRequest, obj: Model, form: Form, change: bool) -> None: if not change: tenant_field = get_tenant_field(obj) if tenant_field: setattr(obj, tenant_field.attname, request.session['active_tenant']) obj.save()
def foreign_key( cls, field_name: str, to: models.Model, to_field: str = "pk", to_field_type: JSONFieldMixin = IntegerField, related_name: Optional[str] = None, ) -> None: """Add a virtual ForeignKey. This works by storing the primary key (or any field passed in the to_field argument) and adding a property that queries the desired model. If the foreign model also is an ExtensibleModel, a reverse mapping is also added under the related_name passed as argument, or this model's default related name. """ id_field_name = f"{field_name}_id" if related_name is None: related_name = cls.Meta.default_related_name # Add field to hold key to foreign model id_field = to_field_type(blank=True, null=True) cls.field(**{id_field_name: id_field}) @property def _virtual_fk(self) -> Optional[models.Model]: id_field_val = getattr(self, id_field_name) if id_field_val: try: return to.objects.get(**{to_field: id_field_val}) except to.DoesNotExist: # We found a stale foreign key setattr(self, id_field_name, None) self.save() return None else: return None @_virtual_fk.setter def _virtual_fk(self, value: Optional[models.Model] = None) -> None: if value is None: id_field_val = None else: id_field_val = getattr(value, to_field) setattr(self, id_field_name, id_field_val) # Add property to wrap get/set on foreign model instance cls._safe_add(_virtual_fk, field_name) # Add related property on foreign model instance if it provides such an interface if hasattr(to, "_safe_add"): def _virtual_related(self) -> models.QuerySet: id_field_val = getattr(self, to_field) return cls.objects.filter(**{id_field_name: id_field_val}) to.property_(_virtual_related, related_name)
def log_whodid(obj: models.Model, user) -> None: """ Stores the given user as creator or editor of the given object """ if hasattr(obj, 'created_by') and obj.created_by is None: obj.created_by = user if hasattr(obj, 'lastmodified_by'): obj.lastmodified_by = user
def update_model(model: Model, **update_data): '根据内容改变与否判断需要更新的模型字段' update_fields = [] for field in update_data: if update_data[field] != getattr(model, field): setattr(model, field, update_data[field]) update_fields.append(field) if update_fields: model.save(update_fields=update_fields)
def save(self, *args, **kwargs): self.ascii_tag = unidecode(self.tag) words = self.ascii_tag.split() known_words_list = known_words(words) for word in words: new_word = Word(word) if not new_word in known_words_list: new_word.save() Model.save(self, *args, **kwargs)
def updateModel(model: Model, instance: Model, fields: Mapping): print(fields) updated_fields = {} for key, value in fields.items(): updated_fields.update({key: value[0] or value[1]}) print(updated_fields) for key, value in updated_fields.items(): setattr(instance, key, value) instance.save() return instance
def update_instance(instance: Model, args: Dict, exception: List = ["id"]) -> Model: if instance: [ setattr(instance, key, value) for key, value in args.items() if key not in exception ] instance.save() return instance
def versao_1_2_2(cmd, *args): """ Atualizações pra versão 1.2.2. Deve ser chamada após exportar o banco de dados pra um arquivo de dump JSON e remover o arquivo do banco de dados. Ações: - Cria um novo banco de dados e o superusuário padrão - Faz as conversões necessárias sobre o dump nos modelos que mudaram - Importa o dump convertido pro banco de dados - Carrega fixture de feriados bancários Argumentos da linha de comando: - dump_file: arquivo de dump do banco de dados na versão 1.2.1 """ if len(args) != 1: raise CommandError("Uso: atualizar 1.2.2 <dump_file>\n\ndump: arquivo de dump do banco de dados anterior (JSON)") sync_and_evolve() criar_superusuario() print("Convertendo entradas no modelo antigo pro novo modelo...") novo_bd_json = converter(args[0]) tmp_dump_filename = "fixture_convertida.json" print("Armazenando dados convertidos em {tmp_dump_filename}".format(**vars())) with open(tmp_dump_filename, "w") as tmp_dump_file: tmp_dump_file.write(novo_bd_json) print("Carregando dados convertidos no banco de dados...") call_command("loaddata", tmp_dump_filename) print("Removendo arquivo temporário...") os.remove(tmp_dump_filename) print("Carregando fixture de feriados bancários...") call_command("loaddata", "feriados_bancarios") print("Reunindo arquivos estáticos...") call_command("collectstatic", interactive=False) print("Re-salvando os pagamentos com cartões pra preencher data de depósito") for pagamento in PagamentoComCartao.objects.all(): pagamento.data_do_deposito = pagamento._data_do_deposito() Model.save(pagamento)
def __init__(self, instance: Model = None, deleted: bool = False, collection_string: str = None, id: int = None, full_data: Dict[str, Any] = None, information: Dict[str, Any] = None) -> None: """ Do not use this. Use the methods from_instance() or from_values(). """ self.instance = instance self.deleted = deleted self.full_data = full_data self.information = information or {} if instance is not None: # Collection element is created via instance self.collection_string = instance.get_collection_string() self.id = instance.pk elif collection_string is not None and id is not None: # Collection element is created via values self.collection_string = collection_string self.id = id else: raise RuntimeError( 'Invalid state. Use CollectionElement.from_instance() or ' 'CollectionElement.from_values() but not CollectionElement() ' 'directly.') if self.is_deleted(): # Delete the element from the cache, if self.is_deleted() is True: full_data_cache.del_element(self.collection_string, self.id) else: # The call to get_full_data() has some sideeffects. When the object # was created with from_instance() or the object is not in the cache # then get_full_data() will save the object into the cache. # This will also raise a DoesNotExist error, if the object does # neither exist in the cache nor in the database. self.get_full_data()
def rename_all_files(): """ Rename the data files according to the scheme: yyyy/mm/dd/id.h5 """ for curve in CurveDB.objects.all(): full_name_old = curve.get_full_filename() new_name = osp.join( curve.params["date"].strftime('%Y/%m/%d'), str(curve.id) + '.h5') curve.data_file = new_name if not osp.exists(full_name_old): print 'file ' + full_name_old + " doesn't exist" else: shutil.move(full_name_old, curve.get_full_filename()) Model.save(curve)
def modelcopy(obj: models.Model): n = obj.__class__() for f in obj._meta.fields: val = getattr(obj, f.name) if isinstance(val, models.Model): setattr(n, f.name, copy.copy(val)) else: setattr(n, f.name, copy.deepcopy(val)) return n
def save(self, *args, **kwargs): """Overwrites Model.save(). We have to be very careful to never overwrite a request, so often the request must be read from the database prior to saving. The safe parameter being set to True enables this behavior. """ if kwargs.pop('safe', False): self.request = type(self).objects.get(id=self.id).request return Model.save(self, *args, **kwargs)
def remove_stale_pages(self, stale_cts): """ See if there are items that point to a removed model. """ stale_ct_ids = list(stale_cts.keys()) pages = (UrlNode.objects .non_polymorphic() # very important, or polymorphic skips them on fetching derived data .filter(polymorphic_ctype__in=stale_ct_ids) .order_by('polymorphic_ctype', 'pk') ) if not pages: self.stdout.write("No stale pages found.") return if self.dry_run: self.stdout.write("The following pages are stale:") else: self.stdout.write("The following pages were stale:") removed_pages = 0 for page in pages: ct = stale_cts[page.polymorphic_ctype_id] self.stdout.write("- #{id} points to removed {app_label}.{model}".format( id=page.pk, app_label=ct.app_label, model=ct.model )) if not self.dry_run: try: page.delete() removed_pages += 1 except PageTypeNotFound: Model.delete(page) if removed_pages: self.stdout.write("Note, when the removed pages contain content items, " "also call `manage.py remove_stale_contentitems --remove-unreferenced")
def delete(self, no_mptt=False, *args, **kwargs): if no_mptt: Model.delete(self, *args, **kwargs) else: super(CMSPlugin, self).delete(*args, **kwargs)
def filter_descendants(self, category: models.Model) -> models.QuerySet: return self.filter(category__in=category.get_descendants(True))
def __init__(self, *args, **kwargs): Model.__init__(self, *args, **kwargs) self.flag = Event() self.heart = Thread(target=self.heart_run) self.heart.daemon = True self.heart.flag = Event()
def __init__(self, *args, **kwargs): Model.__init__(self, *args, **kwargs) assert self.parent.job == self.child.job
def handle_noargs(self, **options): from django.db.models import Model for model in Model.__subclasses__(): print model.__name__, model.objects.count() print >> sys.stderr, "error: %s %d" % \ (model.__name__, model.objects.count())
def _django_save(self, *args, **kwargs): return Model.save(self, *args, **kwargs)
More info: * "Why doesn't django's model.save() call full clean?" http://stackoverflow.com/questions/4441539/ * "Model docs imply that ModelForm will call Model.full_clean(), but it won't." https://code.djangoproject.com/ticket/13100 """ try: self.full_clean() self.save(*args, **kwargs) return True except ValidationError: e = sys.exc_info()[1] self._errors = {} for k, v in e.message_dict.items(): self._errors[k] = v if throw_exception: raise return False Model.add_to_class('_errors', {}) Model.add_to_class(SMART_SAVE_METHOD, save_if_valid)