问题
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