Django Many To Many Ordering
У меня есть две таблицы Subjectlist и Day. Список предметов является m2m в таблице Day. Моя проблема заключается в том, что я составляю школьное расписание. Поэтому для каждого дня должны быть показаны разные предметы, когда я добавляю предметы в каждый день, порядок предметов одинаков.
#Models.py
class SubjectList(models.Model):
subject_name = models.CharField(max_length=25)
def __str__(self):
return self.subject_name
class Day(models.Model):
day_name = models.CharField(max_length=15)
subject_name = models.ManyToManyField(SubjectList)
class_number = models.ForeignKey(AddClass, on_delete=models.CASCADE, null=True, blank=True)
start_time = models.TimeField(null=True, blank=True)
end_time = models.TimeField(null=True, blank=True)
def __str__(self):
return self.class_number.class_number
#Views.py
class TimeTableView(APIView):
def get(self, request, id):
class_number = AddClass.objects.get(id=id)
day = Day.objects.filter(class_number=class_number.id)
print(day)
serializer = DaySerializer(day, many=True)
return Response(serializer.data)
Я хочу сделать вот так
Понедельник - английский, математика, наука, обществознание Вторник - математика, обществознание, английский, математика
но у меня получается вот так
Понедельник - английский, математика, наука, обществознание Вторник - английский язык, математика, естественные науки, обществознание
оба расположены в одном порядке, даже если добавить предметы в разном порядке.
Вы можете добавить дополнительные поля в таблицу M2M, объявив модель и присвоив ее отношению M2M с помощью параметра through
class DaySubjectList(models.Model):
day = models.ForeignKey(Day, on_delete=models.CASCADE, related_name="day_subject_lists")
subject_list = models.ForeignKey(SubjectList, on_delete=models.CASCADE, related_name="day_subject_lists")
order = models.IntegerField(default=0)
class Day(models.Model):
day_name = models.CharField(max_length=15)
subject_name = models.ManyToManyField(SubjectList, through=DaySubjectList)
class_number = models.ForeignKey(AddClass, on_delete=models.CASCADE, null=True, blank=True)
start_time = models.TimeField(null=True, blank=True)
end_time = models.TimeField(null=True, blank=True)
def __str__(self):
return self.class_number.class_number
Вы можете установить поле заказа с помощью параметра through_defaults связанного менеджера
my_day.subject_name.add(my_subject, through_defaults={"position": my_position})
Вы можете заказать, используя related_name
Day.objects.filter(class_number=class_number.id).prefetch_related(Prefetch("day_subject_lists", queryset=DaySubjectList.objects.order_by("position")))
Записи будут упорядочены, только если вы обращаетесь к my_day.day_subject_lists.all(), а не my_day.subject_name.all()
.
Вы можете хранить эти записи под другим именем, если так удобнее
Day.objects.filter(class_number=class_number.id).prefetch_related(Prefetch("day_subject_lists", queryset=DaySubjectList.objects.order_by("position"), to_attr="my_prefered_name"))
обратите внимание, что my_day.my_prefered_name - это список, а не набор запросов, поэтому не используйте .all() для доступа к нему.
Если у вас есть проблемы с тем, что ваши модели ссылаются друг на друга, вы можете использовать строковый синтаксис
class DaySubjectList(models.Model):
day = models.ForeignKey("myapp.Day", on_delete=models.CASCADE, related_name="day_subject_lists")
subject_list = models.ForeignKey("myapp.SubjectList", on_delete=models.CASCADE, related_name="day_subject_lists")
order = models.IntegerField(default=0)
You need to specify an order for the m2m relation [Django-doc]:
class Day(models.Model):
# ...
subject_name = models.ManyToManyField(
SubjectList,
ordered=True
)
# ...
Now if you query a Day object, the related SubjectList objects will be ordered in the order you added these.
You can further alter the order with .move(...), or .reorder(...).
Note: You should rename the subject_name field to subjects, since it relates to multiple SubjectList objects. A ForeignKey or OneToOneField indeed often uses the _name suffix, since these relate to at most one other object, but a ManyToManyField does not have this limitation.
Note: You should not use ForeignKey(.., null=True)s. A foreign key represents a relation, and a relation can not be "NULL". You should make these fields not nullable, and make the related model have a nullable parent relation (with null=True), or make the field optional with blank=True.