There is no getting around the fact that Django admin inlines are built around ForeignKey
fields (or ManyToManyField
, OneToOneField
). However, if I understand your goal, it's to avoid having to manage "date integrity" between your Diary.day
and Sleep.start_time
fields, i.e., the redundancy in a foreign key relation when that relation is really defined by Diary.day == Sleep.start_time.date()
A Django ForiegnKey
field has a to_field property that allows the FK to index a column besides id
. However, as you have a DateTimeField
in Sleep
and a DateField
in Diary
, we'll need to split that DateTimeField
up. Also, a ForeignKey
has to relate to something unique on the "1" side of the relation. Diary.day
needs to be set unique=True
.
In this approach, your models look like
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()
and then your admin.py
is just
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, )
Even though Sleep.start_time
no longer has a date, the Django Admin is quite what you'd expect, and avoids "date redundancy":
Thinking ahead to a more real (and problematic) use case, say every user can have 1 Diary per day:
class Diary(models.Model):
user = models.ForeignKey(User)
day = models.DateField()
activities = models.TextField()
class Meta:
unique_together = ('user', 'day')
One would like to write something like
class Sleep(models.Model):
diary = models.ForeignKey(Diary, to_fields=['user', 'day'], on_delete=models.CASCADE)
However, there's no such feature in Django 1.11, nor can I find any serious discussion of adding that. Certainly composite foreign keys are allowed in Postgres and other SQL DBMS's. I get the impression from the Django source they're keeping their options open: https://github.com/django/django/blob/stable/1.11.x/django/db/models/fields/related.py#L621 hints at a future implementation.
Finally, https://pypi.python.org/pypi/django-composite-foreignkey looks interesting at first, but doesn't create "real" composite foreign keys, nor does it work with Django's admin.
Diary
logs what the user does in a day, andSleep
tracks when the user sleeps. Logically a "Diary entry" for a single day also contains (a list of)Sleep
objects, but I don't want to actually add aForeignKey
Sleep.diary
because then I have to keep it in sync withstart_time
andend_time
manually - i.e. overrideSleep.save()
to point to the correctDiary
object based onstart_time
andend_time
entered by the user. I don't want to change my schema for the sole purpose of making that inbuilt admin work. – Gramme