Django:"matching query does not exist" 在 save() 方法上
Django : "matching query does not exist" on save() method
我正在构建一个获取 API 并用获取的数据填充数据库的应用程序。
我正在尝试为处理的每个 JSON 行保存到数据库。当我最后调用 obj_to_insert.save()
时,出现错误:geotrek.trekking.models.DoesNotExist: POI matching query does not exist.
POI
是我的模型之一,它已正确定义和导入。 Topology
是另外一个,我觉得是他们两个的关系我处理不好。
这是他们的 类:
class POI(StructureRelated, PicturesMixin, PublishableMixin, MapEntityMixin, Topology):
topo_object = models.OneToOneField(Topology, parent_link=True, on_delete=models.CASCADE)
class Topology(ZoningPropertiesMixin, AddPropertyMixin, AltimetryMixin,
TimeStampedModelMixin, NoDeleteMixin, ClusterableModel):
geom = models.GeometryField(editable=(not settings.TREKKING_TOPOLOGY_ENABLED),
srid=settings.SRID, null=True,
default=None, spatial_index=False)
这是处理函数的结构(我把它简化了,我使用的所有变量都在真实代码中正确定义等):
with transaction.atomic():
for datatype_name, datatype_details in dict.items():
##fetching the API
r = response.json()["results"]
for index in range(len(r)):
dict_to_insert = {}
for f in normal_fields: #normal_fields are all of the model fields that aren't a primary key or a foreign key
dict_to_insert[f.name] = other_dict['key'][f.name]
obj_to_insert = DataType(**dict_to_insert)
for f in fkeys_fields: #fkeys_fields are all the model fields that are related to another model
fk_to_insert = {}
if condition:
fk_to_insert[f.name] = other_dict['key'][f.name]
new_topo = Topology.objects.create(**fk_to_insert)
obj_to_insert.topo_object = new_topo
elif condition:
obj_to_insert.structure = Structure.objects.get(name = AUTHENT_STRUCTURE)
elif condition:
fk_to_insert[f.name] = other_dict['key'][f.name] ##simplified
setattr(obj_to_insert, fk_field, f.related_model.objects.get(**fk_to_insert))
obj_to_insert.save()
一切顺利,直到最后的 .save()
,这给出了 models.DoesNotExist
错误。就好像 Django 得到了 obj_to_insert
,试图在 DB 中找到相应的行但没有找到它(正常:我正在尝试创建它)。
当我 print(vars(obj_to_insert))
在尝试保存之前,这是输出,对我来说看起来非常好:
{'_state': <django.db.models.base.ModelState object at 0x7f2cd58ab0a0>, 'id': 84909, 'date_insert': None, 'date_update': None, 'deleted': False, 'geom_3d': None, 'length': 0.0, 'ascent': 0, 'descent': 0, 'min_elevation': 0, 'max_elevation': 0, 'slope': 0.0, 'offset': 0.0, 'kind': 'POI', 'geom_need_update': False, 'geom': None, 'uuid': UUID('6e37ea3e-ec49-4eab-a719-6037b3d61ccb'), 'structure_id': 7, 'published': True, 'published_en': False, 'published_fr': True, 'publication_date': None, 'name': 'Refuge de la Lavey', 'name_en': '', 'name_fr': 'Refuge de la Lavey', 'review': False, 'topo_object_id': 84909, 'description': 'Test refuge', 'description_en': '', 'description_fr': 'Test refuge', 'type_id': 8, 'eid': None}
完整的错误信息如下:
Traceback (most recent call last):
File "/usr/sbin/geotrek", line 20, in <module>
execute_from_command_line(sys.argv)
File "/opt/geotrek-admin/lib/python3.8/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
utility.execute()
File "/opt/geotrek-admin/lib/python3.8/site-packages/django/core/management/__init__.py", line 395, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/opt/geotrek-admin/lib/python3.8/site-packages/django/core/management/base.py", line 330, in run_from_argv
self.execute(*args, **cmd_options)
File "/opt/geotrek-admin/lib/python3.8/site-packages/django/core/management/base.py", line 371, in execute
output = self.handle(*args, **options)
File "/opt/geotrek-admin/lib/python3.8/site-packages/geotrek/common/management/commands/import.py", line 55, in handle
parser.parse(options['shapefile'], limit=limit)
File "/opt/geotrek-admin/var/conf/parsers.py", line 17, in parse
spec.loader.exec_module(module)
File "<frozen importlib._bootstrap_external>", line 848, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/opt/geotrek-admin/var/conf/gag_app/custom_geotrek_shell.py", line 169, in <module>
test()
File "/opt/geotrek-admin/var/conf/gag_app/custom_geotrek_shell.py", line 166, in test
obj_to_insert.save()
File "/opt/geotrek-admin/lib/python3.8/site-packages/geotrek/trekking/models.py", line 744, in save
super().save(*args, **kwargs)
File "/opt/geotrek-admin/lib/python3.8/site-packages/geotrek/common/mixins.py", line 282, in save
super().save(*args, **kwargs)
File "/opt/geotrek-admin/lib/python3.8/site-packages/geotrek/common/utils/postgresql.py", line 23, in wrapped
r = f(*args, **kwargs)
File "/opt/geotrek-admin/lib/python3.8/site-packages/geotrek/core/models.py", line 574, in save
existing = self.__class__.objects.get(pk=self.pk)
File "/opt/geotrek-admin/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/opt/geotrek-admin/lib/python3.8/site-packages/django/db/models/query.py", line 429, in get
raise self.model.DoesNotExist(
geotrek.trekking.models.DoesNotExist: POI matching query does not exist.
我是否错过了使用 save()
方法或处理外键填充的内容?
全功能:
def test():
from django.apps import apps
from django.db import transaction
from django.contrib.contenttypes.models import ContentType
from django.contrib.gis.geos import GEOSGeometry, WKBWriter
from gag_app.env import fk_not_integrated, specific, source_cat_to_gag_cat, core_topology, common, list_label_field
from config.config import API_BASE_URL, AUTHENT_STRUCTURE, SRID
from gag_app.utils import geom4326_to_wkt, camel_case, get_fk_row, create_topology, get_api_field, deserialize_translated_fields
with transaction.atomic():
print("Inspecting...")
coretopology_fields = Topology._meta.get_fields()
for model_name, model_specifics in specific.items():
api_model = model_name.lower() # ex: Trek => trek
url = API_BASE_URL + api_model
print("Fetching API...")
response = requests.get(url)
r = response.json()["results"]
app_name = ContentType.objects.get(model = model_name.lower()).app_label
print('app_name: ', app_name)
model = apps.get_model(app_name, model_name)
print('model: ', model)
all_fields = model._meta.get_fields(include_parents = False) # toutes les colonnes du modèle
# print('all_fields: ', all_fields)
fkeys_fields = [f for f in all_fields if f.many_to_one or f.one_to_one]
#print(fkeys_fields)
pkey_field = [f for f in all_fields if hasattr(f, 'primary_key')]
normal_fields = [f for f in all_fields if f.is_relation is False]
print('normal_fields: ', normal_fields)
for index in range(len(r)):
dict_to_insert = {}
for f in normal_fields:
f_name = f.name
print('f_name: ', f_name)
if f_name in model_specifics:
dict_to_insert = get_api_field(r, index, f_name, model_specifics, dict_to_insert)
elif f_name in common['db_column_api_field']:
dict_to_insert = get_api_field(r, index, f_name, common['db_column_api_field'], dict_to_insert)
elif f_name in common['languages']:
dict_to_insert = deserialize_translated_fields(r[index], f_name, dict_to_insert, normal_fields)
elif f_name in common['default_values']:
dict_to_insert[f_name] = common['default_values'][f_name]
#main_class = eval('models.' + camel_case(model_name))
print('dict_to_insert: ', dict_to_insert)
obj_to_insert = model(**dict_to_insert)
print(vars(obj_to_insert))
for f in fkeys_fields:
print(f)
fk_to_insert = {}
obj_content_type = ContentType.objects.get_for_model(f.related_model)
f_related_table = obj_content_type.app_label + '_' + obj_content_type.model
related_model_fields = f.related_model._meta.get_fields()
related_model_normal_fields_name = [f.name for f in related_model_fields if f.is_relation is False and f.name in list_label_field]
print('related_model_normal_fields_name: ', related_model_normal_fields_name)
fk_field = f.name
print("fk_field: ", fk_field)
if len(related_model_normal_fields_name) == 1:
name_field = related_model_normal_fields_name[0]
elif f_related_table != 'core_topology':
print('related_model_fields:', related_model_fields)
print('related_model_normal_fields_name:', related_model_normal_fields_name)
raise Exception("len(related_model_normal_fields_name) !=1 whereas exactly one field amongst {} should exist in {} table".format(list_label_field, f_related_table))
if f_related_table == 'core_topology':
print(model_name, ': topology exists')
fk_to_insert['kind'] = api_model.upper()
geom = GEOSGeometry(str(r[index]['geometry'])) #default SRID of GEOSGeometry is 4326
geom.transform(SRID)
geom = WKBWriter().write(geom)
fk_to_insert['geom'] = geom
for ctf in coretopology_fields:
ctf_name = ctf.name
if ctf_name in core_topology['db_column_api_field']:
fk_to_insert[ctf_name] = r[index][core_topology['db_column_api_field'][ctf_name]]
elif ctf_name in core_topology['default_values']:
fk_to_insert[ctf_name] = core_topology['default_values'][ctf_name]
print(fk_to_insert)
#obj_to_insert.topo_object = Topology(**fk_to_insert)
new_topo = Topology.objects.create(**fk_to_insert)
obj_to_insert.topo_object = new_topo
elif f_related_table == 'authent_structure':
obj_to_insert.structure = Structure.objects.get(name = AUTHENT_STRUCTURE)
elif f_related_table in fk_not_integrated and r[index][fk_not_integrated[f_related_table]["api_field"]] is not None:
api_main_route = fk_not_integrated[f_related_table]["api_main_route"]
url = API_BASE_URL + api_main_route + '/' + str(r[index][fk_not_integrated[f_related_table]["api_field"]])
params = {"language" : GAG_BASE_LANGUAGE}
print("Fetching API for referred table route...")
response2 = requests.get(url, params = params)
r2 = response2.json()
print('r2:', r2)
api_labels = [r2k for r2k in r2.keys() if r2k in list_label_field]
if len(api_labels) == 1:
api_label = ''.join(api_labels)
elif f_related_table != "core_topology":
print('API response keys:', r2.keys())
print('api_labels:', api_labels)
raise Exception("len(api_labels) !=1 whereas exactly one column amongst {} should exist in {} API route".format(list_label_field, api_main_route))
old_value = r2[api_label]
new_value = source_cat_to_gag_cat[f_related_table][old_value]
fk_to_insert[name_field] = new_value
setattr(obj_to_insert, fk_field, f.related_model.objects.get(**fk_to_insert))
elif fk_field in specific[model_name]:
api_field = specific[model_name][fk_field]
if type(api_field) is list:
old_value = r[index][api_field[0]][api_field[1]]
else:
old_value = r[index][api_field]
new_value = source_cat_to_gag_cat[f_related_table][old_value]
fk_to_insert[name_field] = new_value
print('fk_to_insert: ', fk_to_insert)
setattr(obj_to_insert, fk_field, f.related_model.objects.get(**fk_to_insert))
print(vars(obj_to_insert))
obj_to_insert.save()
print("{} object n°{} inserted!".format(api_model, index))
问题是我的处理顺序。由于 POI
是 Topology
的子对象,我无法创建 POI
对象并将其 link 到之后创建的 POI
对象。当我从 SQLAlchemy 切换我的应用程序时,这种事情的逻辑是不同的。
我正在构建一个获取 API 并用获取的数据填充数据库的应用程序。
我正在尝试为处理的每个 JSON 行保存到数据库。当我最后调用 obj_to_insert.save()
时,出现错误:geotrek.trekking.models.DoesNotExist: POI matching query does not exist.
POI
是我的模型之一,它已正确定义和导入。 Topology
是另外一个,我觉得是他们两个的关系我处理不好。
这是他们的 类:
class POI(StructureRelated, PicturesMixin, PublishableMixin, MapEntityMixin, Topology):
topo_object = models.OneToOneField(Topology, parent_link=True, on_delete=models.CASCADE)
class Topology(ZoningPropertiesMixin, AddPropertyMixin, AltimetryMixin,
TimeStampedModelMixin, NoDeleteMixin, ClusterableModel):
geom = models.GeometryField(editable=(not settings.TREKKING_TOPOLOGY_ENABLED),
srid=settings.SRID, null=True,
default=None, spatial_index=False)
这是处理函数的结构(我把它简化了,我使用的所有变量都在真实代码中正确定义等):
with transaction.atomic():
for datatype_name, datatype_details in dict.items():
##fetching the API
r = response.json()["results"]
for index in range(len(r)):
dict_to_insert = {}
for f in normal_fields: #normal_fields are all of the model fields that aren't a primary key or a foreign key
dict_to_insert[f.name] = other_dict['key'][f.name]
obj_to_insert = DataType(**dict_to_insert)
for f in fkeys_fields: #fkeys_fields are all the model fields that are related to another model
fk_to_insert = {}
if condition:
fk_to_insert[f.name] = other_dict['key'][f.name]
new_topo = Topology.objects.create(**fk_to_insert)
obj_to_insert.topo_object = new_topo
elif condition:
obj_to_insert.structure = Structure.objects.get(name = AUTHENT_STRUCTURE)
elif condition:
fk_to_insert[f.name] = other_dict['key'][f.name] ##simplified
setattr(obj_to_insert, fk_field, f.related_model.objects.get(**fk_to_insert))
obj_to_insert.save()
一切顺利,直到最后的 .save()
,这给出了 models.DoesNotExist
错误。就好像 Django 得到了 obj_to_insert
,试图在 DB 中找到相应的行但没有找到它(正常:我正在尝试创建它)。
当我 print(vars(obj_to_insert))
在尝试保存之前,这是输出,对我来说看起来非常好:
{'_state': <django.db.models.base.ModelState object at 0x7f2cd58ab0a0>, 'id': 84909, 'date_insert': None, 'date_update': None, 'deleted': False, 'geom_3d': None, 'length': 0.0, 'ascent': 0, 'descent': 0, 'min_elevation': 0, 'max_elevation': 0, 'slope': 0.0, 'offset': 0.0, 'kind': 'POI', 'geom_need_update': False, 'geom': None, 'uuid': UUID('6e37ea3e-ec49-4eab-a719-6037b3d61ccb'), 'structure_id': 7, 'published': True, 'published_en': False, 'published_fr': True, 'publication_date': None, 'name': 'Refuge de la Lavey', 'name_en': '', 'name_fr': 'Refuge de la Lavey', 'review': False, 'topo_object_id': 84909, 'description': 'Test refuge', 'description_en': '', 'description_fr': 'Test refuge', 'type_id': 8, 'eid': None}
完整的错误信息如下:
Traceback (most recent call last):
File "/usr/sbin/geotrek", line 20, in <module>
execute_from_command_line(sys.argv)
File "/opt/geotrek-admin/lib/python3.8/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
utility.execute()
File "/opt/geotrek-admin/lib/python3.8/site-packages/django/core/management/__init__.py", line 395, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/opt/geotrek-admin/lib/python3.8/site-packages/django/core/management/base.py", line 330, in run_from_argv
self.execute(*args, **cmd_options)
File "/opt/geotrek-admin/lib/python3.8/site-packages/django/core/management/base.py", line 371, in execute
output = self.handle(*args, **options)
File "/opt/geotrek-admin/lib/python3.8/site-packages/geotrek/common/management/commands/import.py", line 55, in handle
parser.parse(options['shapefile'], limit=limit)
File "/opt/geotrek-admin/var/conf/parsers.py", line 17, in parse
spec.loader.exec_module(module)
File "<frozen importlib._bootstrap_external>", line 848, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/opt/geotrek-admin/var/conf/gag_app/custom_geotrek_shell.py", line 169, in <module>
test()
File "/opt/geotrek-admin/var/conf/gag_app/custom_geotrek_shell.py", line 166, in test
obj_to_insert.save()
File "/opt/geotrek-admin/lib/python3.8/site-packages/geotrek/trekking/models.py", line 744, in save
super().save(*args, **kwargs)
File "/opt/geotrek-admin/lib/python3.8/site-packages/geotrek/common/mixins.py", line 282, in save
super().save(*args, **kwargs)
File "/opt/geotrek-admin/lib/python3.8/site-packages/geotrek/common/utils/postgresql.py", line 23, in wrapped
r = f(*args, **kwargs)
File "/opt/geotrek-admin/lib/python3.8/site-packages/geotrek/core/models.py", line 574, in save
existing = self.__class__.objects.get(pk=self.pk)
File "/opt/geotrek-admin/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/opt/geotrek-admin/lib/python3.8/site-packages/django/db/models/query.py", line 429, in get
raise self.model.DoesNotExist(
geotrek.trekking.models.DoesNotExist: POI matching query does not exist.
我是否错过了使用 save()
方法或处理外键填充的内容?
全功能:
def test():
from django.apps import apps
from django.db import transaction
from django.contrib.contenttypes.models import ContentType
from django.contrib.gis.geos import GEOSGeometry, WKBWriter
from gag_app.env import fk_not_integrated, specific, source_cat_to_gag_cat, core_topology, common, list_label_field
from config.config import API_BASE_URL, AUTHENT_STRUCTURE, SRID
from gag_app.utils import geom4326_to_wkt, camel_case, get_fk_row, create_topology, get_api_field, deserialize_translated_fields
with transaction.atomic():
print("Inspecting...")
coretopology_fields = Topology._meta.get_fields()
for model_name, model_specifics in specific.items():
api_model = model_name.lower() # ex: Trek => trek
url = API_BASE_URL + api_model
print("Fetching API...")
response = requests.get(url)
r = response.json()["results"]
app_name = ContentType.objects.get(model = model_name.lower()).app_label
print('app_name: ', app_name)
model = apps.get_model(app_name, model_name)
print('model: ', model)
all_fields = model._meta.get_fields(include_parents = False) # toutes les colonnes du modèle
# print('all_fields: ', all_fields)
fkeys_fields = [f for f in all_fields if f.many_to_one or f.one_to_one]
#print(fkeys_fields)
pkey_field = [f for f in all_fields if hasattr(f, 'primary_key')]
normal_fields = [f for f in all_fields if f.is_relation is False]
print('normal_fields: ', normal_fields)
for index in range(len(r)):
dict_to_insert = {}
for f in normal_fields:
f_name = f.name
print('f_name: ', f_name)
if f_name in model_specifics:
dict_to_insert = get_api_field(r, index, f_name, model_specifics, dict_to_insert)
elif f_name in common['db_column_api_field']:
dict_to_insert = get_api_field(r, index, f_name, common['db_column_api_field'], dict_to_insert)
elif f_name in common['languages']:
dict_to_insert = deserialize_translated_fields(r[index], f_name, dict_to_insert, normal_fields)
elif f_name in common['default_values']:
dict_to_insert[f_name] = common['default_values'][f_name]
#main_class = eval('models.' + camel_case(model_name))
print('dict_to_insert: ', dict_to_insert)
obj_to_insert = model(**dict_to_insert)
print(vars(obj_to_insert))
for f in fkeys_fields:
print(f)
fk_to_insert = {}
obj_content_type = ContentType.objects.get_for_model(f.related_model)
f_related_table = obj_content_type.app_label + '_' + obj_content_type.model
related_model_fields = f.related_model._meta.get_fields()
related_model_normal_fields_name = [f.name for f in related_model_fields if f.is_relation is False and f.name in list_label_field]
print('related_model_normal_fields_name: ', related_model_normal_fields_name)
fk_field = f.name
print("fk_field: ", fk_field)
if len(related_model_normal_fields_name) == 1:
name_field = related_model_normal_fields_name[0]
elif f_related_table != 'core_topology':
print('related_model_fields:', related_model_fields)
print('related_model_normal_fields_name:', related_model_normal_fields_name)
raise Exception("len(related_model_normal_fields_name) !=1 whereas exactly one field amongst {} should exist in {} table".format(list_label_field, f_related_table))
if f_related_table == 'core_topology':
print(model_name, ': topology exists')
fk_to_insert['kind'] = api_model.upper()
geom = GEOSGeometry(str(r[index]['geometry'])) #default SRID of GEOSGeometry is 4326
geom.transform(SRID)
geom = WKBWriter().write(geom)
fk_to_insert['geom'] = geom
for ctf in coretopology_fields:
ctf_name = ctf.name
if ctf_name in core_topology['db_column_api_field']:
fk_to_insert[ctf_name] = r[index][core_topology['db_column_api_field'][ctf_name]]
elif ctf_name in core_topology['default_values']:
fk_to_insert[ctf_name] = core_topology['default_values'][ctf_name]
print(fk_to_insert)
#obj_to_insert.topo_object = Topology(**fk_to_insert)
new_topo = Topology.objects.create(**fk_to_insert)
obj_to_insert.topo_object = new_topo
elif f_related_table == 'authent_structure':
obj_to_insert.structure = Structure.objects.get(name = AUTHENT_STRUCTURE)
elif f_related_table in fk_not_integrated and r[index][fk_not_integrated[f_related_table]["api_field"]] is not None:
api_main_route = fk_not_integrated[f_related_table]["api_main_route"]
url = API_BASE_URL + api_main_route + '/' + str(r[index][fk_not_integrated[f_related_table]["api_field"]])
params = {"language" : GAG_BASE_LANGUAGE}
print("Fetching API for referred table route...")
response2 = requests.get(url, params = params)
r2 = response2.json()
print('r2:', r2)
api_labels = [r2k for r2k in r2.keys() if r2k in list_label_field]
if len(api_labels) == 1:
api_label = ''.join(api_labels)
elif f_related_table != "core_topology":
print('API response keys:', r2.keys())
print('api_labels:', api_labels)
raise Exception("len(api_labels) !=1 whereas exactly one column amongst {} should exist in {} API route".format(list_label_field, api_main_route))
old_value = r2[api_label]
new_value = source_cat_to_gag_cat[f_related_table][old_value]
fk_to_insert[name_field] = new_value
setattr(obj_to_insert, fk_field, f.related_model.objects.get(**fk_to_insert))
elif fk_field in specific[model_name]:
api_field = specific[model_name][fk_field]
if type(api_field) is list:
old_value = r[index][api_field[0]][api_field[1]]
else:
old_value = r[index][api_field]
new_value = source_cat_to_gag_cat[f_related_table][old_value]
fk_to_insert[name_field] = new_value
print('fk_to_insert: ', fk_to_insert)
setattr(obj_to_insert, fk_field, f.related_model.objects.get(**fk_to_insert))
print(vars(obj_to_insert))
obj_to_insert.save()
print("{} object n°{} inserted!".format(api_model, index))
问题是我的处理顺序。由于 POI
是 Topology
的子对象,我无法创建 POI
对象并将其 link 到之后创建的 POI
对象。当我从 SQLAlchemy 切换我的应用程序时,这种事情的逻辑是不同的。