Как показать отношения в Django Admin - PullRequest
0 голосов
/ 26 апреля 2019

Я использую Django 2.1, и мне трудно понять, как показать отношения в Admin. У меня есть две Больницы Моделей и Единицы, и третий - Экзамены. Они устанавливаются таким образом, у Больницы может быть много Единиц, и одна Единица принадлежит одной Больнице. А модель Exam имеет атрибуты экзаменов, такие как название экзамена и название больницы.

class Hospital(models.Model):

    name = models.CharField(max_length=200)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.name

class Unit(models.Model):

    unit_name = models.CharField(max_length=200)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    parent_company = models.ForeignKey(
        Hospital, related_name='unit_parent', on_delete=models.CASCADE, verbose_name="Hospital")


class Exam(models.Model):

    unit_name = models.ForeignKey(
        Hospital, related_name='hospital_pk', on_delete=models.CASCADE)
    exam_name = models.CharField(max_length=255, blank=True,
                                 null=True, verbose_name="Exam's name")
    date = models.DateField()
    time = models.TimeField()

    def __str__(self):
        return self.exam_name


class CustomExamAdmin(admin.ModelAdmin):

    model = Exam
    list_display = ('exam_name', 'time', 'alert',
                    'document', 'notes', 'report', 'patients_name', 'unit_name')
    list_filter = ('exam_name', 'time')
    list_select_related = ('unit_name',)
    fieldsets = (
        ("Hospital's Name:", {
            'fields': ('unit_name',)}),
        ('Types of Exams:', {
            'fields': ('exam_name', 'modality', 'model_used')}),
        ("Patient's name:", {
            'fields': ('patients_name',)}),
     )

Итак, на странице «Экзамены» администратора я могу выбрать название больницы, но не могу выбрать единицу, принадлежащую больнице. Мне нужно выбрать больницу, а также подразделение, которое ей принадлежит. Должен ли я добавить еще один иностранный ключ к экзаменам, как это: unit_selected = models.ForeignKey ( Unit, related_name = 'unit_pk', on_delete = models.CASCADE)

Например: Больница: Университетская больница Брукдейла Единица: Центр города Единица

Что я получаю: введите описание изображения здесь

1 Ответ

0 голосов
/ 26 апреля 2019

Чтобы выбрать Unit в Admin, необходимо сначала добавить его в модель Exam. У вас есть поле с именем unit_name, но вы определили его как внешний ключ для модели Hospital, а не для модели Unit. Если у вас есть поле unit_name, вам не нужно отдельное поле hospital, поскольку вы можете легко получить его из unit_name.parent_company. Так что вы можете сделать это:

class Exam(models.Model):

    unit_name = models.ForeignKey(
        Unit, related_name='exams', on_delete=models.CASCADE)
    exam_name = models.CharField(max_length=255, blank=True,
                                 null=True, verbose_name="Exam's name")
    date = models.DateField()
    time = models.TimeField()

    def __str__(self):
        return self.exam_name

Для администратора, вместо того, чтобы выбирать больницу и отделение отдельно, на мой взгляд, самый простой подход состоит в том, чтобы включать название больницы как часть названия отделения при его выборе в администраторе, например Brookdale University Hospital|Downtown Unit. Таким образом, вам нужно только одно раскрывающееся поле. Вы можете сделать это так:

from django import forms


class UnitChoiceField(forms.ModelChoiceField):
     def label_from_instance(self, obj):
         return "{}|{}".format(obj.parent_company.name, obj.unit_name)


class CustomExamAdmin(admin.ModelAdmin):

    model = Exam
    list_display = ('exam_name', 'time', 'alert',
                    'document', 'notes', 'report', 'patients_name', 'get_hospital', 'unit_name')
    list_filter = ('exam_name', 'time')
    list_select_related = ('unit_name__parent_company',)
    fieldsets = (
        ("Hospital's Name:", {
            'fields': ('unit_name',)}),
        ('Types of Exams:', {
            'fields': ('exam_name', 'modality', 'model_used')}),
        ("Patient's name:", {
            'fields': ('patients_name',)}),
     )

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'unit_name':
            return UnitChoiceField(
                queryset=Unit.objects.all().select_related('parent_company').order_by(
                'parent_company.name', 'unit_name'))
        return super().formfield_for_foreignkey(db_field, request, **kwargs)

    def get_hospital(self, obj):
    #  required to add hospital name to list_display
        return obj.unit_name.parent_company.name           
    get_hospital.short_description = 'Hospital'

Еще одно примечание: related_name в ForeignKeyField - это отношение внешней модели к модели, которую вы определяете. Так в Unit модели

parent_company = models.ForeignKey(
    Hospital, related_name='unit_parent', on_delete=models.CASCADE, verbose_name="Hospital")

должно быть

 parent_company = models.ForeignKey(
    Hospital, related_name='units', on_delete=models.CASCADE, verbose_name="Hospital")

Тогда из модели Hospital вы можете ссылаться на список единиц измерения как units.

...