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)
        

Я хочу сделать вот так

Понедельник - английский, математика, наука, обществознание Вторник - математика, обществознание, английский, математика

но у меня получается вот так

Понедельник - английский, математика, наука, обществознание Вторник - английский язык, математика, естественные науки, обществознание

enter image description here

оба расположены в одном порядке, даже если добавить предметы в разном порядке.

Вы можете добавить дополнительные поля в таблицу 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.
Вернуться на верх