Я пытаюсь разработать приложение Django со встроенной логикой для временных состояний объектов. Желание состоит в том, чтобы иметь возможность иметь единственный объект, представляющий ресурс, в то время как атрибуты этого ресурса могут изменяться с течением времени. Например, желаемый вариант использования — запрашивать owner ресурса в любой момент времени (в прошлом году, вчера, завтра, в следующем году и т. д.).
Вот с чем я работаю...
class Resource(models.Model):
id = models.AutoField(primary_key=True)
class ResourceState(models.Model):
id = models.AutoField(primary_key=True)
# Link the resource this state is applied to
resource = models.ForeignKey(Resource, related_name='states', on_delete=models.CASCADE)
# Track when this state is ACTIVE on a resource
start_dt = models.DateTimeField()
end_dt = models.DateTimeField()
# Temporal fields, can change between ResourceStates
owner = models.CharField(max_length=100)
description = models.TextField(max_length=500)
Я чувствую, что мне придется создать собственный интерфейс для взаимодействия с этим состоянием. Некоторые примеры использования (интерфейс полностью в воздухе)...
# Get all of the states that were ever active on resource 1 (this is already possible)
Resource.objects.get(id=1).states.objects.all()
# Get the owner of resource 1 from the state that was active yesterday, this is non-standard behavior
Resource.objects.get(id=1).states.at(YESTERDAY).owner
# Create a new state for resource 1, active between tomorrow and infinity (None == infinity)
# This is obviously non standard if I want to enforce one-state-per-timepoint
Resource.objects.get(id=1).states.create(
start_dt=TOMORROW,
end_dt=None,
owner = "New Owner",
description = "New Description"
)
Я чувствую, что наибольшее количество пользовательской логики потребуется для создания. Я хочу обеспечить, чтобы только один ResourceState мог быть активен на Resource в любой момент времени. Это означает, что для создания одних ResourceState объектов мне нужно будет настроить/удалить другие.
>> resource = Resource.objects.get(id=1)
>> resource.states.objects.all()
[ResourceState(start_dt=None, end_dt=None, owner='owner1')]
>> resource.states.create(start_dt=YESTERDAY, end_dt=TOMORROW, owner='owner2')
>> resource.states.objects.all()
[
ResourceState(start_dt=None, end_dt=YESTERDAY, owner='owner1'),
ResourceState(start_dt=YESTERDAY, end_dt=TOMORROW, owner='owner2'),
ResourceState(start_dt=TOMORROW, end_dt=None, owner='owner1')
]
Я знаю, что мне придется проделать большую часть работы по определению логики, но есть ли интуитивно понятное место, куда я должен ее поместить? Предоставляет ли Django удобное место для создания этих методов? Если да, то где лучше всего их применять? Против объекта Resource? Использование пользовательского Manager для взаимодействия со связанными объектами «ResourceState»?
Перечитывая вышесказанное, это немного сбивает с толку, но это не простая тема! Пожалуйста, дайте мне знать, если у кого-нибудь есть идеи, как сделать что-то подобное выше!
Благодаря тонну!





слишком долго для комментария и чисто некоторых мыслей, а не полного ответа, но, имея дело со многими записями, действующими в финансовых системах (не в Django), приходят на ум некоторые вещи:
Моя интуиция заключалась бы в том, чтобы начать с включения метода сохранения модели ресурсов. Вы, вероятно, правы в том, что вам нужен собственный менеджер.
Я, вероятно, также пофлиртовал бы с идеей логического поля is_current в модели состояния, но необходимо соблюдать определенную осторожность с записями состояния, действующими в будущем. Если одновременно есть только одно активное состояние, я бы также рассмотрел необходимость конечной даты. Наличие как начала, так и конца определенно упрощает необработанные SQL-запросы (если они когда-либо понадобятся): date() between state.start and state.end <- это даст текущую запись, подписку на любую дату, чтобы получить действующую запись этой даты. Кроме того, обратите внимание на открытую дату окончания, если вы не знаете дату окончания. Ваши запросы должны будут правильно обрабатывать нули. Вероятно, вам также может понадобиться рассмотреть открытую дату начала (скажем, для загрузки исторических данных, где исходная дата начала неизвестна). Я бы посоветовал воздержаться от использования какой-то сверхранней даты в качестве заполнения (то же самое для даты в далеком будущем для неизвестных дат окончания). Если вы закончите с большим количеством транзакций, ваш оптимизатор запросов может поблагодарить вас, однако я могу быть старым, и это уже не имеет значения.
Если вам нравится читать об этом, я бы порекомендовал взглянуть на 1.8 в https://www.amazon.ca/Art-SQL-Stephane-Faroult/dp/0596008945/ и главу 6:
"But before settling for one solution, we must acknowledge that valuation tables come in all shapes and sizes. For instance, those of telecom companies, which handle tremendous amounts of data, have a relatively short price list that doesn't change very often. By contrast, an investment bank stores new prices for all the securities, derivatives, and any type of financial product it may be dealing with almost continuously. A good solution in one case will not necessarily be a good solution in another.
Handling data that both accumulates and changes requires very careful design and tactics that vary according to the rate of change."