没有外键关系的管理员内联

新手上路,请多包涵

是否可以手动指定要在内联中显示的相关对象集,其中不存在外键关系?

 # 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, )

我想要我的 start_time Diary 模型管理员以显示 SleepDiary.day ,问题是 Sleep 模型没有 ForeignKeyDiary (相反,关系的使用是隐含的)。

使用以上内容,Django 立即抱怨说

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

如何在 Diary 管理页面上将相关的 Sleep 实例显示为内联?

原文由 Flash 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 283
2 个回答

让我首先向您展示您的逻辑的缺点:

  • 添加外键时,有 2 个不常见的操作需要调整关系:创建一个新的睡眠对象并更新睡眠对象的时间。
  • 当不使用外键时,每次请求日记时,都需要查找相应的 Sleep 对象。我假设阅读日记比改变睡眠对象更常见,因为它会出现在大多数项目中。

正如您所注意到的,另一个缺点是您不能使用关系特性。 InlineAdmin 是一个相关的功能,所以正如您所说的“让管理员工作”一样,实际上您需要一把锤子来拧开螺栓。

但是…管理员使用 ModelForm。因此,如果您使用表单集构建 表单(出于同样的原因,它不能是内联表单集)并自己处理保存该表单集,那应该是可能的。 InlineFormset 和 InlineAdmin 的全部要点是使从相关模型生成表单集更容易,为此它需要知道关系。

最后,您可以 添加 url 并构建自定义页面,并且在扩展 admin/base.html 模板时,您将可以访问布局和 javascript 组件。

原文由 user1600649 发布,翻译遵循 CC BY-SA 3.0 许可协议

无法回避 Django 管理内联是围绕 ForeignKey 字段构建的事实(或 ManyToManyFieldOneToOneField ).但是,如果我理解你的目标,这是为了避免必须管理你的 Diary.daySleep.start_time 字段之间的“日期完整性”,即当该关系是真正定义为 Diary.day == Sleep.start_time.date()

Django ForiegnKey 字段具有 to_field 属性,允许 FK 索引除 id 之外的列。 However, as you have a DateTimeField in Sleep and a DateField in Diary , we’ll need to split that DateTimeField 向上。此外,a 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 管理员:日记


提前考虑一个更真实(和有问题)的用例,假设每个用户每天可以有 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 和其他 SQL DBMS 中是允许的。我从 Django 源代码中得到了他们保持选项开放的印象: https ://github.com/django/django/blob/stable/1.11.x/django/db/models/fields/related.py#L621 hints在未来的实施中。

最后, https://pypi.python.org/pypi/django-composite-foreignkey 一开始看起来很有趣,但它不会创建“真正的”复合外键,也不适用于 Django 的管理员。

原文由 rm -rf 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
logo
Stack Overflow 翻译
子站问答
访问
宣传栏