- Em Desenvolvimento!
- Ainda não disponível no PyPi
Django Smart SoftDeletion é um package para implementação de Soft Deletion em projetos desenvolvidos com Django Web Framework.
Caso queira testar os conceitos deste trabalho em seu projeto, faça:
- Copie a app smart_soft_deletion para o diretório de apps de seu projeto;
- Adicione 'smart_soft_deletion ao
INSTALLED_APPS
:
INSTALLED_APPS = [
# ...
'smart_soft_deletion.apps.SmartSoftDeletionConfig',
]
Para que um model class implemente soft deletion, basta que o mesmo herde de smart_soft_deletion.models.SoftDeletionMixin
O exemplo abaixo implementa quatro classes. Todas herdeiras de SoftDeletionMixin
:
- Country
- Founder
- Industry - Possui ForeignKey para Contry e Possui ManyToMany para Founder
- Product - Possui ForeignKey para Industry
# models.py
from django.db import models
from smart_soft_deletion.models import SoftDeletionMixin
class Country(SoftDeletionMixin):
name = models.CharField(max_length=64, unique=True, verbose_name="Name")
def __str__(self):
return "{}".format(self.name)
class Founder(SoftDeletionMixin):
name = models.CharField(max_length=128, unique=True, verbose_name="Name")
def __str__(self):
return "{}".format(self.name)
class Industry(SoftDeletionMixin):
name = models.CharField(max_length=128, unique=True, verbose_name="Name")
country = models.ForeignKey(Country, null=True, on_delete=models.SET_NULL, verbose_name="Country")
founders = models.ManyToManyField(Founder, verbose_name="Founders")
def __str__(self):
return "{}".format(self.name)
class Product(SoftDeletionMixin):
name = models.CharField(max_length=128, unique=True, verbose_name="Name")
industry = models.ForeignKey(Industry, on_delete=models.CASCADE, verbose_name="Industry")
def __str__(self):
return "{}".format(self.name)
Criando objetos
# import Contry, Founder, Industry, Product
# create country
usa = Country.objects.create(name="USA")
japan = Country.objects.create(name="Japan")
# create founder
bill_gates = Founder.objects.create(name="Bill Gates")
paul_allen = Founder.objects.create(name="Paul Allen")
akio_morita = Founder.objects.create(name="Akio Morita")
# create industry
microsoft = Industry.objects.create(name="Microsoft", country=usa)
sony = Industry.objects.create(name="Sony", country=japan)
microsoft.founders.add(bill_gates)
microsoft.founders.add(paul_allen)
sony.founders.add(akio_morita)
# create product
xbox = Product.objects.create(name="Xbox", industry=microsoft)
play_station = Product.objects.create(name="Play Station", industry=sony)
# continua...
Product.objects.all()
# <SoftDeletionQuerySet [<Product: Xbox>, <Product: Play Station>]>
play_station.delete()
Product.objects.all()
# <SoftDeletionQuerySet [<Product: Xbox>]>
Product.objects_with_deleted.all()
# <SoftDeletionQuerySet [<Product: Xbox>, <Product: Play Station>]>
# Isso porque objects_with_deleted manager inclui na queryset os objetos deletados
play_station = Product.objects_with_deleted.get(name='Play Station')
play_station.is_deleted
# True
play_station.restore()
play_station.is_deleted
# False
Product.objects.all()
# <SoftDeletionQuerySet [<Product: Xbox>, <Product: Play Station>]>
# Isso porque o metodo restore recupera o objeto deletado e por consequencia o mesmo volta a aparecer na queryset do manager objects
Deletando um objeto ForeignKey CASCADE.
play_station
tem um ForeignKey CASCADE para microsoft
. No exemplo abaixo o objeto microsoft será deletado e depois restaurado.
# continua...
microsoft.delete()
Product.objects.all()
# <SoftDeletionQuerySet [<Product: Play Station>]>
# xbox foi deletado em cascade junto com microsoft
microsoft.restore()
Product.objects.all()
# <SoftDeletionQuerySet [<Product: Play Station>]>
# xbox não foi restaurado pois objetos deletados em cascade não são restaurados quando seu foreign key é restaurado. Para restaurar xbox faça: xbox.restore(). Veja o item 2 da sessão 'O que ainda falta'
Deletando um objeto ForeignKey SET_NULL.
microsoft
tem um ForeignKey SET_NULL para usa
. No exemplo abaixo o objeto usa será deletado e depois restaurado.
# continua...
microsoft.country
# <Country: USA>
usa.delete()
microsoft.refresh_from_db()
microsoft.is_deleted
# False
#Isso porque objetos com foreign key SET_NULL não são deletados em cascata quando o objeto foreign key é deletado
microsoft.country
# None
# O field foreign key recebe valor None quando o objeto foreign key é deletado
usa.restore()
microsoft.refresh_from_db()
microsoft.country
# O field microsoft.country não recupera a relação com o foreign key restaurado. Veja o item 3 da sessão 'O que ainda falta'
Deletando um objeto ForeignKey ManyToMany.
# continua
microsoft.founders.all()
# Veja ítem 4 de 'O que ainda falta'
paul_allen.delete()
microsoft.founders.all()
# Veja ítem 4 de 'O que ainda falta'
paul_allen.restore()
microsoft.founders.all()
# Veja ítem 4 de 'O que ainda falta'
Para fazer um hard deletion, acrescente o parametro hard_deletion=True
no método delete()
. Exemplo:
# continua
usa.delete(hard_deletion=True)
- Implementar comportamento para
on_delete=models.SET
- Implementar restore de objetos que foram deletado em cascade qndo seu foreign key for restaurado. Esta funcionalide deve poupar os objetos que não foram deletados via CASCADE;
- Implementar restauração da ligação foreign key com fields SET_NULL quando o objeto foreign key for restaurado. Esta funcionalidade de poupar objetos que não perderam a ligação por ocasião de um delete do foreignkey;
- Evitar que um objeto com ManyToMany ao ser deletado perca a relação com os objetos foreign keys;