Django从JSON更新/创建CounterParty模型报错:仅能创建无法更新
问题:Django模型更新失败,报UUID字段类型错误
尝试从JSON字典列表中获取、更新或创建CounterParty模型对象,创建功能正常,但更新时报错:
TypeError: Tried to update field authentication.CounterParty.GUID with a model instance, <CounterParty: CounterParty object (3)>. Use a value compatible with UUIDField.
models.py 代码
class CounterParty(models.Model): GUID = models.UUIDField(default=uuid.uuid4, editable=True, unique=True) name = models.CharField(max_length=150) customer = models.BooleanField(default=False) contractor = models.BooleanField(default=False) class Meta: verbose_name_plural = 'Counter Party'
tasks.py 代码
def create_counter_party(): response = [ { "CounterpartyGUID": "e58ed763-928c-4155-bee9-fdbaaadc15f3", "CounterpartyName": "name1", "Customer": False, "Contractor": True }, { "CounterpartyGUID": "123e4567-e89b-42d3-a456-556642440000", "CounterpartyName": "name2", "Customer": False, "Contractor": False }, ] rep = response for item in rep: try: counter_party = CounterParty.objects.get(GUID=item['CounterpartyGUID']) updated_counter_party = CounterParty.objects.update(GUID=counter_party, name=item['CounterpartyName'], customer=item['Customer'], contractor=item['Contractor']) updated_counter_party.save() except CounterParty.DoesNotExist: counter_party = CounterParty.objects.create(GUID=item['CounterpartyGUID'], name=item['CounterpartyName'], customer=item['Customer'], contractor=item['Contractor']) counter_party.save()
错误栈信息
[2023-01-28 15:29:31,894: ERROR/ForkPoolWorker-8] Task authentication.tasks.create_counter_party[a86333d9-e039-479e-8d35-37fa6b17dbfa] raised unexpected: TypeError('Tried to update field authentication.CounterParty.GUID with a model instance, <CounterParty: CounterParty object (3)>. Use a value compatible with UUIDField.') Traceback (most recent call last): File "/home/zesshi/.local/lib/python3.9/site-packages/celery/app/trace.py", line 451, in trace_task R = retval = fun(*args, **kwargs) File "/home/zesshi/.local/lib/python3.9/site-packages/celery/app/trace.py", line 734, in __protected_call__ return self.run(*args, **kwargs) File "/mnt/c/Users/Shalltear/Desktop/Python/unica_django/authentication/tasks.py", line 27, in create_counter_party counter_party = CounterParty.objects.update(GUID=counter_party, name=item['CounterpartyName'], File "/home/zesshi/.local/lib/python3.9/site-packages/django/db/models/manager.py", line 85, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "/home/zesshi/.local/lib/python3.9/site-packages/django/db/models/query.py", line 1191, in update rows = query.get_compiler(self.db).execute_sql(CURSOR) File "/home/zesshi/.local/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1822, in execute_sql cursor = super().execute_sql(result_type) File "/home/zesshi/.local/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1385, in execute_sql sql, params = self.as_sql() File "/home/zesshi/.local/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1782, in as_sql raise TypeError( TypeError: Tried to update field authentication.CounterParty.GUID with a model instance, <CounterParty: CounterParty object (3)>. Use a value compatible with UUIDField.
解决方案
错误根源:你使用CounterParty.objects.update()时,错误地将模型实例counter_party传给了GUID字段——该字段需要UUID格式的字符串/UUID对象,而非模型实例。另外,objects.update()是批量更新方法,你已经拿到了单个实例,直接修改属性再保存即可。
修改后的tasks.py代码
def create_counter_party(): response = [ { "CounterpartyGUID": "e58ed763-928c-4155-bee9-fdbaaadc15f3", "CounterpartyName": "name1", "Customer": False, "Contractor": True }, { "CounterpartyGUID": "123e4567-e89b-42d3-a456-556642440000", "CounterpartyName": "name2", "Customer": False, "Contractor": False }, ] for item in response: try: # 获取已存在的实例 counter_party = CounterParty.objects.get(GUID=item['CounterpartyGUID']) # 直接修改实例属性 counter_party.name = item['CounterpartyName'] counter_party.customer = item['Customer'] counter_party.contractor = item['Contractor'] # 保存修改 counter_party.save() except CounterParty.DoesNotExist: # 创建新实例 CounterParty.objects.create( GUID=item['CounterpartyGUID'], name=item['CounterpartyName'], customer=item['Customer'], contractor=item['Contractor'] )
更简洁的写法(推荐)
用get_or_create减少重复逻辑:
def create_counter_party(): response = [ { "CounterpartyGUID": "e58ed763-928c-4155-bee9-fdbaaadc15f3", "CounterpartyName": "name1", "Customer": False, "Contractor": True }, { "CounterpartyGUID": "123e4567-e89b-42d3-a456-556642440000", "CounterpartyName": "name2", "Customer": False, "Contractor": False }, ] for item in response: # 不存在则创建,存在则返回已有实例 counter_party, created = CounterParty.objects.get_or_create( GUID=item['CounterpartyGUID'], defaults={ 'name': item['CounterpartyName'], 'customer': item['Customer'], 'contractor': item['Contractor'] } ) # 非新创建的实例才更新属性 if not created: counter_party.name = item['CounterpartyName'] counter_party.customer = item['Customer'] counter_party.contractor = item['Contractor'] counter_party.save()
内容的提问来源于stack exchange,提问作者Zesshi
相关产品推荐
相关产品推荐

