Django Admin 站点 'int' 在模型表单提交时没有 len() 错误
2020-12-03
294
当尝试在 Django 管理站点中提交模型表单 (/add/) 时,我收到以下错误:
TypeError 类型为“int”的对象没有 len()
Environment:
Request Method: POST
Request URL: http://localhost:8000/admin/app/card/add/
Django Version: 3.1.4
Python Version: 3.8.6
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app',
'crispy_forms',
'django_filters',
'markdownify',
'ckeditor',
'ckeditor_uploader',
'rest_framework',
'smart_selects',
'storages',
'widget_tweaks']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback (most recent call last):
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/core/handlers/base.py", line 179, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/contrib/admin/options.py", line 614, in wrapper
return self.admin_site.admin_view(view)(*args, **kwargs)
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/contrib/admin/sites.py", line 233, in inner
return view(request, *args, **kwargs)
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1653, in add_view
return self.changeform_view(request, None, form_url, extra_context)
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1534, in changeform_view
return self._changeform_view(request, object_id, form_url, extra_context)
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1582, in _changeform_view
change_message = self.construct_change_message(request, form, formsets, add)
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1055, in construct_change_message
return construct_change_message(form, formsets, add)
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/contrib/admin/utils.py", line 503, in construct_change_message
changed_data = form.changed_data
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/utils/functional.py", line 48, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/forms/forms.py", line 449, in changed_data
if field.has_changed(initial_value, data_value):
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/forms/models.py", line 1385, in has_changed
if len(initial) != len(data):
Exception Type: TypeError at /admin/app/card/add/
Exception Value: object of type 'int' has no len()
Models.py:
class Card(models.Model):
visible = models.BooleanField(default=True, verbose_name="Visible to Customers?")
software = models.ForeignKey(Software, default=1, on_delete=models.CASCADE)
product = ChainedForeignKey(
Product,
chained_field="software",
chained_model_field="software",
auto_choose=True,
show_all=False,
sort=True,
default=0,)
utility = models.ForeignKey(Utility, verbose_name='Utilities', default=1, on_delete=models.CASCADE)
function = ChainedForeignKey(
Function,
chained_field="utility",
chained_model_field="utility",
auto_choose=True,
show_all=False,
sort=True,
default=0,)
error_code = models.ForeignKey(ErrorCode, default=0, on_delete=models.CASCADE, help_text="Please only use for error codes, if no code, leave empty.")
message = RichTextUploadingField(default="", help_text='Message can include markdown for styling.')
tags = RichTextUploadingField(default="", blank=True, null=False, help_text='Add Text that can be used as tags for searching for this card.')
encountered = models.ManyToManyField(Encountered, default=0, verbose_name='Encountered in', help_text='Version or Year. Select "N/A" if unknown.')
resolved = models.ForeignKey(Resolved, default=0, on_delete=models.CASCADE, verbose_name='Resolved in', help_text='If not resolved, enter "N/A".')
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
card_created_by = models.ForeignKey(
'auth.User',
related_name='card_created_by',
on_delete=models.CASCADE,
verbose_name='Created by',
null=True)
last_edited_by = models.ForeignKey(
'auth.User',
related_name='last_edited_by',
on_delete=models.CASCADE,
verbose_name='Last edited by',
null=True)
card_view_count = models.IntegerField(default=0)
class Solution(models.Model):
card = models.ForeignKey(Card, on_delete=models.CASCADE, null=True)
cause = RichTextUploadingField(blank=False, help_text='Message can include markdown for styling.')
cause_solution = RichTextUploadingField(blank=False, verbose_name='Solution', help_text='Message can include markdown for styling.')
solution_edited_by = models.ForeignKey(
'auth.User',
related_name='solution_edited_by',
verbose_name='Last edited by',
on_delete=models.CASCADE,
blank=True,
null=True
)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
Admin.py:
class SolutionsInlineFormset(forms.models.BaseInlineFormSet):
def save_model(self, request, obj, form, change):
obj.solution_edited_by = request.user
obj.save()
def clean(self):
# get forms that actually have valid data
count = 0
for form in self.forms:
try:
if form.cleaned_data:
count += 1
except AttributeError:
# annoyingly, if a subform is invalid Django explicity raises
# an AttributeError for cleaned_data
pass
if count < 1:
raise forms.ValidationError('You must have at least one solution." \
+ " Please do not place solutions in the message field.')
class SolutionsInline(admin.TabularInline):
model = Solution
extra = 0
ordering = ('-updated', 'id')
readonly_fields = ('solution_edited_by',)
formset = SolutionsInlineFormset
class CardAdmin(admin.ModelAdmin):
model = Card
list_display = ('id', 'card_view_count', 'product', 'software', 'utility', 'function', 'markdown_safe_message', 'updated')
ordering = ('-updated', 'software', 'product', 'utility', 'card_view_count', )
list_filter = ('software', 'product')
formfield_overrides = {
models.TextField: {'widget': CKEditorWidget},
}
inlines = [SolutionsInline, ]
exclude = ['card_view_count', 'last_edited_by', 'card_created_by', ]
readonly_fields = ('card_view_count', 'last_edited_by', 'card_created_by',)
search_fields = ['id',
'message',
'tags',
'software__name',
'product__name',
'solution__cause',
'solution__cause_solution',
'error_code__code',
'function__name',
'utility__name',
'resolved__number',
'encountered__number',
]
save_as = True
def save_model(self, request, obj, form, change):
if change:
obj.last_edited_by = request.user
else:
obj.card_created_by = request.user
obj.save()
def save_formset(self, request, form, formset, change):
super(CardAdmin, self).save_formset(request, form, formset, change)
instances = formset.save(commit=False)
for i in instances:
if hasattr(i, 'solution_edited_by') and not i.solution_edited_by:
i.solution_edited_by = request.user
i.save()
formset.save_m2m()
super(CardAdmin, self).save_formset(request, form, formset, change)
似乎无法找出导致此错误的原因。最近我唯一改变的就是在
list_display
中添加了“id”,并添加了
tags
字段。
跟踪了 /django/forms/models.py 中的错误行:
class ModelMultipleChoiceField(ModelChoiceField):
"""A MultipleChoiceField whose choices are a model QuerySet."""
widget = SelectMultiple
hidden_widget = MultipleHiddenInput
default_error_messages = {
'invalid_list': _('Enter a list of values.'),
'invalid_choice': _('Select a valid choice. %(value)s is not one of the'
' available choices.'),
'invalid_pk_value': _('“%(pk)s” is not a valid value.')
}
def has_changed(self, initial, data):
if self.disabled:
return False
if initial is None:
initial = []
if data is None:
data = []
if len(initial) != len(data): # <-- Problem Child
return True
initial_set = {str(value) for value in self.prepare_value(initial)}
data_set = {str(value) for value in data}
return data_set != initial_set
有没有办法可以调试它以查看哪个变量或字段导致了这个问题?
如能得到任何帮助或建议,我们将不胜感激。
2个回答
您的回溯显示:
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/forms/forms.py", line 449, in changed_data
if field.has_changed(initial_value, data_value):
File "/home/corey/.virtualenvs/cardsite-_p-Jv6sl/lib/python3.8/site-packages/django/forms/models.py", line 1385, in has_changed
if len(initial) != len(data):
因此,您尝试在 forms.py 中获取整数的 len()(您无法执行此操作)
您可以使用
initial_string = str(intial)
来存储一个字符串,然后可以使用
len(initial_string)
进行与之比较,但我认为有更好的方法可以完成您想要做的事情。(您想做什么?)
Colby
2020-12-03
问题最终出在
Card
类上的
encountered
属性上:
encountered = models.ManyToManyField(Encountered, default=0, verbose_name='Encountered in', help_text='Version or Year. Select "N/A" if unknown.')
与此同时,我刚刚将其更改为
ForeignKey
:
encountered = models.ForeignKey(Encountered, default=1, on_delete=models.CASCADE, verbose_name='Encountered in', help_text='Version or Year. Select "N/A" if unknown.')
Corey
2020-12-03