2016-07-20 2 views
0

У меня есть две модели, как показано ниже:Джанго Сортировка ManyToMany поле в недостоверный ордена

class Stop(models.Model): 
    """ 
    Showing bus stops in İzmir. 
    """ 

    code = models.PositiveIntegerField(
     unique=True, 
     primary_key=True, 
     verbose_name="Code" 
    ) 

    label = models.CharField(
     null=False, 
     blank=False, 
     max_length=64, 
     verbose_name="Label" 
    ) 

    coor = ArrayField(
     models.FloatField(), 
     size=2, 
     verbose_name="Coordination" 
    ) 

    class Meta: 
     verbose_name = "Stop" 
     verbose_name_plural = "Stops" 
     ordering = ["label"] 

    def __str__(self): 
     return self.label 

class Route(models.Model): 
    """ 
    Bus routes of İzmir. 
    """ 

    code = models.PositiveSmallIntegerField(
     unique=True, 
     primary_key=True, 
     verbose_name="Code" 
    ) 

    stops = models.ManyToManyField(
     Stop, 
     null=True, 
     blank=True, 
     related_name="routes", 
     verbose_name="Stops" 
    ) 

    terminals = ArrayField(
     models.CharField(
      null=False, 
      blank=False, 
      max_length=32, 
     ), 
     size=2, 
     default=[], 
     verbose_name="Terminals" 
    ) 

    departure_times = ArrayField(
     ArrayField(
      models.TimeField(
       null=False, 
       blank=False 
      ), 
      null=True, 
      default=[] 
     ), 
     default=[], 
     size=6, 
     verbose_name="Departure Times" 
    ) 

    class Meta: 
     verbose_name = "Route" 
     verbose_name_plural = "Routes" 
     ordering = ["code"] 

    def __str__(self): 
     return "{}: {} - {}".format(str(self.code), self.terminals[0], self.terminals[1]) 

Как вы можете видеть, Route имеет ManyToManyFields, который принимает Stop экземпляров.

Я поместил экземпляры со сценарием, который он обрывает пару веб-страниц, кажется, я буду использовать crontab, чтобы они обновлялись. В данных я очищаю, Stop объектов заказываются. Дело в том, что нет значительного фильтра для сортировки, например. a Stop экземпляр приходит за другим.

Django (или Django Rest Framework) возвращает Stop экземпляры Route экземпляра в алфавитном порядке, например.

{ 
    "code": 285, 
    "terminals": [ 
     "EVKA 1", 
     "KONAK" 
    ], 
    "stops": [ 
     40586, 
     40633, 
     12066, 
     40645, 
     40627, 
     40647, 
     40588, 
     40592, 
     40623, 
     40016, 
     40506, 
     40508, 
     40528, 
     40462, 
     40631, 
     40014, 
     40619, 
     40530, 
     12060, 
     40661, 
     40504, 
     40488, 
     40653, 
     40590, 
     40512, 
     40464, 
     10240, 
     10036, 
     12068, 
     40514, 
     40510, 
     40658, 
     40002, 
     40649, 
     12070, 
     40004, 
     40010, 
     40656, 
     12064, 
     40614, 
     40012 
    ], 
    ... 
} 

В каких stops[0] возвращает Stop экземпляр начиная с A и родов, как это.

Итак, есть способ заказать как list в Python? Например, нет существенного момента, вы просто добавляете его в конец и возвращаете так.


среда

  • Python 3.5.1
  • Джанго 1.9.7
  • djangorestframework 3.3.3
  • psycopg2 2.6.2
  • PostgreSQL 9.5
+0

Если поставить отметку времени на модели 'Stop', то вы можете заказать на основе этого штамп времени , –

+0

Дело в том, что экземпляр «Stop» может принадлежать более чем одному объекту Route. Поэтому, даже если я установил отметку времени, поле 'timestamp' экземпляра' Stop' изменилось бы, когда возникнет необходимость в создании другого экземпляра 'Route'. –

ответ

1

position из stop относится к Route, например. одна остановка может быть первой для route 1, вторая для route 2 и т. д. Так что это прекрасный пример того, что вам нужно больше metadata об отношении Route-Stop. Djagno решает это, предоставив вам Intermediate Table двумя ForeignKey и metadata, которые вам нужны для отношения.

class Stop(models.Model): 
    #... 

class Route(models.Model): 

    #... 

    stops = models.ManyToManyField(Stop, through='RouteStop', blank=True, related_name="routes", verbose_name="Stops") 


class RouteStop(models.Model): 
    stop = models.ForeignKey(Stop) 
    route = models.ForeignKey(Route) 
    position = models.PositiveSmallIntegerField() 

    class Meta: 
     unique_together = (("stop", "route"),) 

Теперь, когда вы получаете Routes вы можете заказать route.stops по RouteStop.position, что-то вроде:

Route.objects.all().prefetch_related(
    Prefetch('stops', queryset=Stop.objects.all().order_by('routestop__position')) 
) 
+0

Если ваша 'route = models.ForeignKey (Stop)' строка будет 'route = models.ForeignKey (Route)'? Или, может быть, я ошибаюсь, и код действительно? –

+0

Он также возникает при попытке миграции: 'ValueError: не может изменить поле izmir.Route.stops в izmir.Route.stops - они не совместимы (вы не можете изменять или из полей M2M или добавлять или удалять через = on M2M) ' –

+0

Да, это должно быть' Route' (опечатка четко). О миграции не произойдет автоматически, вам нужно будет сделать [миграцию данных] (http://stackoverflow.com/questions/33257530/how-to-add-through-option-to-existing-manytomanyfield- с-миграций-и-данных я) – Todor