【问题标题】:Django Sort ManyToMany Field in A Nonsignificant OrderDjango 以不重要的顺序对多对多字段进行排序
【发布时间】:2016-11-24 05:42:06
【问题描述】:

我有两个模型如下:

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 对象是有序的。问题是,没有重要的过滤器可以排序,例如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] 返回一个以A 开头的Stop 实例,并且排序类似。

那么,有没有办法像 Python 中的 list 一样订购?就像,没有重要的意义,你只是追加到最后并返回。


环境

  • python 3.5.1
  • django 1.9.7
  • djangorestframework 3.3.3
  • psycopg2 2.6.2
  • postgresql 9.5

【问题讨论】:

  • 如果您在Stop 型号上加上时间戳,那么您可以根据该时间戳订购。
  • 问题是,Stop 实例可能属于多个 Route 对象。所以即使我给它加上时间戳,Stop 实例的timestamp 字段也会在构建另一个Route 实例时发生变化。

标签: python django python-3.x orm manytomanyfield


【解决方案1】:

stopposition 相对于 Route,例如route 1 可以是第一站,route 2 可以是第二站等等。所以这是一个完美的例子,你需要更多关于Route-Stop 关系的metadata。 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 时,您可以通过RouteStop.position 订购route.stops,类似于:

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

【讨论】:

  • 您的route = models.ForeignKey(Stop) 行应该是route = models.ForeignKey(Route) 吗?或者也许我错了,代码是有效的?
  • 当我尝试迁移时它也会引发:ValueError: Cannot alter field izmir.Route.stops into izmir.Route.stops - they are not compatible types (you cannot alter to or from M2M fields, or add or remove through= on M2M fields)
  • 是的,应该是Route(很明显是错字)。关于迁移,它不会自动发生,您需要创建一个data migration
猜你喜欢
  • 2018-08-06
  • 2021-11-05
  • 1970-01-01
  • 2010-11-22
  • 1970-01-01
  • 1970-01-01
  • 2019-04-10
  • 1970-01-01
  • 2011-09-14
相关资源
最近更新 更多