Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 77 additions & 30 deletions backend/api/v1/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
DocumentField,
FavDocument,
FavTemplate,
FieldToDocument,
Template,
TemplateField,
)

User = get_user_model()


class Base64ImageField(serializers.ImageField):
def to_internal_value(self, data):
if isinstance(data, str) and data.startswith("data:image"):
Expand All @@ -29,6 +29,7 @@ def to_internal_value(self, data):

return super().to_internal_value(data)


class TemplateFieldSerializer(serializers.ModelSerializer):
"""Сериализатор поля шаблона."""

Expand Down Expand Up @@ -104,6 +105,7 @@ class TemplateSerializerMinified(serializers.ModelSerializer):

is_favorited = serializers.SerializerMethodField()
image = Base64ImageField(required=True, allow_null=True)

class Meta:
model = Template
exclude = ("template",)
Expand Down Expand Up @@ -181,13 +183,12 @@ class DocumentFieldSerializer(serializers.ModelSerializer):

class Meta:
model = DocumentField
fields = "__all__"
exclude = ("document",)


class DocumentReadSerializer(serializers.ModelSerializer):
"""Сериализатор документов."""
class DocumentReadSerializerMinified(serializers.ModelSerializer):
"""Сериализатор документов сокращенный (без информации о полях)"""

document_fields = DocumentFieldSerializer(many=True)
is_favorited = serializers.SerializerMethodField()

class Meta:
Expand All @@ -200,7 +201,6 @@ class Meta:
"description",
"template",
"owner",
"document_fields",
"is_favorited",
)

Expand All @@ -213,6 +213,67 @@ def get_is_favorited(self, document: Document) -> bool:
).exists()


class DocumentReadSerializerExtended(serializers.ModelSerializer):
"""Сериализатор документов расширенный (с информацией полей шаблона)."""

grouped_fields = TemplateGroupSerializer(
read_only=True,
many=True,
source="template.field_groups",
allow_empty=True,
)
ungrouped_fields = serializers.SerializerMethodField()
is_favorited = serializers.SerializerMethodField()
template = TemplateSerializerMinified(read_only=True)

class Meta:
model = Document
fields = (
"id",
"created",
"updated",
"completed",
"description",
"template",
"owner",
"is_favorited",
"grouped_fields",
"ungrouped_fields",
)

def get_is_favorited(self, document: Document) -> bool:
user = self.context.get("request").user
if not user.is_authenticated:
return False
return FavDocument.objects.filter(
user=user, document=document
).exists()

def get_ungrouped_fields(self, instance):
solo_fields = instance.template.fields.filter(group=None).order_by(
"id"
)
return TemplateFieldSerializerMinified(solo_fields, many=True).data

def to_representation(self, instance):
response = super().to_representation(instance)
response["grouped_fields"].sort(key=lambda x: x["id"])
# add field values
field_vals = {}
for document_field in instance.document_fields.all():
field_vals[document_field.field.id] = document_field.value
for group in response["grouped_fields"]:
for field in group["fields"]:
id = field.get("id")
if id in field_vals:
field["value"] = field_vals[id]
for field in response["ungrouped_fields"]:
id = field.get("id")
if id in field_vals:
field["value"] = field_vals[id]
return response


class DocumentWriteSerializer(serializers.ModelSerializer):
"""Сериализатор документов."""

Expand All @@ -231,41 +292,27 @@ class Meta:

@transaction.atomic
def create(self, validated_data):
"""Пока говно код. Создание документа и полей документа"""
"""Создание документа и полей документа"""
document_fields = validated_data.pop("document_fields")
document = Document.objects.create(**validated_data)
for data in document_fields:
field = data["field"]
template = TemplateField.objects.get(id=field.id).template
if (
document.template == template
): # Эту проверку надо в валидатор засунуть.
# Проверяется, принадлежит ли поле выбраному шаблону
field = DocumentField.objects.create(
field=field, value=data["value"]
)
FieldToDocument.objects.create(fields=field, document=document)
document.create_document_fields(document_fields)
return document

@transaction.atomic
def update(self, instance, validated_data):
"""Пока говно код. Обновление документа и полей документа"""
"""Обновление документа и полей документа"""
document_fields = validated_data.pop("document_fields")
Document.objects.filter(id=instance.id).update(**validated_data)
document = Document.objects.get(id=instance.id)
FieldToDocument.objects.filter(document=document).delete()
for data in document_fields:
field = data["field"]
template = TemplateField.objects.get(id=field.id).template
if document.template == template:
# Эту проверку надо в валидатор засунуть.
# Проверяется, принадлежит ли поле выбраному шаблону
field = DocumentField.objects.create(
field=data["field"], value=data["value"]
)
FieldToDocument.objects.create(fields=field, document=document)
document.document_fields.all().delete()
document.create_document_fields(document_fields)
return instance

def to_representation(self, instance):
return DocumentReadSerializerMinified(
instance, context={"request": self.context.get("request")}
).data


class FavTemplateSerializer(serializers.ModelSerializer):
class Meta:
Expand Down
28 changes: 14 additions & 14 deletions backend/api/v1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,26 @@
from api.v1.permissions import IsOwner, IsOwnerOrAdminOrReadOnly
from api.v1.serializers import (
CategorySerializer,

DocumentFieldForPreviewSerializer,
DocumentFieldSerializer,
DocumentReadSerializer,
DocumentReadSerializerMinified,
DocumentReadSerializerExtended,
DocumentWriteSerializer,
FavDocumentSerializer,
FavTemplateSerializer,
TemplateFieldSerializer,
TemplateSerializer,
TemplateSerializerMinified,
)

# from api.v1.utils import Util
from core.constants import Messages
from core.template_render import DocumentTemplate
from documents.models import (
Category,
Document,
DocumentField,
FavDocument,
FavTemplate,
FieldToDocument,
Template,
)

Expand Down Expand Up @@ -151,7 +150,7 @@ class DocumentViewSet(viewsets.ModelViewSet):
"""Документ."""

queryset = Document.objects.all()
serializer_class = DocumentReadSerializer
serializer_class = DocumentReadSerializerMinified
http_method_names = ("get", "post", "patch", "delete")
permissions_classes = (IsAuthenticated,)
filter_backends = (
Expand All @@ -171,8 +170,10 @@ def get_queryset(self):

def get_serializer_class(self):
"""Выбор сериализатора."""
if self.action in ["list", "retrieve"]:
return DocumentReadSerializer
if self.action == "retrieve":
return DocumentReadSerializerExtended
elif self.action == "list":
return DocumentReadSerializerMinified
return DocumentWriteSerializer

def perform_create(self, serializer):
Expand All @@ -189,7 +190,7 @@ def draft_documents(self, request):
"""Возвращает список незаконченных документов/черновиков"""
user = self.request.user
queryset = Document.objects.filter(completed=False, owner=user)
serializer = DocumentReadSerializer(
serializer = DocumentReadSerializerMinified(
queryset, many=True, context={"request": request}
)
return Response(serializer.data, status=status.HTTP_200_OK)
Expand Down Expand Up @@ -220,9 +221,9 @@ def download_document(self, request, pk=None):

document = get_object_or_404(Document, id=pk)
context = dict()
for docfield in FieldToDocument.objects.filter(document=document):
template_field = docfield.fields.field
context[template_field.tag] = docfield.fields.value
for docfield in document.document_fields.all():
template_field = docfield.field
context[template_field.tag] = docfield.value
context_default = {
field.tag: field.name for field in document.template.fields.all()
}
Expand All @@ -241,7 +242,7 @@ def download_pdf(self, request, pk=None):
"""Скачивание pdf-файла."""
document = get_object_or_404(Document, id=pk, owner=request.user)
docx_stream = io.BytesIO(
b''.join(self.download_document(request, pk).streaming_content)
b"".join(self.download_document(request, pk).streaming_content)
)
docx_file = aw.Document(docx_stream)
buffer = io.BytesIO()
Expand All @@ -267,8 +268,7 @@ def get_queryset(self):
or document.owner != self.request.user
):
raise PermissionDenied()
through_set = FieldToDocument.objects.filter(document=document).all()
return DocumentField.objects.filter(fieldtodocument__in=through_set)
return document.document_fields.objects.all()


class FavTemplateAPIview(APIView):
Expand Down
32 changes: 29 additions & 3 deletions backend/documents/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

from documents import models

admin.site.register(models.FieldToDocument)


@admin.register(models.Category)
class CategoryAdmin(admin.ModelAdmin):
Expand Down Expand Up @@ -104,6 +102,18 @@ def formfield_for_foreignkey(self, db_field, request, **kwargs):
return super().formfield_for_foreignkey(db_field, request, **kwargs)


class DocumentFieldInlineAdmin(admin.TabularInline):
model = models.DocumentField
extra = 1

def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "field" and request._document_instance_:
template = request._document_instance_.template
if template:
kwargs["queryset"] = template.fields.all()
return super().formfield_for_foreignkey(db_field, request, **kwargs)


@admin.register(models.Document)
class DocumentAdmin(admin.ModelAdmin):
list_display = (
Expand All @@ -117,13 +127,29 @@ class DocumentAdmin(admin.ModelAdmin):
)
list_filter = ("template", "owner", "completed")
readonly_fields = ("id", "created", "updated")
inlines = (DocumentFieldInlineAdmin,)

def get_form(self, request, instance=None, **kwargs):
request._document_instance_ = instance
return super().get_form(request, instance, **kwargs)


@admin.register(models.DocumentField)
class DocumentFieldAdmin(admin.ModelAdmin):
list_display = ("id", "field_id", "value", "description")
list_display = ("id", "document_id", "field_id", "value")
readonly_fields = ("id",)

def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "field":
docfield_id = request.resolver_match.kwargs.get("object_id")
if docfield_id:
docfield = models.DocumentField.objects.get(id=docfield_id)
if docfield.document.template:
kwargs[
"queryset"
] = docfield.document.template.fields.all()
return super().formfield_for_foreignkey(db_field, request, **kwargs)


admin.site.site_header = "Административная панель Шаблонизатор"
admin.site.index_title = "Настройки Шаблонизатор"
Expand Down
27 changes: 27 additions & 0 deletions backend/documents/migrations/0027_auto_20231108_1053.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 3.2 on 2023-11-08 07:53

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('documents', '0026_auto_20231107_1326'),
]

operations = [
migrations.RemoveField(
model_name='document',
name='document_fields',
),
migrations.AddField(
model_name='documentfield',
name='document',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='document_fields', to='documents.document', verbose_name='Документ'),
preserve_default=False,
),
migrations.DeleteModel(
name='FieldToDocument',
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 3.2 on 2023-11-08 08:50

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('documents', '0027_auto_20231108_1053'),
]

operations = [
migrations.RemoveField(
model_name='documentfield',
name='description',
),
]
Loading