web-dev-qa-db-ja.com

外部キー関係のないインライン管理者

外部キー関係が存在しない場合に、インラインで表示する関連オブジェクトのセットを手動で指定することは可能ですか?

# Parent
class Diary(models.Model):
    day = models.DateField()
    activities = models.TextField()

# Child
class Sleep(models.Model):
    start_time = models.DateTimeField()
    end_time = models.DateTimeField()

class SleepInline(admin.TabularInline):
    model=Sleep
    def get_queryset(self, request):
        # Return all Sleep objects where start_time and end_time are within Diary.day
        return Sleep.objects.filter(XXX) 

class DiaryAdmin(admin.ModelAdmin):
    inlines = (SleepInline, )

Diaryモデル管理者にstart_timeDiary.dayと同じ日に等しいSleepモデルのインラインを表示させたい。問題は、SleepモデルにForeignKeyからDiaryがないことです(代わりに、日付の使用によって関係が暗黙的に示されます)。

上記を使用すると、Djangoはすぐに次のように文句を言います

<class 'records.admin.SleepInline'>: (admin.E202) 'records.Sleep' has no ForeignKey to 'records.Diary'.

関連するSleepインスタンスをDiary管理ページにインラインで表示するにはどうすればよいですか?

12
Flash

まず、ロジックの欠点を説明します。

  • 外部キーを追加する場合、関係を調整する必要がある珍しい2つの操作があります。それは、新しいスリープオブジェクトの作成と、スリープオブジェクトの時刻の更新です。
  • 外部キーを使用しない場合、日記が要求されるたびに、対応するスリープオブジェクトのルックアップを実行する必要があります。日記を読むことは、そこにあるほとんどのプロジェクトで行われるように、睡眠オブジェクトの変更よりもはるかに一般的であると思います。

お気づきのように、追加の欠点は、リレーショナル機能を使用できないことです。 InlineAdminはリレーショナル機能であるため、「管理者を機能させる」と言うのと同じように、ボルトを緩めるためにハンマーを要求する必要があります。

しかし...管理者はModelFormを利用します。したがって、 formset (同じ理由でインラインフォームセットにすることはできません)を使用してフォームを作成し、そのフォームセットを自分で保存する場合は、可能であるはずです。 InlineFormsetとInlineAdminの要点は、関連するモデルからのフォームセットの生成を容易にすることであり、そのためには関係を知る必要があります。

そして最後に、 rlsを追加 してカスタムページを作成できます。admin/ base.htmlテンプレートを拡張すると、レイアウトとjavascriptコンポーネントにアクセスできるようになります。

2
Melvyn

Django adminインラインがForeignKeyフィールド(またはManyToManyFieldOneToOneField)を中心に構築されているという事実を回避することはできません。私はあなたの目標を理解しています。_Diary.day_フィールドと_Sleep.start_time_フィールドの間の「日付の整合性」を管理する必要がないようにすることです。つまり、外部キー関係が実際にDiary.day == Sleep.start_time.date()

Django ForiegnKeyフィールドには to_fieldプロパティ があり、FKはid以外の列にインデックスを付けることができます。ただし、 DateTimeFieldSleepDateFieldDiaryの場合、そのDateTimeFieldを分割する必要があります。また、ForeignKeyは、関係の「1」側で一意の何かに関連している必要があります。_Diary.day_は_unique=True_に設定する必要があります。

このアプローチでは、モデルは次のようになります。

_from Django.db import models

# Parent
class Diary(models.Model):
    day = models.DateField(unique=True)
    activities = models.TextField()

# Child
class Sleep(models.Model):
    diary = models.ForeignKey(Diary, to_field='day', on_delete=models.CASCADE)
    start_time = models.TimeField()
    end_time = models.DateTimeField()
_

そしてあなたの_admin.py_はただ

_from Django.contrib import admin
from .models import Sleep, Diary

class SleepInline(admin.TabularInline):
    model=Sleep

@admin.register(Diary)
class DiaryAdmin(admin.ModelAdmin):
    inlines = (SleepInline, )
_

_Sleep.start_time_に日付がなくなったとしても、Django Adminはあなたが期待するものであり、「日付の冗長性」を回避します。

Django Admin: Diary


より現実的な(そして問題のある)ユースケースを前もって考えて、すべてのユーザーが1日に1つの日記を持つことができると言います。

_class Diary(models.Model):
    user = models.ForeignKey(User)
    day = models.DateField()
    activities = models.TextField()

    class Meta:
        unique_together = ('user', 'day')
_

次のようなものを書きたい

_class Sleep(models.Model):
    diary = models.ForeignKey(Diary, to_fields=['user', 'day'], on_delete=models.CASCADE)
_

ただし、Django 1.11にはそのような機能はなく、それを追加することについての真剣な議論も見つかりません。確かに、Postgresやその他のSQLDBMSでは複合外部キーが許可されています。=から印象を受けます。 Djangoソースはオプションを開いたままにしています: https://github.com/Django/django/blob/stable/1.11.x/Django/db/models/fields/ related.py#L621 将来の実装を示唆しています。

最後に、 https://pypi.python.org/pypi/Django-composite-foreignkey 最初は面白そうに見えますが、「実際の」複合外部キーを作成せず、Djangoの管理者とも連携しません。 。

6
rm -rf

これは、Nested_adminライブラリを使用して実現できます。だからmyapp/admin.py

from nested_admin.nested import NestedStackedInline, NestedModelAdmin

class SleepInline(NestedStackedInline):

    model = Sleep

class DiaryAdmin(NestedModelAdmin):

   inlines = [SleepInline]
0
nativelectronic