Django-simple-history Как отображать связанные поля в панели администратора?

Я использую django-simple-history. Я сохраняю историческую таблицу продукта и цены, цена связана с продуктом, и в админ-панель добавляется встроенная линия. Хочу отображать в админке в истории товаров записи историй связанных моделей (цен). Как я могу это сделать? И чтобы измененные поля отображались моя модель

class Product(models.Model):
    article = models.PositiveIntegerField()
    history = HistoricalRecords()

class Price(models.Model):
    prod = models.OneToOneField(
        Product,)
    price_supplier = models.FloatField()
    history = HistoricalRecords()

мой администратор

class PriceInline(admin.TabularInline):
    model = Price

class ProductAdmin(SimpleHistoryAdmin):
    inlines = [
        PriceInline,]

admin.site.register(Product, ProductAdmin)

введите сюда описание изображениявведите сюда описание изображения

Попробовал настроить через History_view() и get_history_queryset() на получение объектов другой модели и я их получил, но не понимаю как их встроить в рендер, чтобы и менялась модель товара, и менялась цена модель будет отражена, и в то же время изменившиеся поля будут соответствовать их моделям. или есть другой способ добиться этого результата

Почему бы не перенести цену в модель Product?

willeM_ Van Onsem 11.06.2024 09:21

это необходимость проекта и перенос невозможен. также есть связанные таблицы со стоковыми изображениями документов и характеристиками с такой же привязкой к товарам и их тоже нужно отображать в истории

Анастасия Швечкова 11.06.2024 09:29
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
2
91
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я нашел решение, это что-то вроде ляпа. Поскольку мы не будем отображать цену приложения отдельно в панели администратора (она участвует только во встроенной части продукта), мы можем изменить функцию History_view() с django-simple-history. Я добавлю в пример модель изображения, чтобы показать, как использовать этот подход как с полями «один к одному», так и с полями «один ко многим». При этом я отключил возможность возвращать старое значение из истории и для шаблона изменил то, что отображалось в первом столбце как ссылка, потому что ссылки нужно настраивать отдельно. Теперь в первом столбце у меня есть только названия типов полей.

Теперь мой код выглядит так:

модель.py

    class Product(models.Model):
        article = models.PositiveIntegerField()
        history = HistoricalRecords()

    class Price(models.Model):
        prod = models.OneToOneField(Product,)
        price_supplier = models.FloatField()
        history = HistoricalRecords()

    class ProductImage(models.Model):
        product = models.ForeignKey(Product,)
        photo = models.ImageField("Изображение", upload_to=get_file_path_add)
        history = HistoricalRecords()

admin.py

    class PriceInline(admin.TabularInline):
        model = Price

    class ProductImageInline(admin.TabularInline):
        model = ProductImage

    class PriceAdmin(SimpleHistoryAdmin):
        model = Price

        def history_view(self, request, object_id, extra_context=None):
            """The 'history' admin view for this model."""

            model = self.model
            opts = model._meta
            pk_name = opts.pk.attname
            history = getattr(model, model._meta.simple_history_manager_attribute)

            historical_records = PriceAdmin.get_history_queryset( PriceAdmin, 
             request, history, pk_name, object_id )

            history_list_display = 
             PriceAdmin.get_history_list_display(PriceAdmin,request)

            # Set attribute on each historical record from admin methods
            for history_list_entry in history_list_display:
                value_for_entry = getattr(self, history_list_entry, None)
                if value_for_entry and callable(value_for_entry):
                    for record in historical_records:
                        setattr(record, history_list_entry, 
                        value_for_entry(record))

            PriceAdmin.set_history_delta_changes(PriceAdmin, request, 
            historical_records)

            return historical_records

        def set_history_delta_changes(
            self,
            request,
            historical_records,
            foreign_keys_are_objs=True,
        ):
            previous = None
            for current in historical_records:
                if previous is None:
                    previous = current
                    continue
                # Related objects should have been prefetched in `get_history_queryset()`
            delta = previous.diff_against(
                current, foreign_keys_are_objs=foreign_keys_are_objs
            )
            helper = PriceAdmin.get_historical_record_context_helper(
                PriceAdmin, request, previous
            )
            previous.history_delta_changes = helper.context_for_delta_changes(delta)

            previous = current

    class ProductImageAdmin(SimpleHistoryAdmin):
        model = ProductImage
        
        def history_view(self, request, object_id, extra_context=None):
            """The 'history' admin view for this model."""
            model = self.model
            opts = model._meta
            pk_name = opts.pk.attname
            history = getattr(model, model._meta.simple_history_manager_attribute)

            historical_records = ProductImageAdmin.get_history_queryset(
            ProductImageAdmin, request, history, pk_name, object_id
        )

            history_list_display = ProductImageAdmin.get_history_list_display(
            ProductImageAdmin, request
        )
            # Set attribute on each historical record from admin methods
            for history_list_entry in history_list_display:
                value_for_entry = getattr(self, history_list_entry, None)
                if value_for_entry and callable(value_for_entry):
                     for record in historical_records:
                        setattr(record, history_list_entry, value_for_entry(record))

            ProductImageAdmin.set_history_delta_changes(
            ProductImageAdmin, request, historical_records
        )

             return historical_records

         def set_history_delta_changes(
            self,
            request,
            historical_records,
            foreign_keys_are_objs=True,
    ):
            previous = None
            for current in historical_records:
                if previous is None:
                    previous = current
                    continue
                # Related objects should have been prefetched in `get_history_queryset()`
                delta = previous.diff_against(
                current, foreign_keys_are_objs=foreign_keys_are_objs
            )
                helper = ProductImageAdmin.get_historical_record_context_helper(
                ProductImageAdmin, request, previous
            )
                previous.history_delta_changes = helper.context_for_delta_changes(delta)

                previous = current

    class ProductAdmin(SimpleHistoryAdmin):
        inlines = [
        PriceInline,
        ProductImageInline,
    ]
        def history_view(self, request, object_id, extra_context=None):
        """The 'history' admin view for this model."""
        request.current_app = self.admin_site.name

        model = self.model
        opts = model._meta
        app_label = opts.app_label
        pk_name = opts.pk.attname
        history = getattr(model, model._meta.simple_history_manager_attribute)

        object_id = unquote(object_id)
        price_id = Price.objects.get(prod=object_id)
        image_id = ProductImage.objects.filter(product=object_id)
        
        historical_records = self.get_history_queryset(
            request, history, pk_name, object_id
        )
    #**here we get historical_records in image and price**
        historical_records_image = []
        for item in image_id:
            item_list = ProductImageAdmin.history_view(
                ProductImageAdmin, request, item.id, extra_context=None
            )
            if historical_records_image == []:
                historical_records_image = item_list
            else:
                historical_records_image = list(
                    chain(
                        historical_records_image,
                        item_list,
                    )
                )
        historical_records_price = PriceAdmin.history_view(
            PriceAdmin, request, price_id.id, extra_context=None
        )
         history_list_display = self.get_history_list_display(request)

        # If no history was found, see whether this object even exists.
        try:
            obj = self.get_queryset(request).get(**{pk_name: object_id})
        except model.DoesNotExist:
            try:
                obj = historical_records.latest("history_date").instance
            except historical_records.model.DoesNotExist:
                raise http.Http404

        if not self.has_view_history_or_change_history_permission(request, obj):
            raise PermissionDenied

        # Set attribute on each historical record from admin methods
        for history_list_entry in history_list_display:
            value_for_entry = getattr(self, history_list_entry, None)
            if value_for_entry and callable(value_for_entry):
                for record in historical_records:
                    setattr(record, history_list_entry, value_for_entry(record))

        self.set_history_delta_changes(request, historical_records)
         # HERE WE COLLECT A GENERAL LIST OF ALL RECORDS
         result_list = list(
            chain(
                historical_records,
                historical_records_price,
                historical_records_image,
            )
        )
        # HERE WE SORT THEM ALL BY TIME
        def get_date(element):
            return element.history_date

        result_list_sorted = result_list.sort(key=get_date, reverse=True)

        content_type = self.content_type_model_cls.objects.get_for_model(
            get_user_model()
        )
        admin_user_view = "admin:{}_{}_change".format(
            content_type.app_label,
            content_type.model,
        )
        context = {
            "title": self.history_view_title(request, obj),
            "object_history_list_template": self.object_history_list_template,
            "historical_records": result_list,
            "module_name": capfirst(force_str(opts.verbose_name_plural)),
            "object": obj,
            "root_path": getattr(self.admin_site, "root_path", None),
            "app_label": app_label,
            "opts": opts,
            "admin_user_view": admin_user_view,
            "history_list_display": history_list_display,
            "revert_disabled": self.revert_disabled(request, obj),
        }
        context.update(self.admin_site.each_context(request))

        context.update(extra_context or {})
        extra_kwargs = {}
        return self.render_history_view(
            request, self.object_history_template, context, **extra_kwargs
        )

    admin.site.register(Product, ProductAdmin)

Другие вопросы по теме