У меня есть три модели, которые связаны друг с другом. Первый называется DayOfWeek, который является ярлыком в день и номером. Это выглядит следующим образом:Django Многие многие жалуются на PrimaryKey
class DayOfWeek(models.Model):
day = models.IntegerField()
label = models.CharField(max_length='20')
def __str__(self):
return self.label
Этот класс заполняется с помощью прибор каждый раз, когда я syncdb.Next, у меня есть модель событий, это выглядит следующим образом:
class Event(AnnouncementBase, Location):
cost = CurrencyField(decimal_places=2, max_digits=10, blank=True, default=0.00)
start_date = models.DateField(default = datetime.now().date())
start_time = models.TimeField(default = datetime.now().time())
end_date = models.DateField(blank=True, default=None, null = True)
end_time = models.TimeField(blank=True, default=None, null = True)
Наконец, есть повторение , Он имеет событие и используется для планирования события для повторяющихся событий. Это выглядит следующим образом:
class Recurrence(models.Model):
event = models.ForeignKey(Event, related_name='event')
repeats = models.CharField(max_length = 50, choices = EVENT_REPEAT_CHOICES)
repeat_every = models.IntegerField(default = 1)
repeat_on = models.ManyToManyField(DayOfWeek, blank=True, null=True)
repeat_by = models.CharField(max_length = 50, choices = EVENT_REPEAT_BY_CHOICES, blank=True)
repeat_by_day_of_month = models.IntegerField(default = 0, blank=True)
repeat_ends = models.CharField(max_length = 50, choices = EVENT_REPEAT_END_CHOICES)
end_occurrences = models.IntegerField(default = 0, blank=True)
repeat_end_date = models.DateField(blank=True, default=None, null = True)
past_event_count = models.IntegerField(default=0, blank=True)
scheduled_events = models.ManyToManyField(Event, blank=True, default=None, related_name = 'scheduled_events')
is_active = models.BooleanField(blank=True, default=True)
def save(self, force_insert=False, force_update=False, using=None):
"""Overridden to create events the first time."""
self.full_clean()
#First do normal save so the data is there for the even scheduler.
self.save_base(force_insert=force_insert, force_update=force_update, using=using)
#If nothing is scheduled yet, schedule the first batch
if self.scheduled_events.count() == 0 and self.past_event_count == 0:
self.scheduleEvents()
def clean(self):
#repeat on weekly
if self.repeat_every < 1:
raise ValidationError('Repeat every must be at least 1.')
#weekly
if self.repeats == EVENT_REPEAT_CHOICES[1][0]:
#look for missing stuff
if not self.repeat_on:
raise ValidationError('Missing repeat on.')
Наконец, у меня есть модульный тест, который проверяет это работает нормально, это выглядит следующим образом:
def test_weekly_mon_wed_fri_occurrence(self):
event = Event()
event.start_date = date(year=2012, month=1, day=2)
event.start_time = time(hour=13, minute=30)
event.save()
recurrence = Recurrence()
recurrence.repeats = EVENT_REPEAT_CHOICES[1][0]
recurrence.repeat_on = (EVENT_DAY_CHOICES[1][0], EVENT_DAY_CHOICES[3][0], EVENT_DAY_CHOICES[5][0])
recurrence.repeat_ends = EVENT_REPEAT_END_CHOICES[0][0]
recurrence.event = event
nextEvent = recurrence.getNextEvent(event)
self.assertEquals(date(year=2012, month=1, day=4), nextEvent.start_date)
self.assertEquals(event.start_time, nextEvent.start_time)
nextNextEvent = recurrence.getNextEvent(nextEvent)
self.assertEquals(date(year=2012, month=1, day=6), nextNextEvent.start_date)
self.assertEquals(event.start_time, nextNextEvent.start_time)
Всякий раз, когда тест запускается он выходит из строя, за исключением следующего. ValueError: экземпляр «Recurrence» должен иметь значение первичного ключа, прежде чем использовать отношения «многие-ко-многим».
Ошибка возникает на линии, если self.repeat_on в чистом методе.
Я хочу, чтобы repeat_on был факультативным, нужны только некоторые типы повторений. Как это сделать? Что мне не хватает, что приводит к его провалу?
Я еще не дома, чтобы попробовать это, но у меня есть один вопрос. Сохранение вызовов повторения чистое, что вызвало ошибку. Кроме того, даже если это не вызвало эту ошибку, это приведет к тому, что сообщение очистит сообщение об ошибке проверки. В некоторых случаях требуется значение repeat_on. Как я могу проверять те, которые не нарушают его, когда repeat_on не требуется? Первый вызов сохранения всегда не подтверждается, не так ли? – Jon
Вы правы, и это ограничение отношений M2M в Django. Обратите внимание, что как модель, так и форма имеют свои собственные чистые методы. Модель 'clean' должна быть самодостаточной и проверять только данные, лежащие на этой модели. Вы можете либо реализовать свою собственную таблицу M2M, используя 'through' на Many2ManyField, и добавить' clean' в модель промежуточного продукта и самостоятельно сохранить внешние ключи, или то, что, как мне кажется, вам лучше подойдет, используйте Form, чтобы сначала проверить запрос в целом. – astevanovic