Django中QuerySet无client属性异常排查及解决方案咨询
问题:'QuerySet' object has no attribute 'client' 异常解决
异常描述
遇到异常:'QuerySet' object has no attribute 'client',其中client是Master模型中关联Client的外键(一对多关系),需求是无记录则创建,有记录则更新。
相关日志
2023-09-25 10:29:25,768 - facebookapi.fetchMetadata - CRITICAL - about to save to master 2023-09-25 10:29:25,771 - facebookapi.fetchMetadata - CRITICAL - Master exists now update... 2023-09-25 10:29:25,773 - facebookapi.fetchMetadata - CRITICAL - _master.save() Exception: 'QuerySet' object has no attribute 'client'
模型定义
class Client(models.Model): id = models.BigAutoField(primary_key=True), name = models.CharField(max_length=200, blank=False, null=True) # more fields abbreviated class Master(models.Model): id = models.BigAutoField(primary_key = True) client = models.ForeignKey(Client, on_delete=models.CASCADE) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) user_metadata = models.JSONField(max_length=5000, null=True, blank=True) user_id = models.CharField(max_length=500, blank=False, null = True) user_name = models.CharField(max_length=500, blank=False, null = True) # more fields abbreviated
报错代码
logger.critical("about to save to master+++++++++++++++++++++OOOOOOOOOOOO+++++++++++++") try: _master = Master.objects.filter(client=client_fk) if _master is None: logger.critical("Master does not exist now create...") new_master = Master.objects.create() new_master.client = client_fk new_master.user_id = user_id new_master.user_name = result["name"] new_master.user_apprequests = _connections1["apprequests"] new_master.user_business_users = _connections1["business_users"] new_master.user_businesses = _connections1["businesses"] new_master.user_accounts = _connections1["accounts"] new_master.user_adaccounts = _connections1["adaccounts"] new_master.user_assigned_ad_accounts = _connections1["assigned_ad_accounts"] new_master.user_assigned_pages = _connections1["assigned_pages"] new_master.user_permissions = _connections1["permissions"] new_master.user_personal_ad_accounts = _connections1["personal_ad_accounts"] new_master.user_metadata = result["metadata"] new_master.account_status = "created" new_master.save() else: logger.critical("Master exists now update...") logger.critical("Master.client: %s", _master.client) #_master.client = client_fk _master.user_id = user_id _master.user_name = result["name"] _master.user_apprequests = _connections1["apprequests"] _master.user_business_users = _connections1["business_users"] _master.user_businesses = _connections1["businesses"] _master.user_accounts = _connections1["accounts"] _master.user_adaccounts = _connections1["adaccounts"] _master.user_assigned_ad_accounts = _connections1["assigned_ad_accounts"] _master.user_assigned_pages = _connections1["assigned_pages"] _master.user_permissions = _connections1["permissions"] _master.user_personal_ad_accounts = _connections1["personal_ad_accounts"] _master.user_metadata = result["metadata"] new_master.account_status = "updated" _master.save() return Response("Master saved", status=status.HTTP_200_OK) except Exception as e: logger.critical("_master.save() Exception: %s", e) return Response(e, status=status.HTTP_400_BAD_REQUEST)
已尝试方案
- 将过滤条件改为
client_id,修改模型将client改为client_id并迁移,报错找不到client_id_id - 移除外键再重新添加并迁移,无效
解决方案
核心问题分析
filter()返回QuerySet而非单个对象:Master.objects.filter(client=client_fk)返回的是符合条件的所有记录集合(QuerySet),不是单个Master实例,所以直接访问_master.client会报错,且QuerySet没有save()方法。- 判断条件错误:QuerySet永远不会等于
None,即使没有匹配记录,它也是空的QuerySet,所以if _master is None永远为False,会直接进入更新分支。
修复步骤
不需要创建新模型、删除迁移或放弃外键,直接修改代码即可:
方法1:使用get()配合异常处理(适合唯一记录场景)
如果每个Client对应唯一的Master记录,用get()获取单个对象,捕获DoesNotExist异常来创建新记录:
from django.core.exceptions import ObjectDoesNotExist logger.critical("about to save to master+++++++++++++++++++++OOOOOOOOOOOO+++++++++++++") try: # 获取单个Master对象,不存在则抛出异常 _master = Master.objects.get(client=client_fk) logger.critical("Master exists now update...") # 更新字段 _master.user_id = user_id _master.user_name = result["name"] _master.user_apprequests = _connections1["apprequests"] _master.user_business_users = _connections1["business_users"] _master.user_businesses = _connections1["businesses"] _master.user_accounts = _connections1["accounts"] _master.user_adaccounts = _connections1["adaccounts"] _master.user_assigned_ad_accounts = _connections1["assigned_ad_accounts"] _master.user_assigned_pages = _connections1["assigned_pages"] _master.user_permissions = _connections1["permissions"] _master.user_personal_ad_accounts = _connections1["personal_ad_accounts"] _master.user_metadata = result["metadata"] _master.account_status = "updated" _master.save() except ObjectDoesNotExist: logger.critical("Master does not exist now create...") # 创建新记录,一次性赋值更高效 _master = Master.objects.create( client=client_fk, user_id=user_id, user_name=result["name"], user_apprequests=_connections1["apprequests"], user_business_users=_connections1["business_users"], user_businesses=_connections1["businesses"], user_accounts=_connections1["accounts"], user_adaccounts=_connections1["adaccounts"], user_assigned_ad_accounts=_connections1["assigned_ad_accounts"], user_assigned_pages=_connections1["assigned_pages"], user_permissions=_connections1["permissions"], user_personal_ad_accounts=_connections1["personal_ad_accounts"], user_metadata=result["metadata"], account_status="created" ) except Exception as e: logger.critical("_master.save() Exception: %s", e) return Response(str(e), status=status.HTTP_400_BAD_REQUEST) return Response("Master saved", status=status.HTTP_200_OK)
方法2:使用update_or_create(Django内置简洁方案)
Django提供的update_or_create方法直接实现“无则创建,有则更新”逻辑:
logger.critical("about to save to master+++++++++++++++++++++OOOOOOOOOOOO+++++++++++++") try: # 用client作为匹配条件,defaults为要更新的字段 _master, created = Master.objects.update_or_create( client=client_fk, defaults={ 'user_id': user_id, 'user_name': result["name"], 'user_apprequests': _connections1["apprequests"], 'user_business_users': _connections1["business_users"], 'user_businesses': _connections1["businesses"], 'user_accounts': _connections1["accounts"], 'user_adaccounts': _connections1["adaccounts"], 'user_assigned_ad_accounts': _connections1["assigned_ad_accounts"], 'user_assigned_pages': _connections1["assigned_pages"], 'user_permissions': _connections1["permissions"], 'user_personal_ad_accounts': _connections1["personal_ad_accounts"], 'user_metadata': result["metadata"], 'account_status': "created" } ) # 更新状态:如果是已存在的记录,将状态改为updated if not created: _master.account_status = "updated" _master.save() except Exception as e: logger.critical("_master.save() Exception: %s", e) return Response(str(e), status=status.HTTP_400_BAD_REQUEST) return Response("Master saved", status=status.HTTP_200_OK)
额外注意点
- 模型
Client的id字段末尾多了一个逗号,会导致字段变成元组引发异常,需删除:class Client(models.Model): id = models.BigAutoField(primary_key=True) # 去掉末尾逗号 name = models.CharField(max_length=200, blank=False, null=True) # more fields abbreviated - 确保
client_fk是Client实例,若用主键值过滤,需写成Master.objects.filter(client_id=client_fk_id)。
内容的提问来源于stack exchange,提问作者Mike Oliver
相关产品推荐
相关产品推荐

