Объединение нескольких моделей Django в один список - PullRequest
0 голосов
/ 01 ноября 2019

У меня есть база данных MySQL с четырьмя связанными таблицами: проект, блок, unit_equipment и оборудование. Проект может иметь много юнитов;У единицы может быть много связанных записей оборудования. Один юнит может принадлежать только одному проекту, но между оборудованием и юнитом существует множество ко многим (отсюда и таблица мостов unit_equipment в БД). Я использую Django и пытаюсь создать вид (или список?), Который показывает все 3 модели на одной странице вместе. Таким образом, в нем будут перечислены все проекты, все подразделения и все оборудование. В идеале дисплей должен выглядеть следующим образом:

    Project --------- Unit ------------- Equipment
    Project 1         first_unit         some_equipment1, some_equipment2
    Project 1         second_unit        more_equipment1, more_equipment2
    Project 2         another_unit       some_equipment1, more_equipment1
    Project 2         and_another_unit   some_equipment2, more_equipment2

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

Хотя кажется простым создание формы, в которую я могу добавить новый проект и добавить связанные данные о единицах и оборудовании (используя класс TabularInline), я не могу на всю жизнь понять, как собрать эти данные вместе ипросто покажи это. Я просто хочу получить «основной список» всего в базе данных, в основном.

Вот код, который у меня пока есть:

models.py

class Project(models.Model):
    name = models.CharField(max_length=255, blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'project'

    def __str__(self):
        return self.name

class Unit(models.Model):
    project = models.ForeignKey(Project, models.DO_NOTHING, blank=True, null=True)
    name = models.CharField(max_length=255, blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'unit'

    def __str__(self):
        return self.name

class UnitEquipment(models.Model):
    unit = models.ForeignKey(Unit, models.DO_NOTHING, blank=True, null=True)
    equipment = models.ForeignKey(Equipment, models.DO_NOTHING, blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'unit_equipment'

class Equipment(models.Model):
    name = models.CharField(max_length=100, blank=True, null=True)
    description = models.CharField(max_length=255, blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'equipment'

    def __str__(self):
        return self.name

просмотров. py

def project_detail_view(request):
    obj = Project.objects.all()
    context = {'object': obj}
    return render(request, "project/project_detail.html", context)

urls.py

urlpatterns = [
    path('project/', project_detail_view),
    path('', admin.site.urls),
]

admin.py

class UnitTabularInLine(admin.TabularInline):
    model = Unit
    extra = 0

class ProjectAdmin(admin.ModelAdmin):
    inlines = [UnitTabularInLine]

    class Meta:
        model = Project

    # a list of displayed columns name.
    list_display = ['name']
    # define search columns list, then a search box will be added at the top of list page.
    search_fields = ['name']
    # define filter columns list, then a filter widget will be shown at right side of list page.
    list_filter = ['name']
    # define model data list ordering.
    ordering = ('name')

Я думаю, мне нужно как-то добавить больше записей в list_display в admin файл, но каждый раз, когда я пытаюсь добавить устройство или оборудование, он выдает ошибку. Я также пытался добавить больше атрибутов в Project, но мне кажется, что я не могу понять правильный синтаксис, и я никогда не уверен, какой класс модели я должен сделать.

Я такжеЯ посмотрел на FormSets, но не могу понять, как изменить мой текущий код, чтобы он заработал.

Как мне объединить эти модели в единое представление?

Ответы [ 2 ]

1 голос
/ 01 ноября 2019

Вам не нужно редактировать административное представление, чтобы добавить свой собственный вид: что вы можете найти в этом случае, чтобы ваши данные отображались именно так, как вы хотите.

Если вы это сделаетеЕсли вы хотите отобразить значения связанных объектов в списке администратора, вы можете использовать поиск и пользовательские столбцы: однако в этом случае ваш список будет основан на модуле.

# You don't need an explicit UnitEquipment model here: you can
# use a simple ManyToManyField

class Unit(models.Model):
    project = ...
    name = ...
    equipment = models.ManyToManyField(Equipment, related_name='units')


def equipment_list(admin, instance):
    return ', '.join([x.name for x in instance.equimpent.all()])


class UnitAdmin(admin.ModelAdmin):
    class Meta:
        model = Unit

    list_display = ['project__name', 'name', equipment_list]


    def get_queryset(self, request):
       return super().get_queryset(request)\
                     .select_related('project')\
                     .prefetch_related('equipment')

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

Есть также дальнейшее улучшение ваших запросов: вы можете агрегироватьсвязанные имена оборудования, используя аннотацию подзапроса, и предотвращают второй запрос (который выбирает все связанные элементы оборудования для единиц в наборе запросов). Это заменит prefetch_related()

0 голосов
/ 02 ноября 2019

Благодаря @Matthew Schinckel я смог найти свой путь к ответу. Вот как теперь выглядят мои файлы (редактировал только класс Unit в models.py):

models.py

class Unit(models.Model):
    project = models.ForeignKey(Project, models.DO_NOTHING, blank=True, null=True)
    name = models.CharField(max_length=255, blank=True, null=True)
    equipment = models.ManyToManyField(Equipment, related_name='units')

    class Meta:
        managed = False
        db_table = 'unit'

    def __str__(self):
        return self.name

    def equipment_list(self):
        return ', '.join([x.name for x in self.equipment.all()])

admin.py

class UnitAdmin(admin.ModelAdmin):
    class Meta:
        model = Unit

    # a list of displayed columns name.
    list_display = ('project', 'name', 'equipment_list')
    # define search columns list, then a search box will be added at the top of list page.
    search_fields = ['project']
    # define filter columns list, then a filter widget will be shown at right side of list page.
    list_filter = ['project', 'name']
    # define model data list ordering.
    ordering = ('project', 'name')

    def get_queryset(self, request):
        return super().get_queryset(request)\
            .select_related('project')\
            .prefetch_related('equipment')

Итак, я сделал следующие изменения:
1. Сделайте list_display кортежем вместо списка.
2. Добавьте def equipment_list(self) в класс Unit (чтобы он вызывался как атрибут Unit) и передайте (self)вместо (admin, instance) (я продолжал получать сообщение об ошибке при поиске аргумента экземпляра).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...