首页 > 解决方案 > Django ModelForm 不保存到数据库

问题描述

我是 Django 新手,很难弄清楚如何获取模型表单以保存到我的数据库中。我一直在关注一些教程/书籍,并在 SO 上花费了大量时间,但我无法弄清楚这部分内容。我正在关注的书籍示例是创建一个 IMDB 类型的网站,用户可以在其中投票电影质量(在我的示例中更改为游戏)。

python v. 3.6.7,django v. 2.1.3,postgres v. 2.2.2

这是我要存储的模型和相关的管理器

class VoteManager(models.Manager):
    def get_vote_or_unsaved_blank_vote(self, game, user):
        try:
            vote = Vote.objects.get(game=game, user=user)
        return vote
    except self.model.DoesNotExist:
            vote = Vote(game=game, user=user)
        return vote

class Vote(models.Model):
    objects = VoteManager()

    value = models.FloatField()
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    game = models.ForeignKey(Game, on_delete=models.CASCADE,)
    voted_on = models.DateTimeField(auto_now=True)

    class Meta:
        unique_together = ('user', 'game')

现在我尝试使用的模型表单来尝试存储它

class VoteForm(forms.ModelForm):
    user = forms.ModelChoiceField(widget=forms.HiddenInput, queryset=get_user_model().objects.all(), disabled=True)
    game = forms.ModelChoiceField(widget=forms.HiddenInput, queryset=Game.objects.all(), disabled=True)
    value = forms.FloatField()

    class Meta:
        model = Vote
        fields = ('user', 'game', 'value')

我用来显示此信息的模板。

{% block main %}
<h1>{{ object }}</h1>
<p class="lead">
{{ object.summary }}
</p>
{% endblock %}

{% block sidebar %}
 {# rating div omitted #}
  <div>
    {% if vote_form %}
      <form
          method="post"
          action="{{ vote_form_url }}" >
        {% csrf_token %}
        {{ vote_form.as_p }}
        <button
            class="btn btn-primary" >
          Vote
        </button >
      </form >
    <h3>Score: {{ object.score|default_if_none:"No score yet!" }}</h3>
    {% else %}
      <p >Log in to vote for this game</p >
    {% endif %}
  </div >
{% endblock %}

最后是组合所有这些部分的视图

class GameDetail(DetailView):
    queryset = Game.objects.all_with_related_persons_and_score()

    def post(self, request, *args, **kwargs):
        return redirect('core:CreateVote', game_id=kwargs['pk'])

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        if self.request.user.is_authenticated:
            vote = Vote.objects.get_vote_or_unsaved_blank_vote(game=self.object, user=self.request.user)
            if vote.id:
                vote_form_url = reverse('core:UpdateVote', kwargs={'game_id': vote.game.id, 'pk': vote.id})
            else:
                vote_form_url = reverse('core:CreateVote', kwargs={'game_id': self.object.id})
            ctx['vote_form'] = VoteForm(instance=vote)
            ctx['vote_from_url'] = vote_form_url
        return ctx

class CreateVote(LoginRequiredMixin, CreateView):
    form_class = VoteForm

    def get_initial(self):
        initial = super().get_initial()
        initial['user'] = self.request.user.id
        initial['game'] = self.kwargs['game_id']
        return initial

    def get_success_url(self):
        print('never called?')
        game_id = self.kwargs['game_id']
        return reverse('core:GameDetail', kwargs={'pk': game_id})

    def render_to_response(self, context, **response_kwargs):
        game_id = self.kwargs['game_id']
        game_detail_url = reverse('core:GameDetail', kwargs={'pk': game_id})
        return redirect(to=game_detail_url)

我目前的猜测是我只是不知道如何从模板中获取表单,这里的许多示例在请求时创建表单,我一直遵循的教程在 get_context_data 中创建表单,然后将其传递给模板。所以我一直在努力弄清楚如何保存或验证表格是否正确。

对不起所有的文字,但这些片段是如此相互关联,我想确保我包含了所有有用的东西。从数据库显示和读取似乎可以工作,如果我手动进入并通过管理面板添加投票,我可以成功读取它们,当尝试通过投票按钮写入新分数时没有任何反应,下面是终端窗口输出的内容。

[12/Dec/2018 20:24:34] "GET /game/85 HTTP/1.1" 200 2081
[12/Dec/2018 20:46:49] "POST /game/85 HTTP/1.1" 302 0
[12/Dec/2018 20:46:49] "GET /game/vote/85/create HTTP/1.1" 302 0
[12/Dec/2018 20:46:49] "GET /game/85 HTTP/1.1" 200 2081

哦,也许 url 模式可能有用。

app_name = 'core'
urlpatterns = [
    path('', views.MainPage.as_view(), name='MainPage'),
    path('games', views.GameList.as_view(), name='GameList'),
    path('game/<int:pk>', views.GameDetail.as_view(), name='GameDetail'),
    path('game/vote/<int:game_id>/create', views.CreateVote.as_view(), name='CreateVote'),
    path('game/vote/<int:game_id>/update/<int:pk>', views.UpdateVote.as_view(), name='UpdateVote'),
]

在此先感谢,我已经在这个问题上撞墙了一段时间。

标签: pythondjangopython-3.xdjango-forms

解决方案


尝试将 type="submit" 添加到您的按钮:

<button class="btn btn-primary" type="submit">Vote</button >

然后在您的 CreateView 添加一个 form_valid 方法:

class CreateVote(LoginRequiredMixin, CreateView):
    model = Vote
    template_name = 'folder/create_vote.html'
    form_class = VoteForm

    ...

    def form_valid(self, form):
        vote = form.save(commit=False)
        game = Game.objects.get(id=game_id)
        vote.game = game
        vote.save() # You have to save the vote for it to be added to the db.
        return HttpResponseRedirect(reverse('redirect_view'))

推荐阅读