Django: TypeError: '<' not supported between instances (model objects)

Django: TypeError: '<' not supported between instances (model objects)

我正在尝试将我的 Django 项目从 Python 2.7/Django 1.11 迁移到 Python 3.7/Django 2.1。

我发现了一个问题,我想了解其原因。

我的项目中有 3 个模型:

class DeviceModel(models.Model):
    name = models.CharField(max_length=255)
    pirsh = models.CharField(max_length=255)

    def __str__(self):
        return self.name + " - " + self.pirsh

class Device(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    device_model = models.ForeignKey(DeviceModel, on_delete=models.CASCADE)
    serial_number = models.CharField(max_length=255)


    def __str__(self):
        return self.device_model.name + " - " + self.device_model.pirsh + " - " \
                + self.serial_number

class DeviceTest(models.Model):
    device = models.ForeignKey(Device, on_delete=models.CASCADE)
    created_at = models.DateTimeField()

    TEST_OK = '+'
    TEST_ERROR = '-'
    TEST_PENDING = '?'
    TEST_RESULT_CHOICES = (
        (TEST_OK, 'Success'),
        (TEST_ERROR, 'Fail'),
        (TEST_PENDING, 'Not checked'),
    )
    status = models.CharField(max_length=1, choices=TEST_RESULT_CHOICES, default=TEST_PENDING)

    comment = models.TextField(blank=True, default="")
    tester = models.CharField(max_length=255)
    action = models.CharField(max_length=255)

    def save(self, *args, **kwargs):
        ''' On save, update timestamps '''
        if not self.created_at:
            self.created_at = timezone.now()
        return super(DeviceTest, self).save(*args, **kwargs)

    def __str__(self):
        return  self.device_id.device_model.name + " - " + \
                self.device_id.device_model.pirsh + " - " + \
                self.device_id.serial_number + " - " + \
                str(self.created_at) + " - " + \
                "Result (" + self.status + ")"

这是我的代码,用于按最新测试状态对 Device 个对象进行排序('dev_filter'、'field' 和 'order' 参数从 GET 请求中解析):

if (dev_filter!="") and (dev_filter!="-1"):
    device_list = Device.objects.all().filter(device_model = dev_filter)
else:
    device_list = Device.objects.all()

dev_status_list = []
for dev in device_list:
    try:
        dev_status_list.append(DeviceTest.objects.filter(device_id=dev.pk).latest('created_at').status)
    except:
        dev_status_list.append("Not checked")

device_list = [device_list for (dev_status_list, device_list) in sorted(zip(dev_status_list, device_list))]

if (order == '-'):
    device_list.reverse()

此代码在 Python 2.7/Django 1.11 中运行良好,但在 Python 3.7/Django 2.1

中运行不正常

Django 标记为错误 sorted(zip(dev_status_list, device_list)) 函数:

TypeError: '<' not supported between instances of 'Device' and 'Device'

我看到这个问题有两个解决方案:要么使用

device_list = [device_list for (dev_status_list, device_list) in sorted(zip(dev_status_list, device_list), key=lambda x: (x[0],x[1].__str__()))]

或将 __lt__ 方法添加到 Device 模型:

def __lt__(self, other):
    return self.__str__() < other.__str__()

我的问题是 - 更改了什么?这个错误是因为 Python 升级还是 Django 升级? Python 2.7/Django 1.11 框架中 Device 对象的默认排序方法是什么?我是正确的,它是字符串表示吗?我的哪个解决方案是首选?

Python 3 引入新的ordering comparison:

The ordering comparison operators (<, <=, >=, >) raise a TypeError exception when the operands don’t have a meaningful natural ordering.

一个简单的例子,它在 Python2 中打印 True 并在 Python3

中引发 TypeError
class A:
    pass

print(A() < A())

原因是因为 Python 3 简化了 rules for ordering 比较,当列表的内容是字典时,它改变了排序列表的行为。
当操作数没有有意义的自然顺序

时,排序比较运算符(<、<=、>=、>)会引发 TypeError 异常

还有一个有趣的例子

引用上面提到的例子in this link

Python 2.7

>>> [{'a':1}, {'b':2}] < [{'a':1}, {'b':2, 'c':3}]
True

Python 3.5

>>> [{'a':1}, {'b':2}] < [{'a':1}, {'b':2, 'c':3}]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: dict() < dict()

The problem is that the second elements in both lists have different keys and Python doesn't know how to compare them. In earlier Python versions this has been special cased as described here by Ned Batchelder (the author of Python's coverage tool) but in Python 3 dictionaries have no natural sort order.

您可以阅读有关该问题的更多信息 here