我正在尝试将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
个对象进行排序(从GET请求中解析了'dev_filter','field'和'order'参数):
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
对象的默认排序方法是什么?我是否正确,它是字符串表示形式?而我的哪种解决方案是首选?
答案 0 :(得分:2)
Python 3引入了新的ordering comparison:
当操作数没有有意义的自然排序时,排序比较运算符(<,<=,> =,>)会引发 TypeError 异常。
一个简单的示例,该示例在Python2中打印True
,在Python3中引发TypeError
class A:
pass
print(A() < A())
答案 1 :(得分:0)
原因是因为 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()
问题在于两个列表中的第二个元素都不同 键和Python不知道如何比较它们。在早期的Python中 内德(Ned)特别将此版本命名为described here Batchelder(Python覆盖工具的作者),但在Python 3中 字典没有自然的排序顺序。
您可以详细了解问题here。