mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-04-09 09:58:20 -05:00
Rework how slugs are generated/referenced #393
This commit is contained in:
parent
c7f4bfe4f3
commit
5c3cb1e4ab
@ -9,13 +9,32 @@ Changelog
|
|||||||
its location in ``PAPERLESS_OPTIPNG_BINARY``. The Docker image has already
|
its location in ``PAPERLESS_OPTIPNG_BINARY``. The Docker image has already
|
||||||
been updated on the Docker Hub, so you just need to pull the latest one from
|
been updated on the Docker Hub, so you just need to pull the latest one from
|
||||||
there if you're a Docker user.
|
there if you're a Docker user.
|
||||||
|
|
||||||
|
* A problem in how we handle slug values on Tags and Correspondents required a
|
||||||
|
few changes to how we handle this field `#393`_:
|
||||||
|
|
||||||
|
1. Slugs are no longer editable. They're derived from the name of the tag or
|
||||||
|
correspondent at save time, so if you wanna change the slug, you have to
|
||||||
|
change the name, and even then you're restricted to the rules of the
|
||||||
|
``slugify()`` function. The slug value is still visible in the admin
|
||||||
|
though.
|
||||||
|
2. I've added a migration to go over all existing tags & correspondents and
|
||||||
|
rewrite the ``.slug`` values to ones conforming to the ``slugify()``
|
||||||
|
rules.
|
||||||
|
3. The consumption process now uses the same rules as ``.save()`` in
|
||||||
|
determining a slug and using that to check for an existing
|
||||||
|
tag/correspondent.
|
||||||
|
|
||||||
* An annoying bug in the date capture code was causing some bogus dates to be
|
* An annoying bug in the date capture code was causing some bogus dates to be
|
||||||
attached to documents, which in turn busted the UI. Thanks to `Andrew Peng`_
|
attached to documents, which in turn busted the UI. Thanks to `Andrew Peng`_
|
||||||
for reporting this. `#414`_.
|
for reporting this. `#414`_.
|
||||||
|
|
||||||
* A bug in the Dockerfile meant that Tesseract language files weren't being
|
* A bug in the Dockerfile meant that Tesseract language files weren't being
|
||||||
installed correctly. `euri10`_ was quick to provide a fix: `#406`_, `#413`_.
|
installed correctly. `euri10`_ was quick to provide a fix: `#406`_, `#413`_.
|
||||||
|
|
||||||
* Document consumption is now wrapped in a transaction as per an old ticket
|
* Document consumption is now wrapped in a transaction as per an old ticket
|
||||||
`#262`_.
|
`#262`_.
|
||||||
|
|
||||||
* The ``get_date()`` functionality of the parsers has been consolidated onto
|
* The ``get_date()`` functionality of the parsers has been consolidated onto
|
||||||
the ``DocumentParser`` class since much of that code was redundant anyway.
|
the ``DocumentParser`` class since much of that code was redundant anyway.
|
||||||
|
|
||||||
@ -627,6 +646,7 @@ bulk of the work on this big change.
|
|||||||
.. _#391: https://github.com/danielquinn/paperless/pull/391
|
.. _#391: https://github.com/danielquinn/paperless/pull/391
|
||||||
.. _#390: https://github.com/danielquinn/paperless/pull/390
|
.. _#390: https://github.com/danielquinn/paperless/pull/390
|
||||||
.. _#392: https://github.com/danielquinn/paperless/issues/392
|
.. _#392: https://github.com/danielquinn/paperless/issues/392
|
||||||
|
.. _#393: https://github.com/danielquinn/paperless/issues/393
|
||||||
.. _#395: https://github.com/danielquinn/paperless/pull/395
|
.. _#395: https://github.com/danielquinn/paperless/pull/395
|
||||||
.. _#396: https://github.com/danielquinn/paperless/pull/396
|
.. _#396: https://github.com/danielquinn/paperless/pull/396
|
||||||
.. _#399: https://github.com/danielquinn/paperless/pull/399
|
.. _#399: https://github.com/danielquinn/paperless/pull/399
|
||||||
|
@ -125,6 +125,8 @@ class CorrespondentAdmin(CommonAdmin):
|
|||||||
list_filter = ("matching_algorithm",)
|
list_filter = ("matching_algorithm",)
|
||||||
list_editable = ("match", "matching_algorithm")
|
list_editable = ("match", "matching_algorithm")
|
||||||
|
|
||||||
|
readonly_fields = ("slug",)
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super(CorrespondentAdmin, self).get_queryset(request)
|
qs = super(CorrespondentAdmin, self).get_queryset(request)
|
||||||
qs = qs.annotate(
|
qs = qs.annotate(
|
||||||
@ -149,6 +151,8 @@ class TagAdmin(CommonAdmin):
|
|||||||
list_filter = ("colour", "matching_algorithm")
|
list_filter = ("colour", "matching_algorithm")
|
||||||
list_editable = ("colour", "match", "matching_algorithm")
|
list_editable = ("colour", "match", "matching_algorithm")
|
||||||
|
|
||||||
|
readonly_fields = ("slug",)
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super(TagAdmin, self).get_queryset(request)
|
qs = super(TagAdmin, self).get_queryset(request)
|
||||||
qs = qs.annotate(document_count=models.Count("documents"))
|
qs = qs.annotate(document_count=models.Count("documents"))
|
||||||
|
52
src/documents/migrations/0022_auto_20181007_1420.py
Normal file
52
src/documents/migrations/0022_auto_20181007_1420.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Generated by Django 2.0.8 on 2018-10-07 14:20
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
from django.utils.text import slugify
|
||||||
|
|
||||||
|
|
||||||
|
def re_slug_all_the_things(apps, schema_editor):
|
||||||
|
"""
|
||||||
|
Rewrite all slug values to make sure they're actually slugs before we brand
|
||||||
|
them as uneditable.
|
||||||
|
"""
|
||||||
|
|
||||||
|
Tag = apps.get_model("documents", "Tag")
|
||||||
|
Correspondent = apps.get_model("documents", "Tag")
|
||||||
|
|
||||||
|
for klass in (Tag, Correspondent):
|
||||||
|
for instance in klass.objects.all():
|
||||||
|
klass.objects.filter(
|
||||||
|
pk=instance.pk
|
||||||
|
).update(
|
||||||
|
slug=slugify(instance.slug)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('documents', '0021_document_storage_type'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='tag',
|
||||||
|
options={'ordering': ('name',)},
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='correspondent',
|
||||||
|
name='slug',
|
||||||
|
field=models.SlugField(blank=True, editable=False),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='document',
|
||||||
|
name='file_type',
|
||||||
|
field=models.CharField(choices=[('pdf', 'PDF'), ('png', 'PNG'), ('jpg', 'JPG'), ('gif', 'GIF'), ('tiff', 'TIFF'), ('txt', 'TXT'), ('csv', 'CSV'), ('md', 'MD')], editable=False, max_length=4),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='tag',
|
||||||
|
name='slug',
|
||||||
|
field=models.SlugField(blank=True, editable=False),
|
||||||
|
),
|
||||||
|
migrations.RunPython(re_slug_all_the_things, migrations.RunPython.noop)
|
||||||
|
]
|
@ -11,6 +11,7 @@ from django.conf import settings
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.template.defaultfilters import slugify
|
from django.template.defaultfilters import slugify
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.utils.text import slugify
|
||||||
from fuzzywuzzy import fuzz
|
from fuzzywuzzy import fuzz
|
||||||
|
|
||||||
from .managers import LogManager
|
from .managers import LogManager
|
||||||
@ -37,7 +38,7 @@ class MatchingModel(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
name = models.CharField(max_length=128, unique=True)
|
name = models.CharField(max_length=128, unique=True)
|
||||||
slug = models.SlugField(blank=True)
|
slug = models.SlugField(blank=True, editable=False)
|
||||||
|
|
||||||
match = models.CharField(max_length=256, blank=True)
|
match = models.CharField(max_length=256, blank=True)
|
||||||
matching_algorithm = models.PositiveIntegerField(
|
matching_algorithm = models.PositiveIntegerField(
|
||||||
@ -147,9 +148,7 @@ class MatchingModel(models.Model):
|
|||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
|
|
||||||
self.match = self.match.lower()
|
self.match = self.match.lower()
|
||||||
|
self.slug = slugify(self.name)
|
||||||
if not self.slug:
|
|
||||||
self.slug = slugify(self.name)
|
|
||||||
|
|
||||||
models.Model.save(self, *args, **kwargs)
|
models.Model.save(self, *args, **kwargs)
|
||||||
|
|
||||||
@ -452,7 +451,7 @@ class FileInfo:
|
|||||||
r = []
|
r = []
|
||||||
for t in tags.split(","):
|
for t in tags.split(","):
|
||||||
r.append(Tag.objects.get_or_create(
|
r.append(Tag.objects.get_or_create(
|
||||||
slug=t.lower(),
|
slug=slugify(t),
|
||||||
defaults={"name": t}
|
defaults={"name": t}
|
||||||
)[0])
|
)[0])
|
||||||
return tuple(r)
|
return tuple(r)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user