From 347986a2b3d781ea5dad617cea762c0c483536ea Mon Sep 17 00:00:00 2001 From: Daniel Quinn Date: Sat, 15 Jul 2017 19:06:52 +0100 Subject: [PATCH] Allow correspondents to be deleted without deleting their documents Fixes #235 --- docs/changelog.rst | 7 ++++- requirements.txt | 1 + .../migrations/0018_auto_20170715_1712.py | 21 +++++++++++++ src/documents/models.py | 7 ++++- src/documents/tests/factories.py | 17 ++++++++++ src/documents/tests/test_models.py | 31 +++++++++++++++++++ 6 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 src/documents/migrations/0018_auto_20170715_1712.py create mode 100644 src/documents/tests/factories.py create mode 100644 src/documents/tests/test_models.py diff --git a/docs/changelog.rst b/docs/changelog.rst index a15c92f31..64518c80e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,6 +2,11 @@ Changelog ######### * 0.7.0 + * **Potentially breaking change**: As per `#235`_, Paperless will no longer + automatically delete documents attached to correspondents when those + correspondents are themselves deleted. This was Django's default + behaviour, but didn't make much sense in Paperless' case. Thanks to + `Thomas Brueggemann`_ and `David Martin`_ for their input on this one. * Fix for `#232`_ wherein Paperless wasn't recognising ``.tif`` files properly. Thanks to `ayounggun`_ for reporting this one and to `Kusti Skytén`_ for posting the correct solution in the Github issue. @@ -264,5 +269,5 @@ Changelog .. _#229: https://github.com/danielquinn/paperless/pull/229 .. _#230: https://github.com/danielquinn/paperless/pull/230 .. _#232: https://github.com/danielquinn/paperless/issues/232 +.. _#235: https://github.com/danielquinn/paperless/issues/235 .. _#236: https://github.com/danielquinn/paperless/issues/236 - diff --git a/requirements.txt b/requirements.txt index bb545e961..5d3faa924 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,6 +16,7 @@ pytz>=2016.10 gunicorn==19.6.0 # For the tests +factory-boy pytest pytest-django pytest-sugar diff --git a/src/documents/migrations/0018_auto_20170715_1712.py b/src/documents/migrations/0018_auto_20170715_1712.py new file mode 100644 index 000000000..58d1e9fe8 --- /dev/null +++ b/src/documents/migrations/0018_auto_20170715_1712.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-07-15 17:12 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('documents', '0017_auto_20170512_0507'), + ] + + operations = [ + migrations.AlterField( + model_name='document', + name='correspondent', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='documents', to='documents.Correspondent'), + ), + ] diff --git a/src/documents/models.py b/src/documents/models.py index b064b3d92..2fa2dca0b 100644 --- a/src/documents/models.py +++ b/src/documents/models.py @@ -172,7 +172,12 @@ class Document(models.Model): TYPES = (TYPE_PDF, TYPE_PNG, TYPE_JPG, TYPE_GIF, TYPE_TIF,) correspondent = models.ForeignKey( - Correspondent, blank=True, null=True, related_name="documents") + Correspondent, + blank=True, + null=True, + related_name="documents", + on_delete=models.SET_NULL + ) title = models.CharField(max_length=128, blank=True, db_index=True) diff --git a/src/documents/tests/factories.py b/src/documents/tests/factories.py new file mode 100644 index 000000000..8ed747b83 --- /dev/null +++ b/src/documents/tests/factories.py @@ -0,0 +1,17 @@ +import factory + +from ..models import Document, Correspondent + + +class CorrespondentFactory(factory.DjangoModelFactory): + + class Meta: + model = Correspondent + + name = factory.Faker("name") + + +class DocumentFactory(factory.DjangoModelFactory): + + class Meta: + model = Document diff --git a/src/documents/tests/test_models.py b/src/documents/tests/test_models.py new file mode 100644 index 000000000..606403ec1 --- /dev/null +++ b/src/documents/tests/test_models.py @@ -0,0 +1,31 @@ +from django.test import TestCase + +from ..models import Document, Correspondent +from .factories import DocumentFactory, CorrespondentFactory + + +class CorrespondentTestCase(TestCase): + + def test___str__(self): + for s in ("test", "οχι", "test with fun_charÅc'\"terß"): + correspondent = CorrespondentFactory.create(name=s) + self.assertEqual(str(correspondent), s) + + +class DocumentTestCase(TestCase): + + def test_correspondent_deletion_does_not_cascade(self): + + self.assertEqual(Correspondent.objects.all().count(), 0) + correspondent = CorrespondentFactory.create() + self.assertEqual(Correspondent.objects.all().count(), 1) + + self.assertEqual(Document.objects.all().count(), 0) + DocumentFactory.create(correspondent=correspondent) + self.assertEqual(Document.objects.all().count(), 1) + self.assertIsNotNone(Document.objects.all().first().correspondent) + + correspondent.delete() + self.assertEqual(Correspondent.objects.all().count(), 0) + self.assertEqual(Document.objects.all().count(), 1) + self.assertIsNone(Document.objects.all().first().correspondent)