问题
I working on FormView, and I need to set initial
from another object, an example in my case we use Question
model to set an initial for QuestionSuggestedEditsForm
. But we got an error when updating the initial
dict.
1. models.py
@python_2_unicode_compatible
class Question(TimeStampedModel):
author = models.ForeignKey(
User, related_name='question_author')
title = models.CharField(
_('Title'), max_length=200)
slug = models.SlugField(
_('Slug'), max_length=200, unique=True)
tags = models.ManyToManyField(
Tag, related_name='tags')
STATUS_CHOICES = (
('approved', _('Approved')),
('duplicated', _('Duplicated')),
('pending', _('Pending')),
('on_hold', _('On Hold')),
('closed', _('Closed')),
('deleted', _('Deleted'))
)
status = models.CharField(
_('Status'), max_length=20,
choices=STATUS_CHOICES, default='approved')
description = models.TextField(_('Description'))
rating = RatingField(can_change_vote=True)
edited = models.BooleanField(
_('Edited?'), default=False)
editor = models.ForeignKey(
User, blank=True, null=True,
on_delete=models.SET_NULL, related_name='question_editor')
objects = QuestionQuerySet.as_manager()
def __str__(self):
return self.title
def _unique_slug(self):
"""
return unique slug if origin slug is exist.
eg: `foo-bar` => `foo-bar-1`
"""
origin_slug = slugify(self.title)
unique_slug = origin_slug
numb = 1
while Question.objects.filter(slug=unique_slug).exists():
unique_slug = '%s-%d' % (origin_slug, numb)
numb += 1
return unique_slug
def save(self, *args, **kwargs):
if self.slug: # edit
if slugify(self.title) != self.slug:
self.slug = self._unique_slug()
else: # create
self.slug = self._unique_slug()
super(Question, self).save(*args, **kwargs)
def edits_object(self):
question = self
qs = QuestionSuggestedEdits.objects.filter(question=question)
if qs.exists():
return qs.first()
return question
class Meta:
verbose_name_plural = _('questions')
ordering = ['-created']
@python_2_unicode_compatible
class QuestionSuggestedEdits(TimeStampedModel):
question = models.ForeignKey(
Question, related_name='suggested_edits_question')
editor = models.ForeignKey(
User, related_name='suggested_edits_editor')
title = models.CharField(
_('Title'), max_length=200)
slug = models.SlugField(
_('Slug'), max_length=200, unique=True)
tags = models.ManyToManyField(
Tag, related_name='suggested_edits_tags')
STATUS_CHOICES = (
('approved', _('Approved')),
('rejected', _('Rejected')),
('pending', _('Pending'))
)
status = models.CharField(
_('Status'), max_length=20,
choices=STATUS_CHOICES, default='pending')
description = models.TextField(_('Description'))
comment = models.TextField(_('Revision Comment'))
class Meta:
verbose_name_plural = _('question suggested edits')
ordering = ['-created']
2. forms.py
class QuestionSuggestedEditsForm(forms.ModelForm):
class Meta:
model = QuestionSuggestedEdits
fields = ['title', 'description', 'tags']
3. views.py
class QuestionSuggestedEditsCreate(LoginRequiredMixin, RevisionMixin, FormView):
template_name = 'app_faq/question_suggested_edits_create.html'
form_class = QuestionSuggestedEditsForm
model = QuestionSuggestedEdits
def get_object(self):
return get_object_or_404(Question, pk=self.kwargs['pk'])
def form_valid(self, form):
initial = form.save(commit=False)
initial.question = self.get_object()
initial.editor = self.request.user
initial.save()
form.save_m2m()
messages.success(self.request, _('Suggeste edits Question successfully created!'))
return redirect(reverse('question_redirect', kwargs={'pk': initial.pk}))
def get_initial(self):
initial = super(QuestionSuggestedEditsCreate, self).get_initial()
for field, _cls in self.form_class.base_fields.items():
# print(field, _cls)
# title <django.forms.fields.CharField object at 0xb54f4e2c>
# description <django.forms.fields.CharField object at 0xb54f844c>
# tags <django.forms.models.ModelMultipleChoiceField object at 0xb54f830c>
value = getattr(self.get_object(), field) # got a value
# print(field, '-', value)
# title - Lorem ipsum dolor ismet title
# description - Lorem ipsum dolor ismet description
# tags - app_faq.Tag.None # maybe because this?
# print(self.get_object().tags.all())
# <QuerySet [<Tag: ajax>, <Tag: desktop>, <Tag: Django>]>
#initial.update({field: 'no error'})
initial.update({field: value}) # traceback started here..
return initial
def get_context_data(self, **kwargs):
context = super(QuestionSuggestedEditsCreate, self).get_context_data(**kwargs)
context['question'] = self.get_object()
return context
And we got a traceback KeyError: 'manager'
;
Internal Server Error: /question/suggestion/edit/118/
Traceback (most recent call last):
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/core/handlers/base.py", line 217, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/core/handlers/base.py", line 215, in _get_response
response = response.render()
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/response.py", line 107, in render
self.content = self.rendered_content
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/response.py", line 84, in rendered_content
content = template.render(context, self._request)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/backends/django.py", line 66, in render
return self.template.render(context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/base.py", line 207, in render
return self._render(context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/base.py", line 199, in _render
return self.nodelist.render(context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/base.py", line 990, in render
bit = node.render_annotated(context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/base.py", line 957, in render_annotated
return self.render(context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/loader_tags.py", line 177, in render
return compiled_parent._render(context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/base.py", line 199, in _render
return self.nodelist.render(context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/base.py", line 990, in render
bit = node.render_annotated(context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/base.py", line 957, in render_annotated
return self.render(context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/loader_tags.py", line 177, in render
return compiled_parent._render(context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/base.py", line 199, in _render
return self.nodelist.render(context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/base.py", line 990, in render
bit = node.render_annotated(context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/base.py", line 957, in render_annotated
return self.render(context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/loader_tags.py", line 72, in render
result = block.nodelist.render(context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/base.py", line 990, in render
bit = node.render_annotated(context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/base.py", line 957, in render_annotated
return self.render(context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/base.py", line 1046, in render
return render_value_in_context(output, context)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/template/base.py", line 1024, in render_value_in_context
value = force_text(value)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/utils/encoding.py", line 76, in force_text
s = six.text_type(s)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/utils/html.py", line 385, in <lambda>
klass.__str__ = lambda self: mark_safe(klass_str(self))
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/forms/boundfield.py", line 41, in __str__
return self.as_widget()
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/forms/boundfield.py", line 101, in as_widget
attrs = self.build_widget_attrs(attrs, widget)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/forms/boundfield.py", line 257, in build_widget_attrs
if widget.use_required_attribute(self.initial) and self.field.required and self.form.use_required_attribute:
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/utils/functional.py", line 35, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/forms/boundfield.py", line 245, in initial
data = self.form.get_initial_for_field(self.field, self.name)
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/forms/forms.py", line 506, in get_initial_for_field
value = value()
File "/home/agaust/ENV/env-django-faq/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 842, in __call__
manager = getattr(self.model, kwargs.pop('manager'))
KeyError: 'manager'
[22/Sep/2017 21:00:43] "GET /question/suggestion/edit/118/ HTTP/1.1" 500 217200
回答1:
It about m2m relationship, and solved with this;
def get_initial(self):
initial = super(QuestionSuggestedEditsCreate, self).get_initial()
for field, _cls in self.form_class.base_fields.items():
value = getattr(self.get_object(), field)
if field == 'tags':
value = self.get_object().tags.all()
initial.update({field: value})
return initial
Or;
def get_initial(self):
initial = super(QuestionSuggestedEditsCreate, self).get_initial()
for field, _cls in self.form_class.base_fields.items():
value = getattr(self.get_object(), field)
if _cls.__class__.__name__ == 'ModelMultipleChoiceField':
m2m_instance = getattr(self.get_object(), field)
value = m2m_instance.all()
initial.update({field: value})
return initial
来源:https://stackoverflow.com/questions/46366436/keyerror-manager-in-django-get-initial