def delete(self, force=False): """ Deletes the records in the current QuerySet. """ assert self.query.can_filter(), \ "Cannot use 'limit' or 'offset' with delete." del_query = self._clone() # The delete is actually 2 queries - one to find related objects, # and one to delete. Make sure that the discovery of related # objects is performed on the same database as the deletion. del_query._for_write = True # Disable non-supported fields. del_query.query.select_for_update = False del_query.query.select_related = False del_query.query.clear_ordering(force_empty=True) collector = Collector(using=del_query.db) collector.collect(del_query) collector.delete(force=force) # Clear the result cache, in case this QuerySet gets reused. self._result_cache = None
def delete(self, using=None): using = using or router.db_for_write(self.__class__, instance=self) assert self._get_pk_val( ) is not None, "%s object can't be deleted because its %s attribute is set to None." % ( self._meta.object_name, self._meta.pk.attname) # Find all the objects than need to be deleted. collector = Collector(using=using) collector.collect([self]) #hack to prevent ORM delet object via sql #it does not use QuerySet - directly sql module :( to_delete = {} for k in collector.data.keys()[:]: if issubclass(k, MongoModel): to_delete.update({k: collector.data.pop(k)}) for key, object_set in to_delete.items(): for obj in object_set: cls = obj.__class__ if not cls._meta.auto_created: models.signals.pre_delete.send(sender=cls, instance=obj) cls._default_manager.filter(pk=obj.pk).delete() if not cls._meta.auto_created: models.signals.post_delete.send(sender=cls, instance=obj) # Delete other objects. collector.delete()
def delete_related(self, affected=None, using=None): """ Стандартное каскадное удаление объектов в django, дополненное проверкой на удаляемые классы моделей affected. По умолчанию affected содержит пустой список - это ограничивает удаляемые модели только текущим классом. К перечисленным в affected классам текущий добавляется автоматически. Если удаление не удалось выполнить, возвращает False, иначе True. Пример: Model1.objects.get(id=1).delete_related(affected=[Model2, Model3]) """ # Кописаст из django.db.models.Model delete() using = using or router.db_for_write(self.__class__, instance=self) assert self._get_pk_val() is not None, ( "%s object can't be deleted because its " "%s attribute is set to None.") % (self._meta.object_name, self._meta.pk.attname) collector = Collector(using=using) collector.collect([self]) # cut affected = affected or [] assert isinstance(affected, list), ('Affected models must be the list type') affected.append(self.__class__) for model in collector.data.keys(): if model not in affected: return False collector.delete() return True
def revert(self, delete=False): # Group the models by the database of the serialized model. versions_by_db = defaultdict(list) for version in self.version_set.iterator(): versions_by_db[version.db].append(version) # For each db, perform a separate atomic revert. for version_db, versions in versions_by_db.items(): with transaction.atomic(using=version_db): # Optionally delete objects no longer in the current revision. if delete: # Get a set of all objects in this revision. old_revision = set() for version in versions: model = version._model try: # Load the model instance from the same DB as it was saved under. old_revision.add(model._default_manager.using(version.db).get(pk=version.object_id)) except model.DoesNotExist: pass # Calculate the set of all objects that are in the revision now. current_revision = chain.from_iterable( _follow_relations_recursive(obj) for obj in old_revision ) # Delete objects that are no longer in the current revision. collector = Collector(using=version_db) new_objs = [item for item in current_revision if item not in old_revision] for model, group in groupby(new_objs, type): collector.collect(list(group)) collector.delete() # Attempt to revert all revisions. _safe_revert(versions)
def delete(self, using=None): """Surcharge de la methode save pour supprimer le fichier source avant l objet """ using = using or router.db_for_write(self.__class__, instance=self) assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % ( self._meta.object_name, self._meta.pk.attname, ) if self.source_file: tab_path = self.source_file.name.split("/") # decoupage du chemin vers le fichier source rep_path = os.path.join( os.path.join(settings.VIDEO_ROOT, tab_path[1]).replace("\\", "/") ) # recomposition du chemin du repertoire du fichier source self.source_file.delete() # suppression du fichier source if len(os.listdir(rep_path)) == 0: # si le repertoire du fichier source est vide try: os.rmdir(rep_path) # suppression du repertoire except: pass # Si un probleme survient on ne fait rien collector = Collector(using=using) collector.collect([self]) collector.delete()
def delete(self, using=None): # FIXME: if the Translation is the one used as default/fallback, # then deleting it will mean the corresponding field on the related # model will stay empty even if there are translations in other # languages! cls = self.__class__ using = using or router.db_for_write(cls, instance=self) # Look for all translations for the same string (id=self.id) except the # current one (autoid=self.autoid). qs = cls.objects.filter(id=self.id).exclude(autoid=self.autoid) if qs.using(using).exists(): # If other Translations for the same id exist, we just need to # delete this one and *only* this one, without letting Django # collect dependencies (it'd remove the others, which we want to # keep). assert self._get_pk_val() is not None collector = Collector(using=using) collector.collect([self], collect_related=False) # In addition, because we have FK pointing to a non-unique column, # we need to force MySQL to ignore constraints because it's dumb # and would otherwise complain even if there are remaining rows # that matches the FK. with connections[using].constraint_checks_disabled(): collector.delete() else: # If no other Translations with that id exist, then we should let # django behave normally. It should find the related model and set # the FKs to NULL. return super(Translation, self).delete(using=using)
def delete(self, using=None): using = using or router.db_for_write(self.__class__, instance=self) assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname) collector = Collector(using=using) collector.collect([self]) collector.delete()
def delete(self, using=None): using = using or router.db_for_write(self.__class__, instance=self) assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % ( self._meta.object_name, self._meta.pk.attname, ) # Find all the objects than need to be deleted. collector = Collector(using=using) collector.collect([self]) # hack to prevent ORM delet object via sql # it does not use QuerySet - directly sql module :( to_delete = {} for k in collector.data.keys()[:]: if issubclass(k, MongoModel): to_delete.update({k: collector.data.pop(k)}) for key, object_set in to_delete.items(): for obj in object_set: cls = obj.__class__ if not cls._meta.auto_created: models.signals.pre_delete.send(sender=cls, instance=obj) cls._default_manager.filter(pk=obj.pk).delete() if not cls._meta.auto_created: models.signals.post_delete.send(sender=cls, instance=obj) # Delete other objects. collector.delete()
def delete(self): """ Deletes the records in the current QuerySet. """ assert self.query.can_filter(), \ "Cannot use 'limit' or 'offset' with delete." # NB: this line is patched to work with SkinnyQuerySet # see https://gist.github.com/550438#file-gistfile2-txt del_query = self._clone(klass=QuerySet) # The delete is actually 2 queries - one to find related objects, # and one to delete. Make sure that the discovery of related # objects is performed on the same database as the deletion. del_query._for_write = True # Disable non-supported fields. del_query.query.select_for_update = False del_query.query.select_related = False del_query.query.clear_ordering(force_empty=True) collector = Collector(using=del_query.db) collector.collect(del_query) collector.delete() # Clear the result cache, in case this QuerySet gets reused. self._result_cache = None
def handle(self, *args, **options): verbosity = int(options.get("verbosity", "1")) levels = (logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG) if "verbosity" in options: logging.basicConfig(format='%(message)s', level=levels[verbosity]) if options['days'] < 7 and not options['force']: logger.error( 'Delete less than one week not allowed, try using --force') return if options['days'] < 1: logger.error('Delete less than one day not allowed at all') return start_date = timezone.now() - timedelta(days=options['days']) collector = Collector(using=DEFAULT_DB_ALIAS) logger.info("Purge old chat records since {}".format(start_date)) for model in [ChatHistory]: qs = model.objects.filter(created__lt=start_date) logger.info("Delete {} records in {}".format( qs.count(), model._meta.db_table)) collector.collect(qs) collector.delete() logger.info("Done purging old records.")
def delete(self, using=None): if (self.__class__._meta.materialized_view or (self.__class__._meta.intermediate and not self.__class__._meta.concrete)): raise NonPersistantModel('Materialized views and intermediate views can\'t be'\ 'saved or deleted') using = using or router.db_for_write(self.__class__, instance=self) assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname) collector = Collector(using=using) collector.collect([self]) collector.delete()
def delete(self, **kwargs): """ Deletes fields from base model """ assert self._get_pk_val( ) is not None, "Object %s cannot be deleted because %s is null." % ( self._meta.object_name, self._meta.pk.attname) seen_objs = Collector( router.db_for_write(self.__class__, instance=self)) seen_objs.collect([self]) self.can_delete() seen_objs.delete()
def delete(self, *args, **kwargs): """ Replace super(BaseModel, self).delete() Cause: When delete relationship in cascade default no have attribute User to Log. """ using = router.db_for_write(self.__class__, instance=self) assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % ( self._meta.object_name, self._meta.pk.attname) collector = Collector(using=using) collector.collect([self]) collector.delete()
def delete(self, *args, **kwargs): ''' Replace super(BaseModel, self).delete() Cause: When delete relationship in cascade default no have attribute User to Log. ''' using = router.db_for_write(self.__class__, instance=self) assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % ( self._meta.object_name, self._meta.pk.attname) collector = Collector(using=using) collector.collect([self]) collector.delete()
def handle(self, *args, **options): verbosity = int(options.get("verbosity", "1")) levels = (logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG) if "verbosity" in options: logging.basicConfig(format='%(message)s', level=levels[verbosity]) if options['days'] < 7 and not options['force']: logger.error('Delete less than one week not allowed, try using --force') return if options['days'] < 1: logger.error('Delete less than one day not allowed at all') return start_date = timezone.now() - timedelta(days=options['days']) collector = Collector(using=DEFAULT_DB_ALIAS) logger.info("Purge old records since {}".format(start_date)) for model in (NotifySend, TaskReport): qs = model.objects.filter(created__lt=start_date) logger.info("Delete {} records in {}".format(qs.count(), model._meta.db_table)) collector.collect(qs) collector.delete() logger.info("Done purging old records.") if not options['vacuum']: return sql = "VACUUM" if options['full']: sql += " FULL" force_proxy = connection.cursor() realconn = connection.connection old_isolation_level = realconn.isolation_level realconn.set_isolation_level(0) cursor = realconn.cursor() for model in (NotifySend, TaskReport): sql_command = "{} {}".format(sql, model._meta.db_table) logger.info("Run {}".format(sql_command)) cursor.execute(sql_command) realconn.set_isolation_level(old_isolation_level) del force_proxy
def hard_delete(self): """Delete the records in the current QuerySet.""" self._not_support_combined_queries('delete') assert not self.query.is_sliced, \ "Cannot use 'limit' or 'offset' with delete." if self._fields is not None: raise TypeError( "Cannot call delete() after .values() or .values_list()") del_query = self._chain() # The delete is actually 2 queries - one to find related objects, # and one to delete. Make sure that the discovery of related # objects is performed on the same database as the deletion. del_query._for_write = True # Disable non-supported fields. del_query.query.select_for_update = False del_query.query.select_related = False del_query.query.clear_ordering(force_empty=True) collector = Collector(using=del_query.db) collector.collect(del_query) deleted, _rows_count = collector.delete() # Clear the result cache, in case this QuerySet gets reused. self._result_cache = None return deleted, _rows_count
def delete_without_cascade(self, using=None, keep_parents=False): """ Modified version of django's default delete() method. This method is added to enable safe deletion of the child models without removing objects related to it through the parent. As of Feb 2017, no models are directly related to the OAuth2DataRequestProject or OnSiteDataRequestProject child models. """ allowed_models = [ "private_sharing.onsitedatarequestproject", "private_sharing.oauth2datarequestproject", ] if self._meta.label_lower not in allowed_models: raise Exception("'delete_without_cascade' only for child models!") using = using or router.db_for_write(self.__class__, instance=self) assert self._get_pk_val() is not None, ( "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname)) collector = Collector(using=using) collector.collect([self], keep_parents=keep_parents, collect_related=False) return collector.delete()
def soft_delete(self, *args, **kwargs): if len(self.data) > 0: # normal deletes for model, instances in self.data.iteritems(): if issubclass(model, SoftDeletableModel): for instance in instances: instance.is_active = False instance.save() else: collector = Collector(using=None) # use the default db collector.collect(instances) collector.delete() else: # fast deletes for qs in self.fast_deletes: qs.update(is_active=False)
def change_spanish_home_pages_to_home_pages(apps, schema_editor): SpanishHomePage = apps.get_model('v1', 'SpanishHomePage') spanish_home_pages = SpanishHomePage.objects.all() # If there are no SpanishHomePages, nothing to do. if not spanish_home_pages.exists(): return ContentType = apps.get_model('contenttypes', 'ContentType') Page = apps.get_model('wagtailcore', 'Page') PageRevision = apps.get_model('wagtailcore', 'PageRevision') # When running migrations against an empty database, there won't already # be a ContentType for the HomePage model type. But we need one in order to # convert SpanishHomePages to that type. So use get_or_create here to # either use the existing ContentType or create a new one. homepage_content_type, _ = ContentType.objects.get_or_create( app_label='v1', model='homepage') # This is by no means a general solution to the problem of changing a # Wagtail Page's type, but seems to work for this specific situation, where # we meet these requirements: # # - Changing a child page into its immediate parent's page type # - There are no foreign keys from the child page type to other models # - There are no foreign keys from other models to the child page type collector = Collector(using=schema_editor.connection.alias) for page in spanish_home_pages: # This deletes the page's row in the v1_spanishhomepage table without # touching the parent v1_homepage, v1_cfgovpage, or wagtailcore_page # tables. collector.collect([page], keep_parents=True, collect_related=False) collector.delete() # This updates the wagtailcore_page table to set the page's new type. page.content_type = homepage_content_type Page.save(page, update_fields=['content_type']) # Finally fixup existing page revisions so they also have the right # content type. This doesn't affect anything, but is good for # consistency. for revision in PageRevision.objects.filter(page_id=page.pk): content = json.loads(revision.content_json) content['content_type'] = homepage_content_type.pk revision.content_json = json.dumps(content) revision.save(update_fields=['content_json'])
def delete_complete(self, using=None, keep_parents=False): using = using or router.db_for_write(self.__class__, instance=self) assert self._get_pk_val() is not None, ( "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname) ) collector = Collector(using=using) collector.collect([self], keep_parents=keep_parents) return collector.delete()
def delete(self, using=None): """Surcharge de la methode save pour supprimer le fichier source avant l objet """ using = using or router.db_for_write(self.__class__, instance=self) assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % ( self._meta.object_name, self._meta.pk.attname, ) if self.outputdir: try: shutil.rmtree( os.path.join(settings.VIDEO_ROOT, self.outputdir).replace("\\", "/") ) # suppression du repertoire except: pass # Si un probleme survient on ne fait rien collector = Collector(using=using) collector.collect([self]) collector.delete()
def delete(self, using=None, keep_parents=False): using = using or router.db_for_write(self.__class__, instance=self) collector = Collector(using=using) collector.collect([self], keep_parents=keep_parents) if (self.registration_reminder is not None and not self.registration_reminder.sent): collector.add([self.registration_reminder]) if self.start_reminder is not None and not self.start_reminder.sent: collector.add([self.start_reminder]) if self.is_pizza_event(): collector.add([self.pizzaevent]) return collector.delete()
def delete_related(self, affected=None, using=None): """ Стандартное каскадное удаление объектов в django, дополненное проверкой на удаляемые классы моделей affected. По умолчанию affected содержит пустой список - это ограничивает удаляемые модели только текущим классом. К перечисленным в affected классам текущий добавляется автоматически. Если удаление не удалось выполнить, возвращает False, иначе True. Пример: Model1.objects.get(id=1).delete_related(affected=[Model2, Model3]) """ # Кописаст из django.db.models.Model delete() using = using or router.db_for_write(self.__class__, instance=self) assert self._get_pk_val() is not None, ( "%s object can't be deleted because its " "%s attribute is set to None." ) % ( self._meta.object_name, self._meta.pk.attname ) collector = Collector(using=using) collector.collect([self]) # cut affected = affected or [] assert isinstance(affected, list), ( 'Affected models must be the list type') affected.append(self.__class__) for model in collector.data.keys(): if model not in affected: return False collector.delete() return True
def delete(self, using=None, keep_parents=False, hard_delete=False, *args, **kwargs): using = using or router.db_for_write(self.__class__, instance=self) assert self._get_pk_val() is not None, ( "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname) ) collector = Collector(using=using) collector.collect([self], keep_parents=keep_parents) with transaction.atomic(): if hard_delete: # set hard deletion for all related models for model, instances in six.iteritems(collector.data): if issubclass(model, SyncableModel) or issubclass(model, MorangoMPTTModel): for obj in instances: obj._update_hard_deleted_models() return collector.delete()
def delete(self, using=None, keep_parents=False): using = using or router.db_for_write(self.__class__, instance=self) assert self.pk is not None, ( "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname)) collector = Collector(using=using) # Change S # MEMO: Collector doesn't support method to change its base query. # Therefore, I changed param '[self]' to CPkQuerySet object. # #collector.collect([self], keep_parents=keep_parents) model = self._meta.model qs = model.objects.filter(pk=self.pk) collector.collect(qs, keep_parents=keep_parents) # Change E return collector.delete()
def delete(self, using=None, keep_parents=False, use_protection=False): """ delete the object Parameters: using: str, optional keep_parents: bool, optional(default=False) use_protection: bool, optional(default=False) if True, raise a ProtectedError when trying to delete related objects if on_delete=PROTECT_CASCADE if False, delete objects cascaded """ using = using or router.db_for_write(self.__class__, instance=self) assert self.pk is not None, ( "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname)) collector = Collector(using=using) collector.use_protection = use_protection collector.collect([self], keep_parents=keep_parents) return collector.delete()
def delete_without_cascade(self, using=None, keep_parents=False): """ Modified version of django's default delete() method. This method is added to enable safe deletion of the child models without removing objects related to it through the parent. As of Feb 2017, no models are directly related to the OAuth2DataRequestProject or OnSiteDataRequestProject child models. """ allowed_models = [ "private_sharing.onsitedatarequestproject", "private_sharing.oauth2datarequestproject", ] if self._meta.label_lower not in allowed_models: raise Exception("'delete_without_cascade' only for child models!") using = using or router.db_for_write(self.__class__, instance=self) assert self._get_pk_val() is not None, ( "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname) ) collector = Collector(using=using) collector.collect([self], keep_parents=keep_parents, collect_related=False) return collector.delete()
def save(self, *args, **kwargs): delete_collector = Collector( using=router.db_for_write(self.__class__, instance=self)) if not self.pk: super().save(*args, **kwargs) if self.published: if self.registration_required: registration_reminder_time = (self.registration_start - timezone.timedelta(hours=1)) registration_reminder = ScheduledMessage() if (self.registration_reminder is not None and not self.registration_reminder.sent): registration_reminder = self.registration_reminder if registration_reminder_time > timezone.now(): registration_reminder.title_en = "Event registration" registration_reminder.title_nl = "Evenement registratie" registration_reminder.body_en = ("Registration for '{}' " "starts in 1 hour".format( self.title_en)) registration_reminder.body_nl = ("Registratie voor '{}' " "start in 1 uur".format( self.title_nl)) registration_reminder.category = Category.objects.get( key=Category.EVENT) registration_reminder.time = registration_reminder_time registration_reminder.url = ( f"{settings.BASE_URL}" f'{reverse("events:event", args=[self.id])}') registration_reminder.save() self.registration_reminder = registration_reminder self.registration_reminder.users.set( Member.current_members.all()) elif registration_reminder.pk is not None: delete_collector.add([self.registration_reminder]) self.registration_reminder = None start_reminder_time = self.start - timezone.timedelta(hours=1) start_reminder = ScheduledMessage() if self.start_reminder is not None and not self.start_reminder.sent: start_reminder = self.start_reminder if start_reminder_time > timezone.now(): start_reminder.title_en = "Event" start_reminder.title_nl = "Evenement" start_reminder.body_en = f"'{self.title_en}' starts in " "1 hour" start_reminder.body_nl = f"'{self.title_nl}' begint over " "1 uur" start_reminder.category = Category.objects.get( key=Category.EVENT) start_reminder.time = start_reminder_time start_reminder.save() self.start_reminder = start_reminder if self.registration_required: self.start_reminder.users.set( [r.member for r in self.participants if r.member]) else: self.start_reminder.users.set(Member.current_members.all()) elif start_reminder.pk is not None: delete_collector.add([self.start_reminder]) self.start_reminder = None else: if (self.registration_reminder is not None and not self.registration_reminder.sent): delete_collector.add([self.registration_reminder]) self.registration_reminder = None if self.start_reminder is not None and not self.start_reminder.sent: delete_collector.add([self.start_reminder]) self.start_reminder = None super().save() delete_collector.delete()
def delete(self): print("deleting ...") # debug count = self.count() for instance in self: print("get instance ...") # debug print(instance) instance_db = instance._state.db self_pk = instance.pk db = Databases.objects.get_data_by_full_name(instance._state.db) db.count = db.count - 1 db.save() if instance.__class__.forward_models is not None: print("forward_fields", instance.__class__.forward_fields) # debug print("forward_models", instance.__class__.forward_models) # debug frd_pks = {} for forward_model in instance.__class__.forward_models: attrname = instance.__class__.forward_fields[forward_model._meta.model_name] frd_pks[getattr(instance, attrname + '_id')] = forward_model # 1- delete instance from its used database super(ShardUserModelQueryset,self).delete() # 2- same instance from related database: # forward_model ---> this instance if instance.__class__.forward_models is not None: for frd_pk in frd_pks: forward_model = frd_pks[frd_pk] print("forward model:", frd_pk, forward_model) # debug ct_model = ContentType.objects.get(model=forward_model._meta.model_name).model_class() ct_model_obj = ct_model.objects.filter(pk= frd_pk) print("forward obj:", ct_model_obj) # debug # do not delete forward_model instance if exist in its specific database if ct_model_obj.count() == 0: qs = models.QuerySet(forward_model, using=str(instance_db)).filter(pk= frd_pk) print(qs) collector = Collector(using=instance_db) collector.collect(qs) deleted, _rows_count = collector.delete() # 3- delete related model instance # related_model ---> instance related to this model if instance.__class__.related_models is not None: print("get query set ...") # debug print("related models", instance.__class__.related_models) # debug for related_model in instance.related_models: print("related fields", instance.related_fields[related_model._meta.model_name]) # debug # get related database db_list = Databases.objects.all().filter(model_name=related_model._meta.model_name).exclude(count=0) # if exist if db_list.count() != 0: for db in db_list: #try: filters = {} filters[instance.related_fields[related_model._meta.model_name]] = instance qs1 = models.QuerySet(related_model, using=str(db)).filter(**filters) # on delete cascad delete related instances if self.model.on_delete[related_model._meta.model_name].__name__ == "CASCADE": collector = Collector(using=qs1.db) collector.collect(qs1) deleted, _rows_count = collector.delete() if qs1.count() == 0: # if related instance dosn't exist # delete this model instance in other model databases print("self_pk ", self_pk) qs2 = models.QuerySet(self.model, using=str(qs1.db)).filter(pk= self_pk) print('qs2', qs2) collector = Collector(using=qs1.db) collector.collect(qs2) deleted, _rows_count = collector.delete()
def delete(self): print("deleting ...") count = self.count() for instance in self: print("get instance ...") #debug print(instance) #debug db = Databases.objects.get_data_by_full_name(instance._state.db) instance_db = instance._state.db self_pk = instance.pk db.count = db.count - 1 db.save() if instance.__class__.forward_models is not None: print("forward_fields", instance.__class__.forward_fields) # debug print("forward_models", instance.__class__.forward_models) # debug frd_pks = {} for forward_model in instance.__class__.forward_models: attrname = instance.__class__.forward_fields[forward_model._meta.model_name] frd_pks[getattr(instance, attrname + '_id')] = forward_model # 1- delete instance from its used database super(ShardModelQueryset,self).delete() # 2- same instance from related database: if instance.__class__.forward_models is not None: for frd_pk in frd_pks: forward_model = frd_pks[frd_pk] print(frd_pk, forward_model) ct_model = ContentType.objects.get(model=forward_model._meta.model_name).model_class() ct_model_obj = ct_model.objects.filter(pk= frd_pk) print(ct_model_obj) # do not delete forward_model instance if exist in his specific database if ct_model_obj.count() == 0: qs = models.QuerySet(forward_model, using=str(instance_db)).filter(pk= frd_pk) print(qs) collector = Collector(using=instance_db) collector.collect(qs) deleted, _rows_count = collector.delete() # 3- delete related model instance from its database: # related_models: mean models where use this model in # this mean when delete this model instance will delete # also in other model databases if instance.__class__.related_models is not None: print("get query set ...") print(instance.__class__.related_models) for related_model in instance.related_models: print(instance.related_fields) db_list = Databases.objects.all().filter(model_name=related_model._meta.model_name).exclude(count=0) if db_list.count() != 0: for db in db_list: try: # on delete cascad # if self.model.on_delete[related_model._meta.model_name].__name__ == "CASCADE": # filters = {} # # TODO: Change key dynamicly # filters["owner"] = instance # qs1 = models.QuerySet(related_model, using=str(db)).filter(**filters) # collector = Collector(using=qs1.db) # collector.collect(qs1) # deleted, _rows_count = collector.delete() filters = {} filters[instance.related_fields[related_model._meta.model_name]] = instance qs1 = models.QuerySet(related_model, using=str(db)).filter(**filters) # on delete cascad delete related instances if self.model.on_delete[related_model._meta.model_name].__name__ == "CASCADE": collector = Collector(using=qs1.db) collector.collect(qs1) deleted, _rows_count = collector.delete() if qs1.count() == 0: # if related instance dosn't exist # delete this model instance in other model databases print("self_pk ", self_pk) qs2 = models.QuerySet(self.model, using=str(qs1.db)).filter(pk= self_pk) print('qs2', qs2) collector = Collector(using=qs1.db) collector.collect(qs2) deleted, _rows_count = collector.delete() except instance.DoesNotExist: continue