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。
我正在尝试将我的 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 比较,当列表的内容是字典时,它改变了排序列表的行为。
当操作数没有有意义的自然顺序
还有一个有趣的例子
引用上面提到的例子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。