from django.db import models
from django_minio_backend import MinioBackend


class BaseFile(models.Model):
    id = models.BigAutoField(primary_key=True, db_column="id_object")
    file_name = models.CharField(max_length=100)

    class Meta:
        abstract = True


class VideoFile(BaseFile):
    duration = models.PositiveIntegerField("Длительность в мс", null=True)
    frame_rate = models.IntegerField("Частота кадров", null=True)
    file_path = models.FileField(storage=MinioBackend(bucket_name="archive-kffd"), upload_to="video")
    material = models.ForeignKey(
        "VideoMaterial",
        verbose_name="Видео-файл",
        related_name="media_files",
        on_delete=models.PROTECT,
        db_column="id_main",
    )

    class Meta:
        db_table = "archive_video_file"
        ordering = ("id",)


class AudioFile(BaseFile):
    duration = models.PositiveIntegerField("Длительность в мс", null=True)
    file_path = models.FileField(storage=MinioBackend(bucket_name="archive-kffd"), upload_to="audio")
    material = models.ForeignKey(
        "AudioMaterial",
        verbose_name="Аудио-файл",
        related_name="media_files",
        on_delete=models.PROTECT,
        db_column="id_main",
    )

    class Meta:
        db_table = "archive_audio_file"
        ordering = ("id",)


class ImageFile(BaseFile):
    file_path = models.FileField(storage=MinioBackend(bucket_name="archive-kffd"), upload_to="image")
    material = models.ForeignKey(
        "ImageMaterial",
        verbose_name="Фото-файл",
        related_name="media_files",
        on_delete=models.PROTECT,
        db_column="id_main",
    )

    class Meta:
        db_table = "archive_image_file"
        ordering = ("id",)


class CreationDateVariant(models.IntegerChoices):
    ONLY_YEAR = 1, "только год"
    MONTH_AND_YEAR = 3, "год и месяц"
    FULL_DATE = 7, "год, месяц и число"


class BaseMaterial(models.Model):
    id = models.BigAutoField(primary_key=True, db_column="id_main")
    keywords = models.CharField("Ключевые слова", max_length=512, blank=True)
    annotation = models.TextField("Аннотация", blank=True)
    archive_number = models.CharField(max_length=256, unique=True)
    persons = models.CharField("Персоналии", max_length=1024, blank=True)
    source = models.CharField("Источник поступления", max_length=256, blank=True)
    founder = models.CharField("Фондообразователь", max_length=256, blank=True)
    creation_date = models.DateField("Дата создания", null=True)
    creation_date_key = models.SmallIntegerField(
        help_text="Показывает какая часть даты известна в двоичном формате: "
        "001 (1) только год, "
        "011 (3) год и месяц, "
        "111 (7) год месяц и число",
        choices=CreationDateVariant.choices,
        null=True,
    )
    creation_date_comment = models.CharField("Дата создания комментарий", max_length=1024, blank=True)
    creation_place = models.CharField("Место создания", max_length=256, blank=True)
    receive_date = models.DateField("Дата поступления", null=True)

    class Meta:
        abstract = True


class AudioMaterial(BaseMaterial):
    title = models.CharField("Название", max_length=512, blank=True)
    text_author = models.CharField("Автор текста", max_length=256, blank=True)
    performer = models.CharField("Исполнитель", max_length=256, blank=True)
    music_author = models.CharField("Автор музыки", max_length=256, blank=True)
    arrangement = models.CharField("Аранжировка", max_length=256, blank=True)
    conductor = models.CharField("Дирижер", max_length=256, blank=True)
    art_director = models.CharField("Художественный руководитель", max_length=256, blank=True)
    language = models.CharField("Язык", max_length=256, blank=True)
    choir = models.CharField("Сопровождение (хор)", max_length=256, blank=True)
    orchestra = models.CharField("Сопровождение (инструменты)", max_length=256, blank=True)
    montage_sheet = models.TextField("Монтажный лист", blank=True)

    class Meta:
        verbose_name = "Фонодокумент"
        verbose_name_plural = "Фонодокументы"
        db_table = "archive_audio_material"
        ordering = ("id",)


class VideoMaterial(BaseMaterial):
    title = models.CharField("Название", max_length=512, blank=True)
    description = models.TextField("Описание сюжета", blank=True)
    montage_sheet = models.TextField("Монтажный лист", blank=True)
    roles = models.TextField("В ролях", blank=True)
    scriptwriter = models.CharField("Сценарист", max_length=512, blank=True)
    director = models.CharField("Режиссер", max_length=512, blank=True)
    cameraman = models.CharField("Оператор", max_length=512, blank=True)
    sound_engineer = models.CharField("Звукооператор", max_length=512, blank=True)
    painter = models.CharField("Художник", max_length=512, blank=True)
    composer = models.CharField("Композитор", max_length=512, blank=True)
    studio = models.CharField("Студия", max_length=512, blank=True)
    role_dubbing = models.CharField("Роли озвучивали", max_length=1024, blank=True)
    video_creators = models.CharField("Над фильмом работали", max_length=1024, blank=True)
    video_type = models.CharField("Вид документа", max_length=256, blank=True)
    color = models.CharField("Цветность", max_length=256, blank=True)
    language = models.CharField("Язык", max_length=256, blank=True)
    literature_source = models.CharField("Литературный первоисточник", max_length=512, blank=True)
    voice_type = models.CharField("Озвученность", max_length=256, blank=True)

    class Meta:
        verbose_name = "Киновидеодокумент"
        verbose_name_plural = "Киновидеодокументы"
        db_table = "archive_video_material"
        ordering = ("id",)


class ImageMaterial(BaseMaterial):
    author = models.CharField("Автор", max_length=256, blank=True)
    photo_type = models.CharField("Вид фотодокумента", max_length=256, blank=True)
    color = models.CharField("Цветность", max_length=256, blank=True)

    class Meta:
        verbose_name = "Фотодокумент"
        verbose_name_plural = "Фотодокументы"
        db_table = "archive_image_material"
        ordering = ("id",)from django.core.exceptions import PermissionDenied
from django.http import Http404
from django.utils.encoding import force_str
from rest_framework import exceptions, serializers
from rest_framework.metadata import SimpleMetadata
from rest_framework.request import clone_request
from rest_framework.utils.field_mapping import ClassLookupDict


class CustomMetadata(SimpleMetadata):


    label_lookup = ClassLookupDict(
        {
            serializers.Field: "field",
            serializers.BooleanField: "boolean",
            serializers.CharField: "string",
            serializers.UUIDField: "string",
            serializers.URLField: "url",
            serializers.EmailField: "email",
            serializers.RegexField: "regex",
            serializers.SlugField: "slug",
            serializers.IntegerField: "integer",
            serializers.FloatField: "float",
            serializers.DecimalField: "decimal",
            serializers.DateField: "date",
            serializers.DateTimeField: "datetime",
            serializers.TimeField: "time",
            serializers.DurationField: "duration",
            serializers.ChoiceField: "choice",
            serializers.MultipleChoiceField: "multiple choice",
            serializers.FileField: "file upload",
            serializers.ImageField: "image upload",
            serializers.ListField: "list",
            serializers.DictField: "nested object",
            serializers.Serializer: "nested object",
        }
    )

    def determine_metadata(self, request, view):

        metadata = {
            "name": view.get_view_name(),
            "description": view.get_view_description(),
            "renders": [renderer.media_type for renderer in view.renderer_classes],
            "parses": [parser.media_type for parser in view.parser_classes],
        }
        if hasattr(view, "get_serializer"):
            actions = self.determine_actions(request, view)
            if actions:
                metadata["actions"] = actions
        return metadata

    def determine_actions(self, request, view):

        actions = {}

        for method in {"PUT", "POST", "GET"} & set(view.allowed_methods):

            view.request = clone_request(request, method)
            try:

                if hasattr(view, "check_permissions"):
                    view.check_permissions(view.request)

                if method == "PUT" and hasattr(view, "get_object"):
                    view.get_object()
            except (exceptions.APIException, PermissionDenied, Http404):

                pass
            else:

                serializer = view.get_serializer()
                actions[method] = self.get_serializer_info(serializer)
            finally:

                view.request = request

        return actions

    def get_serializer_info(self, serializer):

        if hasattr(serializer, "child"):

            serializer = serializer.child
        return {
            field_name: self.get_field_info(field)
            for field_name, field in serializer.fields.items()
            if not isinstance(field, serializers.HiddenField)
        }

    def get_field_info(self, field):

        field_info = {
            "type": self.label_lookup[field],
            "required": getattr(field, "required", False),
        }


        attrs = [
            "read_only",
            "label",
            "help_text",
            "min_length",
            "max_length",
            "min_value",
            "max_value",
            "max_digits",
            "decimal_places",
        ]

        for attr in attrs:
            value = getattr(field, attr, None)
            if value is not None and value != "":
                field_info[attr] = force_str(value, strings_only=True)


        if hasattr(field, "child"):
            field_info["child"] = self.get_field_info(field.child)
        elif hasattr(field, "fields"):
            field_info["children"] = self.get_serializer_info(field)


        if (
            not field_info.get("read_only")
            and not isinstance(field, (serializers.RelatedField, serializers.ManyRelatedField))
            and hasattr(field, "choices")
        ):
            field_info["choices"] = [
                {"value": choice_value, "display_name": force_str(choice_name, strings_only=True)}
                for choice_value, choice_name in field.choices.items()
            ]

        return field_info<script setup>
import { onBeforeMount, ref } from 'vue'
import { getRecordList, getOptions } from '@/api/default_api_promises.js'
import { useRoute, useRouter } from 'vue-router'
import Paginator from '@/components/common/Paginator.vue'
import DynamicDataList from '@/components/DynamicDataList.vue'

let route = useRoute();
let router = useRouter();
console.log(route.query)
let currentTableTab = ref(route.query.material_type)

let items = ref([]);
let totalCount = ref(0);
let pageCount = ref(0);
function getItems() {
  let urlSearchParams = new URLSearchParams(route.query);
  getRecordList({ url: `/api/${currentTableTab.value}-materials/` })({ params: urlSearchParams })
    .then(response => {
      totalCount.value = response.data.count;
      items.value = response.data.results;
      pageCount.value = Math.ceil(totalCount.value / route.query.page_size);
    })


function updateTab() {
  let query = { ...route.query, material_type: currentTableTab.value }
  router.push({ name: route.name, query: query, params: { ...route.params } })
}

onBeforeMount(getItems)
</script>

<template>
  <v-tabs
    v-model="currentTableTab"
    align-tabs="center"
    color="primary-blue"
    @update:model-value="updateTab"
  >
    <v-tab value="image">Фото</v-tab>
    <v-tab value="audio">Фоно</v-tab>
    <v-tab value="video">Видео</v-tab>
  </v-tabs>

  <dynamic-data-list :items="items" :material-type="currentTableTab"/>
  <paginator v-if="items.length" :page-count="pageCount"/>
</template>


<style scoped lang="scss">
</style>
import api from "@/plugins/axios.js";

function recordBase(method, options) {
  const defaultAxios = {
    method: method
  }
  return function (queryParams) {
    return api({ ...defaultAxios, ...options, ...queryParams })
  };
}

export function getRecordList(options) {
  return recordBase("get", options)
}

export function getRecordDetail(options) {
  return recordBase("get", options)
}

export function getOptions(options) {
  return recordBase("options", options)
}
from django.db.models import Q
from rest_framework import viewsets
from rest_framework.response import Response

from backend.apps.archive.models import AudioMaterial, ImageMaterial, VideoMaterial

from . import serializers


class BaseMaterialViewSet(viewsets.ReadOnlyModelViewSet):
    def get_common_search_lookup(self, common_search_value):
        lookup = Q()
        for field in self.common_search_fields:
            lookup |= Q(**{f"{field}__icontains": common_search_value})
        return lookup

    def get_queryset(self):
        queryset = super().get_queryset()
        common_search_query = self.request.GET.get("common_search_query")

        if common_search_query:
            query_lookup = self.get_common_search_lookup(common_search_query)
            queryset = queryset.filter(query_lookup)

        return queryset

    def list(self, request, *args, **kwargs):
        queryset = self.get_queryset()
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        serializer = self.get_serializer(self.queryset, many=True)
        return self.get_paginated_response(serializer.data) if page is not None else Response(serializer.data)


class AudioMaterialViewSet(BaseMaterialViewSet):
    queryset = AudioMaterial.objects.all()
    serializer_class = serializers.AudioMaterialListSerializer
    common_search_fields = ["keywords", "annotation", "persons", "title"]


class ImageMaterialViewSet(BaseMaterialViewSet):
    queryset = ImageMaterial.objects.all()
    serializer_class = serializers.ImageMaterialListSerializer
    common_search_fields = ["keywords", "annotation", "persons", "author"]

    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)


class VideoMaterialViewSet(BaseMaterialViewSet):
    queryset = VideoMaterial.objects.all()
    serializer_class = serializers.VideoMaterialListSerializer
    common_search_fields = ["keywords", "annotation", "persons", "title", "description"]
<script setup> по аналогии сделай options запрос чтобы в результатах поиска динамически выводились названия полей каждого типа материала и их значения в этом файле:
import { ref, onBeforeMount, onMounted } from 'vue';
import axios from 'axios';

const props = defineProps({
  materialType: String
});

const items = ref([]);
const fields = ref({});

const iconMap = {
  audio: 'mdi-volume-high',
  photo: 'mdi-image-outline',
  video: 'mdi-video-outline'
};

// const fetchFieldsMetadata = () => {
//   axios.options(`/api/materials/${props.materialType}/`)
//     .then(data => {
//       console.log(123, data)
//       fields.value = data;
//     })
//     .catch(error => {
//       console.error('Error fetching field metadata:', error);
//     });
// };

// onBeforeMount(fetchFieldsMetadata);
</script>

<template>
  <v-data-iterator :items="items" class="d-flex justify-center">
    <template v-slot:default="{ items }">
      <template v-for="(item, index) in items" :key="index">
        <div class="item">
          <div class="item-icon">
            <v-icon size="110" color="primary-violet">
              {{ iconMap[item.materialType] || 'mdi-file-document-outline' }}
            </v-icon>
          </div>
          <div class="item-content">
            <div v-for="(value, key) in item.raw" :key="key" class="item-field">
              <span class="field-label">{{ key }}:</span>
              <span class="field-value">{{ value }}</span>
            </div>
          </div>
        </div>
      </template>
    </template>
  </v-data-iterator>
</template>

<style scoped lang="scss">
.item {
  width: 900px;
  padding: 15px;
  margin-top: 15px;
  margin-bottom: 15px;
  border: 1px solid darkgray;
  border-radius: 8px;
  display: flex;
  overflow: hidden;
}

.item-icon {
  flex-shrink: 0;
  width: 110px;
}

.item-content {
  flex-grow: 1;
  margin-left: 20px;
  overflow: hidden;
}

.item-field {
  display: flex;
  align-items: center;
  margin-bottom: 3px;
  line-height: 1.2;
}

.field-label {
  flex-shrink: 0;
  font-size: 12px;
  font-weight: bold;
  color: gray;
  margin-right: 5px;
}

.field-value {
  font-size: 12px;
  font-weight: normal;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
</style>import re

from rest_framework import serializers

from . import models





class BaseMaterialListSerializer(serializers.ModelSerializer):
    archive_number = serializers.CharField(label="Архивный номер")

    @staticmethod
    def get_annotation(instance):
        max_tokens = 11
        if instance.annotation:
            tokens = re.findall(r"\S+", instance.annotation)
            annotation = " ".join(tokens[:max_tokens])
            annotation += " ..." if len(tokens) > max_tokens else ""
            return annotation
        return ""

    @staticmethod
    def get_creation_date(instance):
        match instance.creation_date_key:
            case models.CreationDateVariant.ONLY_YEAR:
                return instance.creation_date.year
            case models.CreationDateVariant.MONTH_AND_YEAR:
                return instance.creation_date.strftime("%m.%Y")
            case models.CreationDateVariant.FULL_DATE:
                return instance.creation_date.strftime("%d.%m.%Y")


class ImageMaterialListSerializer(BaseMaterialListSerializer):
    class Meta:
        model = models.ImageMaterial
        fields = ("archive_number", "annotation", "creation_date", "author", "photo_type", "color")


class AudioMaterialListSerializer(BaseMaterialListSerializer):
    class Meta:
        model = models.AudioMaterial
        fields = ("archive_number", "title", "annotation", "performer", "creation_date", "language")


class VideoMaterialListSerializer(BaseMaterialListSerializer):
    class Meta:
        model = models.VideoMaterial
        fields = ("archive_number", "title", "creation_date", "annotation", "roles", "language")