Расширенная модель Django

У меня есть 2 модели. В одной из них я хочу выводить общую информацию, а в другой - расширенную. Я хочу, чтобы модели объединяло поле service_id.

В модели AdvancedService у меня есть 2 объекта с одним service_id. В модели Service, когда я нажимаю на service_id, я хочу просмотреть 2 объекта с таким service_id. Однако я не понимаю, как это можно сделать. Мой код:

#models.py

class ServiceModel(models.Model):
    service_id = models.CharField(max_length=150)
    total_cars = models.PositiveIntegerField() # bmw + audi
    repaired = models.PositiveIntegerField() # broken_motor + broken_body
    advanced = models.ForeignKey(
        'AdvancedServiceModel', on_delete=models.CASCADE)

class AdvancedServiceModel(models.Model):
    service_id = models.CharField(max_length=150)
    bmw = models.PositiveIntegerField()
    audi = models.PositiveIntegerField()
    broken_motor = models.PositiveIntegerField()
    broken_body = models.PositiveIntegerField()

    def __str__(self) -> str:
        return f'{self.service_id}'

#admin.py

from django.contrib import admin
from .models import ServiceModel, AdvancedServiceModel
from django.urls import reverse
from django.utils.html import escape, mark_safe

@admin.register(ServiceModel)
class ServiceModelAdmin(admin.ModelAdmin):
    list_display = ['advanced_link', 'total_cars', 'repaired']

    def advanced_link(self, obj: AdvancedServiceModel):
        link = reverse("admin:tasks_advancedservicemodel_changelist")
        return mark_safe(f'<a href="{link}">{escape(obj.advanced.__str__())}</a>')

    advanced_link.short_description = 'Service id'
    advanced_link.admin_order_field = 'service_id' # Make row sortable

@admin.register(AdvancedServiceModel)
class AdvancedServiceModelAdmin(admin.ModelAdmin):
    list_display = ['service_id', 'bmw', 'audi', 'broken_motor', 'broken_body']

Мой ответ требует, чтобы ServiceModel.service_id был уникальным. Вы должны переместить внешний ключ из ServiceModel в AdvancedServiceModel. Это потому, что вы хотите иметь один экземпляр модели сервиса для всех продвинутых моделей сервиса. В Django нет OneToManyField. Он может быть реализован только через ForeignKey.

В рамках этого изменения вы удалите поле service_id из AdvancedServiceModel. Если вам нужно получить фактический идентификатор услуги, вам нужно будет извлечь связанное с ним поле ServiceModel.

class ServiceModel(models.Model):
    service_id = models.CharField(max_length=150, unique=True)
    total_cars = models.PositiveIntegerField() # bmw + audi
    repaired = models.PositiveIntegerField() # broken_motor + broken_body


class AdvancedServiceModel(models.Model):
    service_model = models.ForeignKey(
        ServiceModel, related_name='advanced_service_models', on_delete=models.CASCADE)
    bmw = models.PositiveIntegerField()
    audi = models.PositiveIntegerField()
    broken_motor = models.PositiveIntegerField()
    broken_body = models.PositiveIntegerField()

# admin.py
from django.db.models import Count

@admin.register(ServiceModel)
class ServiceModelAdmin(admin.ModelAdmin):
    list_display = ['advanced_link', 'total_cars', 'repaired']

    def get_queryset(self, *args, **kwargs): # I forget the arguments, look them up please.
        return super().get_queryset(*args, **kwargs).annotate(
            advanced_count=Count('advanced_service_models__id'),
        )

    def advanced_link(self, obj: AdvancedServiceModel):
        link = reverse("admin:tasks_advancedservicemodel_changelist") + f"?service_model__id__exact={obj.id}"
        count = obj.advanced_count
        return mark_safe(f'<a href="{link}">View Advanced Services ({count})</a>')

    advanced_link.short_description = 'Service id'
    advanced_link.admin_order_field = 'service_id' # Make row sortable

@admin.register(AdvancedServiceModel)
class AdvancedServiceModelAdmin(admin.ModelAdmin):
    list_display = ['service_id', 'bmw', 'audi', 'broken_motor', 'broken_body']
    list_select_related = ['service_model']
    
    def service_id(self, obj):
        return obj.service_model.service_id
Вернуться на верх