KeyError: 'manager' in django get_initial

2019-08-26 20:19发布

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条回答
放我归山
2楼-- · 2019-08-26 21:11

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
查看更多
登录 后发表回答