到目前为止做了什么:
- 我在Django 1.5上,升级到1.6(不能像在Python 2.6上那样更高),但这并没有解决问题
- 我对这个问题研究得死去活来,似乎找不到确切的答案。通过查看Django项目的Bug Tracker,我看到了类似的问题,但似乎没有一个适合我的特定情况
- 我过去已经解决了这个问题,例如使用原始SQL调用将
affpart.damage_types.all()
替换为自定义函数,但现在这种情况开始更频繁地发生,并且变得非常痛苦
描述:
我在一个项目下有两个Django应用程序。其中一个应用程序使用另一个应用中的模型,使用多对多关系。
这已经顺利工作了几个月,事实上,它在我的生产机器上运行良好,但在我的开发机器上失败了。最近的情况是,我被要求添加一个新功能,当我开始工作时,我在相关代码中得到了一个FieldError
,我甚至没有碰过。
此最新问题的违规代码行是:for dt in affpart.damage_types.all()
错误为:
Cannot resolve keyword u'affectedpart' into field. Choices are: cgs_damage_code, description, id, reg_exp, sti
错误发生在query.py
模块中Django的内部。
从高层来看,当我试图在不同的Django应用程序中使用多对多模型时,就会出现这个错误。例如,一个受影响的零件可能有多种类型的损坏,并且在不同的受影响零件上可以找到一种损坏类型。
这两个应用程序是:trending
和sitar
sitar
是第一个构建的,它有我想从趋势中使用的模型。
在trending
中,我的models.py
文件有一个类似于以下的AffectedPart
模型:
from sitar.models import (Part, DamageType, Aircraft)
# this model is in trendin.models
class AffectedPart(models.Model):
res = models.ForeignKey(Res, null=True)
arising = models.ForeignKey(Arising, null=True)
aircraft = models.ForeignKey(Aircraft)
# filled out automatically only if part to Damage/Repair type matching done
maintenance_phase = models.CharField(max_length=10,
choices=MAINTENANCE_PHASE_CHOICES)
occurrence_date = models.DateField()
partnumber = models.ForeignKey(Part)
damage_types = models.ManyToManyField(DamageType, null=True, blank=True)
repair_types = models.ManyToManyField(RepairType, null=True, blank=True)
def __unicode__(self, ):
if self.res:
parent = self.res.number
else:
parent = str(self.arising)
return '{0} - {1}'.format(self.partnumber.number, parent)
# The following models are in sitar.models
class Part(models.Model):
''' This model is used to create pick-lists so the user can associate
one or more applicable parts from a pre-defined list to
a tracked item.
It will also allow for regular CRUD functionality which is
implemented by taking advantage of the Django admin interface. '''
# Added to associate a zone with a part
zones = models.ManyToManyField("Zone", null=True, blank=True)
number = models.CharField(max_length=50, unique=True)
description = models.CharField(max_length=100, blank=True)
comments = models.TextField(blank=True)
material = models.CharField(max_length=100, blank=True)
class Meta:
''' Order by part number field (ascending) when presenting data '''
ordering = ['number']
def __unicode__(self):
''' Return unicode description of a part instance '''
if self.description:
return '%s -- %s' % (self.number, self.description)
else:
return self.number
def get_encoded_part_number(self):
'''
This method will remove any '/' in part numbers and replace them
with '~' so that they can be used in URLs.
'''
return self.number.replace('/','~')
class DamageType(models.Model):
description = models.CharField(max_length=50, unique=True)
# a regular expression to account for possible spelling mistakes when
# querying the database
reg_exp = models.CharField(max_length=50, blank=True)
# Added to provide damage code for TRENDING
cgs_damage_code = models.CharField(max_length=10, blank=True,
verbose_name="CGS Damage Code")
def __unicode__(self):
''' Return unicode representation of a DamageType instance. '''
return self.description
class Meta:
''' Order by description field (ascending) when presenting data '''
ordering = ['description']
def save(self):
''' Override the save method of the DamageType model in order to assign
a regexp if one does not exist.'''
# if the tracked item does not have a reg_exp just use
# the description
if not self.reg_exp:
self.reg_exp = self.description
super(DamageType,self).save()
堆栈跟踪
Environment:
Request Method: POST
Request URL: http://127.0.0.1:8000/trending/trend/
Django Version: 1.6
Python Version: 2.6.7
Installed Applications:
('django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.admin',
'sitar')
Installed Middleware:
('django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware')
Traceback:
File "C:virtual_envsitar_env2libsite-packagesdjangocorehandlersbase.py" in get_response
114. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:virtual_envsitar_env2libsite-packagesdjangocontribauthdecorators.py" in _wrapped_view
22. return view_func(request, *args, **kwargs)
File "C:virtual_envsitar_env2cissimptrendingviews.py" in trend
418. list_result = utils.convert_queryset_to_lists(q_results, form)
File "C:virtual_envsitar_env2cissimptrendingutils.py" in convert_queryset_to_lists
918. for dt in affpart.damage_types.all()]),
File "C:virtual_envsitar_env2libsite-packagesdjangodbmodelsmanager.py" in all
133. return self.get_queryset()
File "C:virtual_envsitar_env2libsite-packagesdjangodbmodelsfieldsrelated.py" in get_queryset
539. return super(ManyRelatedManager, self).get_queryset().using(db)._next_is_sticky().filter(**self.core_filters)
File "C:virtual_envsitar_env2libsite-packagesdjangodbmodelsquery.py" in filter
590. return self._filter_or_exclude(False, *args, **kwargs)
File "C:virtual_envsitar_env2libsite-packagesdjangodbmodelsquery.py" in _filter_or_exclude
608. clone.query.add_q(Q(*args, **kwargs))
File "C:virtual_envsitar_env2libsite-packagesdjangodbmodelssqlquery.py" in add_q
1198. clause = self._add_q(where_part, used_aliases)
File "C:virtual_envsitar_env2libsite-packagesdjangodbmodelssqlquery.py" in _add_q
1232. current_negated=current_negated)
File "C:virtual_envsitar_env2libsite-packagesdjangodbmodelssqlquery.py" in build_filter
1100. allow_explicit_fk=True)
File "C:virtual_envsitar_env2libsite-packagesdjangodbmodelssqlquery.py" in setup_joins
1351. names, opts, allow_many, allow_explicit_fk)
File "C:virtual_envsitar_env2libsite-packagesdjangodbmodelssqlquery.py" in names_to_path
1274. "Choices are: %s" % (name, ", ".join(available)))
Exception Type: FieldError at /trending/trend/
Exception Value: Cannot resolve keyword u'affectedpart' into field. Choices are: cgs_damage_code, description, id, reg_exp, sti
如果有人对此有解决方案,或者知道一个应用程序中的模型与另一个应用软件中的模型有多对多关系的最佳实践,我很乐意听到
感谢
看起来像是您试图调用的地方:
damage_type.affectedpart.all()
或者类似的东西。要获得你的损伤类型的所有受影响的零件,你需要做一些类似的事情:
damage_type.affectedpart_set.all()
您可以在文档中阅读更多相关内容。
如果这不是您的错误,请跟踪有问题的代码段。
是否将DamageType
关系从ForeignKey
更改为ManyToMany
?
我猜你已经创建了,Django从未创建过中间表,所以它试图使用DamageType
表。这就是为什么它在寻找与AffectedPart
的关系。
当您进行模型更改时,应该使用类似South的东西进行迁移,因为更改为ManyToMany
字段并不像听起来那么简单。
否则,您可以自己创建一个"直通"表。
发生错误是因为我忽略了将"trending"
放入INSTALLED_APPS
中。
由于它在生产中使用完全相同的设置文件,所以我从未想过要查看那里。
感谢科林·安德森django-users@googlegroups.com论坛
科林感兴趣的一些评论:
- 你怎么知道的!?!我破解。。。开玩笑:)。我怀疑有什么东西没有加载,安装的应用程序列表在你发布的回溯中
2.我在生产中也有同样的代码,它运行起来没有问题。知道为什么吗?在开发中,如果不是所有的代码都是在启动时加载和运行的,那么在生产中(至少在1.7之前),实际上只是根据需要加载。基本上,通过应用程序加载重构和django.setup(),我们终于解决了这样的问题。