首页 > 解决方案 > 具有两个 ForeignKey 关系的 CreateView 时出现 KeyError

问题描述

楷模

我在 Journals 应用程序中创建了两个模型。一种模型用于日记 ( to_journal),另一种模型用于日记条目 ( to_journal_entry)。to_journal 模型通过“journal user”与用户模型相关,to_journal_entry 模型to_journal通过journal_name.

它看起来像这样:

在此处输入图像描述

模型.py

class to_journal(models.Model):
    journal_name = models.CharField(max_length = 40)
    slug = AutoSlugField(populate_from='journal_name')
    date_created = models.DateTimeField(auto_now_add=True)
    journal_user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE,)

    def __str__(self):
        return str(self.journal_user) + " " + self.name

    def get_absolute_url(self):
        return reverse('to-journals')


class to_journal_entry(models.Model):
    body = models.TextField()
    entry_date = models.DateTimeField(auto_now_add=True)
    journal_name = models.ForeignKey(to_journal, on_delete=models.CASCADE,)
    journal_user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE,)

    def __str__(self):
        return str(self.journal_name) + " " + str(self.entry_date)

    def get_absolute_url(self):
         return reverse('to_journals', args=[str(self.slug)])

意见

我已成功为to_journal. 在相关页面上,我输入我想给我的期刊的期刊名称,按“添加”按钮,页面更新,显示更新的期刊列表。这是通过以下CreateToJournal视图实现的。

在此处输入图像描述

我想为日记条目实现同样的目标。一旦我“进入”任何给定的期刊,我希望能够输入文本,并且我希望页面重新加载并仅更新该特定期刊的条目列表。

在此处输入图像描述

错误

一旦我在这里按下添加按钮,这是我得到的错误:

在此处输入图像描述

对于这一行:

在此处输入图像描述

我在这一步遇到了问题。当我写我的form_valid

def form_valid(self, form):
        current_journal_id = to_journal.objects.get(id=self.kwargs['id'])
        form.instance.journal_user = self.request.user
        form.instance.journal_name = current_journal_id.journal_name
        return super(ToJournalEntriesList, self).form_valid(form)

我通过说来指定用户,form.instance.journal_user = self.request.user并通过说或类似的东西来指定当前日志form.instance.journal_name = to_journal.objects.get(id=self.kwargs['id']).journal_name(下面是我尝试过的其他事情的列表)。

视图.py

class CreateToJournal(LoginRequiredMixin, CreateView):
    model = to_journal
    template_name = 'to_journals/to_journal_list.html'
    fields = ('journal_name',)

    def form_valid(self, form):
        form.instance.journal_user = self.request.user
        return super(CreateToJournal, self).form_valid(form)

    def get_context_data(self, **kwargs):
        context = super(CreateToJournal, self).get_context_data(**kwargs)
        context['to_journals'] = to_journal.objects.filter(journal_user=self.request.user)
        return context


class ToJournalEntriesList(LoginRequiredMixin, CreateView):
    model = to_journal_entry
    template_name = 'to_journals/to_journal_entries_list.html'
    fields = ('body',)
    success_url = reverse_lazy('to-journal-entries')

def form_valid(self, form):
    # line below should get the current object (Parent Journal)
    current_journal_id = to_journal.objects.get(id=self.kwargs['id'])

    form.instance.journal_user = self.request.user

    # Line below should set the journal name for the form as the journal name of the object I got earlier.
    form.instance.journal_name = current_journal_id.journal_name
    return super(ToJournalEntriesList, self).form_valid(form)

def get_context_data(self, **kwargs):
    context = super(ToJournalEntriesList, self).get_context_data(**kwargs)
    context['to_journal_entries'] = to_journal.objects.filter(journal_user=self.request.user)
    context['to_journal_entries'] = to_journal_entry.objects.filter(pk=self.kwargs.get('pk'))
    return context

我努力了

这些给了我DoesNotExist错误,这很奇怪,因为我位于日志中,它应该会自动拾取。

数据库

只是想也显示我正在使用的数据库。它有一个id列,所以假设应该可以正常工作:

在此处输入图像描述

模板

<h1 class="green-button" onclick="inputJournal(); this.onclick=null;">Add Entry</h1>
  <div id="new-journal">
     <form class="" id="myForm" action="" method="post">
       {% csrf_token %}
       {{ form }}
       <button type="submit" id="add-button">Add</button>
     </form>
  </div>

对不起,很长的帖子!如果需要任何额外的信息,我很乐意提供更多信息。我真的很感谢大家看看。

最好的,拉苏尔

编辑

网址

to_journals/urls.py

from django.urls import path
from .views import CreateToJournal, ToJournalEntriesList


urlpatterns = [
    path('', CreateToJournal.as_view(), name='to-journals'),
    path('<slug:slug>', ToJournalEntriesList.as_view(), name='to-journal-entries'),
]

根 urls.py

urlpatterns = [
    path('admin/', admin.site.urls),

    path('users/', include('users.urls')),
    path('users/', include('django.contrib.auth.urls')),

    path('', include('pages.urls')),

    path('to-journals/', include('to_journals.urls')),

] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \
+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

编辑 2

在建议的答案之后,这是新的错误。

在此处输入图像描述

在此处输入图像描述

编辑 3 - 工作修复(感谢 Daniel Roseman)

def form_valid(self, form):
        current_journal = to_journal.objects.get(journal_user=self.request.user, slug=self.kwargs['slug'])
        form.instance.journal_user = self.request.user
        form.instance.journal_name = current_journal
        return super(ToJournalEntriesList, self).form_valid(form)

变化在于 kwargs 调用(slug 而不是 id)和命名约定current_journal而不是current_journal_id

标签: djangodjango-formsdjango-viewskeyword-argument

解决方案


self.kwargs包含在该视图的 URL 中传递的命名参数。从模式中我们可以看出,在 URL 中传递的唯一 kwarg 是slug,它清楚地引用了期刊的 slug 字段;在屏幕截图的情况下,sleep。所以这就是我们需要在方法中使用的值和字段来查找它:

current_journal_id = to_journal.objects.get(slug=self.kwargs['slug'])

但是请给您的对象名称以反映它们的实际情况。上面我们得到的是实际的日志,而不是 id;叫它current_journal。同样,入口的外键指向期刊,而不是期刊名称;你应该命名 FK to_journal(虽然我也不明白为什么你的模型首先被称为,而不仅仅是Journal)。

编辑

您的第二个问题是由您令人困惑的命名约定直接引起的。它应该是:

form.instance.journal_name = current_journal_id

(不是current_journal_id.journal_name)。如果您正确命名事物,那将是

form.instance.journal = current_journal

这会更清晰,更不容易出错。


推荐阅读