mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	logging: don't group by logging_group
This commit is contained in:
		| @@ -1,11 +1,10 @@ | |||||||
| from django_filters.rest_framework import BooleanFilter, FilterSet | from django_filters.rest_framework import BooleanFilter, FilterSet | ||||||
|  |  | ||||||
| from .models import Correspondent, Document, Tag, DocumentType | from .models import Correspondent, Document, Tag, DocumentType, Log | ||||||
|  |  | ||||||
|  |  | ||||||
| CHAR_KWARGS = ["istartswith", "iendswith", "icontains", "iexact"] | CHAR_KWARGS = ["istartswith", "iendswith", "icontains", "iexact"] | ||||||
| ID_KWARGS = ["in", "exact"] | ID_KWARGS = ["in", "exact"] | ||||||
| INT_KWARGS = ["exact"] | INT_KWARGS = ["exact", "gt", "gte", "lt", "lte"] | ||||||
| DATE_KWARGS = ["year", "month", "day", "date__gt", "gt", "date__lt", "lt"] | DATE_KWARGS = ["year", "month", "day", "date__gt", "gt", "date__lt", "lt"] | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -68,3 +67,16 @@ class DocumentFilterSet(FilterSet): | |||||||
|             "document_type__name": CHAR_KWARGS, |             "document_type__name": CHAR_KWARGS, | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class LogFilterSet(FilterSet): | ||||||
|  |  | ||||||
|  |     class Meta: | ||||||
|  |         model = Log | ||||||
|  |         fields = { | ||||||
|  |  | ||||||
|  |             "level": INT_KWARGS, | ||||||
|  |             "created": DATE_KWARGS, | ||||||
|  |             "group": ID_KWARGS | ||||||
|  |  | ||||||
|  |         } | ||||||
|   | |||||||
| @@ -1,70 +0,0 @@ | |||||||
| from django.conf import settings |  | ||||||
|  |  | ||||||
| from django.db import models |  | ||||||
| from django.db.models.aggregates import Max |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class GroupConcat(models.Aggregate): |  | ||||||
|     """ |  | ||||||
|     Theoretically, this should work in Sqlite, PostgreSQL, and MySQL, but I've |  | ||||||
|     only ever tested it in Sqlite. |  | ||||||
|     """ |  | ||||||
|  |  | ||||||
|     ENGINE_SQLITE = 1 |  | ||||||
|     ENGINE_POSTGRESQL = 2 |  | ||||||
|     ENGINE_MYSQL = 3 |  | ||||||
|     ENGINES = { |  | ||||||
|         "django.db.backends.sqlite3": ENGINE_SQLITE, |  | ||||||
|         "django.db.backends.postgresql_psycopg2": ENGINE_POSTGRESQL, |  | ||||||
|         "django.db.backends.postgresql": ENGINE_POSTGRESQL, |  | ||||||
|         "django.db.backends.mysql": ENGINE_MYSQL |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     def __init__(self, expression, separator="\n", **extra): |  | ||||||
|  |  | ||||||
|         self.engine = self._get_engine() |  | ||||||
|         self.function = self._get_function() |  | ||||||
|         self.template = self._get_template(separator) |  | ||||||
|  |  | ||||||
|         models.Aggregate.__init__( |  | ||||||
|             self, |  | ||||||
|             expression, |  | ||||||
|             output_field=models.CharField(), |  | ||||||
|             **extra |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     def _get_engine(self): |  | ||||||
|         engine = settings.DATABASES["default"]["ENGINE"] |  | ||||||
|         try: |  | ||||||
|             return self.ENGINES[engine] |  | ||||||
|         except KeyError: |  | ||||||
|             raise NotImplementedError( |  | ||||||
|                 "There's currently no support for {} when it comes to group " |  | ||||||
|                 "concatenation in Paperless".format(engine) |  | ||||||
|             ) |  | ||||||
|  |  | ||||||
|     def _get_function(self): |  | ||||||
|         if self.engine == self.ENGINE_POSTGRESQL: |  | ||||||
|             return "STRING_AGG" |  | ||||||
|         return "GROUP_CONCAT" |  | ||||||
|  |  | ||||||
|     def _get_template(self, separator): |  | ||||||
|         if self.engine == self.ENGINE_MYSQL: |  | ||||||
|             return "%(function)s(%(expressions)s SEPARATOR '{}')".format( |  | ||||||
|                 separator) |  | ||||||
|         return "%(function)s(%(expressions)s, '{}')".format(separator) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class LogQuerySet(models.query.QuerySet): |  | ||||||
|  |  | ||||||
|     def by_group(self): |  | ||||||
|         return self.values("group").annotate( |  | ||||||
|             time=Max("modified"), |  | ||||||
|             messages=GroupConcat("message"), |  | ||||||
|         ).order_by("-time") |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class LogManager(models.Manager): |  | ||||||
|  |  | ||||||
|     def get_queryset(self): |  | ||||||
|         return LogQuerySet(self.model, using=self._db) |  | ||||||
							
								
								
									
										26
									
								
								src/documents/migrations/1005_auto_20201102_0007.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/documents/migrations/1005_auto_20201102_0007.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | # Generated by Django 3.1.2 on 2020-11-02 00:07 | ||||||
|  |  | ||||||
|  | from django.db import migrations, models | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  |  | ||||||
|  |     dependencies = [ | ||||||
|  |         ('documents', '1004_auto_20201029_1331'), | ||||||
|  |     ] | ||||||
|  |  | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AlterModelOptions( | ||||||
|  |             name='log', | ||||||
|  |             options={'ordering': ('-created',)}, | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='log', | ||||||
|  |             name='modified', | ||||||
|  |         ), | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='log', | ||||||
|  |             name='group', | ||||||
|  |             field=models.UUIDField(blank=True, null=True), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
| @@ -13,12 +13,6 @@ from django.template.defaultfilters import slugify | |||||||
| from django.utils import timezone | from django.utils import timezone | ||||||
| from django.utils.text import slugify | from django.utils.text import slugify | ||||||
|  |  | ||||||
| from .managers import LogManager |  | ||||||
|  |  | ||||||
| try: |  | ||||||
|     from django.core.urlresolvers import reverse |  | ||||||
| except ImportError: |  | ||||||
|     from django.urls import reverse |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class MatchingModel(models.Model): | class MatchingModel(models.Model): | ||||||
| @@ -263,33 +257,17 @@ class Log(models.Model): | |||||||
|         (logging.CRITICAL, "Critical"), |         (logging.CRITICAL, "Critical"), | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     group = models.UUIDField(blank=True) |     group = models.UUIDField(blank=True, null=True) | ||||||
|     message = models.TextField() |     message = models.TextField() | ||||||
|     level = models.PositiveIntegerField(choices=LEVELS, default=logging.INFO) |     level = models.PositiveIntegerField(choices=LEVELS, default=logging.INFO) | ||||||
|     created = models.DateTimeField(auto_now_add=True) |     created = models.DateTimeField(auto_now_add=True) | ||||||
|     modified = models.DateTimeField(auto_now=True) |  | ||||||
|  |  | ||||||
|     objects = LogManager() |  | ||||||
|  |  | ||||||
|     class Meta: |     class Meta: | ||||||
|         ordering = ("-modified",) |         ordering = ("-created",) | ||||||
|  |  | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return self.message |         return self.message | ||||||
|  |  | ||||||
|     def save(self, *args, **kwargs): |  | ||||||
|         """ |  | ||||||
|         To allow for the case where we don't want to group the message, we |  | ||||||
|         shouldn't force the caller to specify a one-time group value.  However, |  | ||||||
|         allowing group=None means that the manager can't differentiate the |  | ||||||
|         different un-grouped messages, so instead we set a random one here. |  | ||||||
|         """ |  | ||||||
|  |  | ||||||
|         if not self.group: |  | ||||||
|             self.group = uuid.uuid4() |  | ||||||
|  |  | ||||||
|         models.Model.save(self, *args, **kwargs) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class FileInfo: | class FileInfo: | ||||||
|  |  | ||||||
|   | |||||||
| @@ -105,12 +105,13 @@ class DocumentSerializer(serializers.ModelSerializer): | |||||||
|  |  | ||||||
| class LogSerializer(serializers.ModelSerializer): | class LogSerializer(serializers.ModelSerializer): | ||||||
|  |  | ||||||
|     time = serializers.DateTimeField() |  | ||||||
|     messages = serializers.CharField() |  | ||||||
|  |  | ||||||
|     class Meta: |     class Meta: | ||||||
|         model = Log |         model = Log | ||||||
|         fields = ( |         fields = ( | ||||||
|             "time", |             "id", | ||||||
|             "messages" |             "created", | ||||||
|  |             "message", | ||||||
|  |             "group", | ||||||
|  |             "level" | ||||||
|         ) |         ) | ||||||
|   | |||||||
| @@ -27,7 +27,8 @@ from .filters import ( | |||||||
|     CorrespondentFilterSet, |     CorrespondentFilterSet, | ||||||
|     DocumentFilterSet, |     DocumentFilterSet, | ||||||
|     TagFilterSet, |     TagFilterSet, | ||||||
|     DocumentTypeFilterSet |     DocumentTypeFilterSet, | ||||||
|  |     LogFilterSet | ||||||
| ) | ) | ||||||
|  |  | ||||||
| import documents.index as index | import documents.index as index | ||||||
| @@ -147,12 +148,14 @@ class DocumentViewSet(RetrieveModelMixin, | |||||||
|  |  | ||||||
| class LogViewSet(ReadOnlyModelViewSet): | class LogViewSet(ReadOnlyModelViewSet): | ||||||
|     model = Log |     model = Log | ||||||
|     queryset = Log.objects.all().by_group() |  | ||||||
|  |     queryset = Log.objects.all() | ||||||
|     serializer_class = LogSerializer |     serializer_class = LogSerializer | ||||||
|     pagination_class = StandardPagination |     pagination_class = StandardPagination | ||||||
|     permission_classes = (IsAuthenticated,) |     permission_classes = (IsAuthenticated,) | ||||||
|     filter_backends = (DjangoFilterBackend, OrderingFilter) |     filter_backends = (DjangoFilterBackend, OrderingFilter) | ||||||
|     ordering_fields = ("time",) |     filter_class = LogFilterSet | ||||||
|  |     ordering_fields = ("created",) | ||||||
|  |  | ||||||
|  |  | ||||||
| class SearchView(APIView): | class SearchView(APIView): | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Jonas Winkler
					Jonas Winkler