Django:对象需要具有字段“...”的值才能使用这种多对多关系

Posted

技术标签:

【中文标题】Django:对象需要具有字段“...”的值才能使用这种多对多关系【英文标题】:Django: object needs to have a value for field "..." before this many-to-many relationship can be used 【发布时间】:2013-04-14 18:57:11 【问题描述】:

我在使用 Django 1.5 时遇到了一个奇怪的错误: 我定义了如下模型:

class Company(models.Model): 
    user = models.OnetoOneField(User)
    agreed_to_terms = models.NullBooleanField(default=False) 
    address = models.CharField(_('Complete Address'), 
            max_length = 255, null = True, blank = True) 
    winning_bid = models.ForeignKey('Bid', 
            related_name='winning_bid', 
            blank = True, null = True)
    bid_list = models.ManyToManyField('Bid', 
            related_name='bids', 
            blank = True, null = True)
    ...

class Bid(models.Model):
    user = models.ForeignKey(User, null = True, blank = True)
    description = models.TextField(_('Description'), 
                            blank = True, null = True,)
    volume = models.DecimalField(max_digits=7, decimal_places=3,
            null=True, blank=True,)
    ...
    # all other attributes are of the Boolean, CharField or DecimalField type. No Foreignkeys, nor ManytoManyFields.

当我尝试通过 Django 管理员向表单提交初始数据时,我收到以下错误: 异常值: "" 需要为字段 "company" 设置一个值,然后才能使用这种多对多关系。

请参阅下面的回溯。 错误消息对我来说没有多大意义。唯一的 m2m 关系是bid_list,即null = True,并且在保存时为空。 Django 1.5 中是否有一些我在阅读变更日志时没有发现的新东西(这是我在 Django 1.5 中的第一个项目)?

有趣的是,当我在Django shell 中保存一个对象时,我没有收到错误消息,但是没有任何错误消息,该对象也不会被保存。

In [1]: user = User.objects.get(username='admin') 
In [2]: new_company = Company() 
In [3]: new_company.user = user 
In [4]: new_company.save() Out[4]: <Company: Company object> 
In [5]: foo = Company.objects.all()
Out[5]: []

当我尝试使用debug toolbar 跟踪 SQL 语句时,我只能看到 SQL SELECT 语句,没有 INSERT 请求。

这种奇怪行为的解释是什么?

追溯:

Request Method: POST
Request URL: /admin/company/company/add/

Django Version: 1.5.1
Python Version: 2.7.1
Installed Applications:
('django.contrib.admin',
 'django.contrib.admindocs',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.gis',
 'django.contrib.humanize',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.admin',
 'django.contrib.admindocs',
 'crispy_forms',
 'django_extensions',
 'easy_thumbnails',
 'registration',
 'south',
 'company',
 'bid',
 'debug_toolbar')
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',
 'debug_toolbar.middleware.DebugToolbarMiddleware')


Traceback:
File "/Users/neurix/Development/virtual/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  115.                         response = callback(request, *callback_args, **callback_kwargs)
File "/Users/neurix/Development/virtual/lib/python2.7/site-packages/django/contrib/admin/options.py" in wrapper
  372.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "/Users/neurix/Development/virtual/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view
  91.                     response = view_func(request, *args, **kwargs)
File "/Users/neurix/Development/virtual/lib/python2.7/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
  89.         response = view_func(request, *args, **kwargs)
File "/Users/neurix/Development/virtual/lib/python2.7/site-packages/django/contrib/admin/sites.py" in inner
  202.             return view(request, *args, **kwargs)
File "/Users/neurix/Development/virtual/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapper
  25.             return bound_func(*args, **kwargs)
File "/Users/neurix/Development/virtual/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view
  91.                     response = view_func(request, *args, **kwargs)
File "/Users/neurix/Development/virtual/lib/python2.7/site-packages/django/utils/decorators.py" in bound_func
  21.                 return func(self, *args2, **kwargs2)
File "/Users/neurix/Development/virtual/lib/python2.7/site-packages/django/db/transaction.py" in inner
  223.                 return func(*args, **kwargs)
File "/Users/neurix/Development/virtual/lib/python2.7/site-packages/django/contrib/admin/options.py" in add_view
  1008.                 self.save_related(request, form, formsets, False)
File "/Users/neurix/Development/virtual/lib/python2.7/site-packages/django/contrib/admin/options.py" in save_related
  762.         form.save_m2m()
File "/Users/neurix/Development/virtual/lib/python2.7/site-packages/django/forms/models.py" in save_m2m
  84.                 f.save_form_data(instance, cleaned_data[f.name])
File "/Users/neurix/Development/virtual/lib/python2.7/site-packages/django/db/models/fields/related.py" in save_form_data
  1336.         setattr(instance, self.attname, data)
File "/Users/neurix/Development/virtual/lib/python2.7/site-packages/django/db/models/fields/related.py" in __set__
  910.         manager = self.__get__(instance)
File "/Users/neurix/Development/virtual/lib/python2.7/site-packages/django/db/models/fields/related.py" in __get__
  897.             through=self.field.rel.through,
File "/Users/neurix/Development/virtual/lib/python2.7/site-packages/django/db/models/fields/related.py" in __init__
  586.                                  (instance, source_field_name))

Exception Type: ValueError at /admin/company/company/add/
Exception Value: "<Company: Company object>" needs to have a value for field "company" before this many-to-many relationship can be used.

settings.py

import os, os.path, sys
DEBUG = True
TEMPLATE_DEBUG = DEBUG

# Setting up folders
abspath = lambda *p: os.path.abspath(os.path.join(*p))
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
TASK2_MODULE_PATH = abspath(PROJECT_ROOT, 'apps/')
sys.path.insert(0, TASK2_MODULE_PATH)

# Loading passwords
try:
    from settings_pwd import *
except ImportError:
    pass
AUTH_PROFILE_MODULE = 'profile.UserProfile'
#ALLOWED_HOSTS = [''] # not needed for DEBUG = True
TIME_ZONE = 'Europe/London'
LANGUAGE_CODE = 'en-uk'
LANGUAGES = [
        ("en", u"English"),
        ]
SITE_ID = 1
USE_I18N = True
USE_L10N = True
USE_TZ = True
if DEBUG:
    MEDIA_ROOT = os.path.join(PROJECT_ROOT, "site_media", "media")
else:
    MEDIA_ROOT = "folder_to_upload_files"
if DEBUG:
    MEDIA_URL = "/media/"
else:
    MEDIA_URL = "/media/uploads/"
if DEBUG:
    STATIC_ROOT = os.path.join(PROJECT_ROOT, "site_media","static")
else:
    STATIC_ROOT = "folder_to_static_files" 
STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(PROJECT_ROOT, "assets"),
)
STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)
SECRET_KEY = '...'
TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',)

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',)
ROOT_URLCONF = 'task2.urls'
WSGI_APPLICATION = 'task2.wsgi.application'
TEMPLATE_DIRS = (
    os.path.join(PROJECT_ROOT, "templates"),
    os.path.join(PROJECT_ROOT, "templates/pages"),)
INSTALLED_APPS = (
    # Django apps
    'django.contrib.admin',
    'django.contrib.admindocs',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.gis',
    'django.contrib.humanize',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.admin',
    'django.contrib.admindocs',
    # third party apps
    'crispy_forms',
    'django_extensions',
    'easy_thumbnails',
    'registration',
    'south',

    # task2 apps
    'profile',
    'company',
)
AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
)

log = DEBUG 

if log:
    LOGGING =  
        'version': 1,
        'disable_existing_loggers': True,
        'formatters': 
            'simple': 
                'format': '%(levelname)s %(message)s',
                ,  
            ,  
        'handlers': 
            'console':
                'level':'DEBUG',
                'class':'logging.StreamHandler',
                'formatter': 'simple'
                ,  
            ,  
        'loggers': 
            'django': 
                'handlers': ['console'],
                'level': 'DEBUG',
                ,  
               
            
####################
# THIRD PARTY SETUPS

# For Crispy Forms
CRISPY_FAIL_SILENTLY = not DEBUG
CRISPY_TEMPLATE_PACK = 'bootstrap'

## For Django Registration
ACCOUNT_ACTIVATION_DAYS = 7

# for Django testing to avoid conflicts with South migrations
SOUTH_TESTS_MIGRATE = False

# Debug_toolbar settings
if DEBUG:
    INTERNAL_IPS = ('127.0.0.1',)
    MIDDLEWARE_CLASSES += (
        'debug_toolbar.middleware.DebugToolbarMiddleware',
    )

    INSTALLED_APPS += (
        'debug_toolbar',
    )

    DEBUG_TOOLBAR_PANELS = (
        'debug_toolbar.panels.version.VersionDebugPanel',
        'debug_toolbar.panels.timer.TimerDebugPanel',
        'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel',
        'debug_toolbar.panels.headers.HeaderDebugPanel',
        #'debug_toolbar.panels.profiling.ProfilingDebugPanel',
        'debug_toolbar.panels.request_vars.RequestVarsDebugPanel',
        'debug_toolbar.panels.sql.SQLDebugPanel',
        'debug_toolbar.panels.template.TemplateDebugPanel',
        'debug_toolbar.panels.cache.CacheDebugPanel',
        'debug_toolbar.panels.signals.SignalDebugPanel',
        'debug_toolbar.panels.logger.LoggingPanel',
    )

    DEBUG_TOOLBAR_CONFIG = 
        'INTERCEPT_REDIRECTS': False,
    

# Easy_Thumbnail setup
THUMBNAIL_ALIASES = 
    '': 
        'thumbnail': 'size': (50, 50), 'crop': True,
    ,

【问题讨论】:

你在这个模型上有company字段Company吗? 异常值:“”需要字段“company”的值才能使用这种多对多关系。您的模型没有“公司”字段。 admin.py 中是否一切正常? @Hellpain 我也这么认为,但 admin.py 再简单不过了:from company.models import Company admin.site.register(Company)。也很奇怪,对象不会毫无错误地保存在django shelll 中。很奇怪。 @akshar raaj 我刚刚再次检查,模型不包含公司字段。还有其他原因吗? 请显示您的“投标”模型和 settings.py。您的模型“公司”没问题,问题出在其他地方。 【参考方案1】:

问题与您如何使用视图有关。 我认为您正在使用: instance.add(many_to_many_instance) 在您拥有实例 ID 之前。

所以首先保存你的模型:

instance.save()
instance.add(many_to_many_instance)

【讨论】:

是的,错误消息是抱怨访问不存在的数据库对象。我投票给你。 我遇到了同样的问题,您的回答启发了我研究模型类中多对多字段的其他用途。就我而言,问题是对clean 中的多对多字段的引用。【参考方案2】:

您正在使用自定义用户模型 AUTH_PROFILE_MODULE = 'profile.UserProfile',但在代码中我想您使用的是本机 django 用户。

我想你的模型应该是这样的

class Company(models.Model): 
    user = models.OnetoOneField('profile.UserProfile')
...

阅读更多https://docs.djangoproject.com/en/1.5/ref/contrib/auth/#django.contrib.auth.models.User.get_profile

【讨论】:

感谢您的回答。按照您的建议,通过切换用户类,错误消失了。但是,即使管理页面返回对象已成功保存,表也是空的,并且没有对象到达数据库。你知道为什么吗? 这很奇怪。你在用postgre吗? postgre 有几个额外的配置。 docs.djangoproject.com/en/1.5/ref/databases/… 否则尝试在 sqlite 上运行项目。我们必须看看问题出在哪里——在数据库中还是在代码中 感谢您提示切换到 sqlite。它表明问题一定出在代码上,因为错误仍然存​​在(我实际上再次看到原始错误消息)。 感谢您的帮助和建议。问题已经解决了。魔鬼坐在 save() 方法中,我覆盖了它并忘记在帖子中复制。但是,您的提示让我再次阅读了 1.5 文档,其中揭示了有趣的消息。感谢您的帮助!

以上是关于Django:对象需要具有字段“...”的值才能使用这种多对多关系的主要内容,如果未能解决你的问题,请参考以下文章

Django:如何在同一对象中提到的时间自动更改字段的值?

如何计算Django中一个对象的多个字段的值?

Django 查询集过滤具有相同多对多字段的对象

Django F对象的使用

Django 1.8.3 - 具有相关对象的模型字段验证

Django:如何选择具有相同字段值的对象?