Django ModelForm не сохраняется в БД - PullRequest
0 голосов
/ 12 декабря 2018

Я новичок в Django и с трудом выясняю, как получить модельную форму для сохранения в моей БД.Я следил за некоторыми учебниками / книгами и тратил много времени на SO, и я просто не могу понять эту часть.Приведенные ниже примеры книг приводят создание веб-сайта типа IMDB, где пользователь может голосовать за качество фильмов (в моем примере это были игры).

python v. 3.6.7, django v. 2.1.3, postgresv. 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'),
]

Заранее спасибо, я некоторое время бил головой об стену на этом.

Ответы [ 2 ]

0 голосов
/ 13 декабря 2018

Это было болезненное решение, простая опечатка.В get_context_data моего GameDetail я настраиваю данные для шаблона, чтобы использовать, одним из этих полей был URL для публикации на

ctx['vote_from_url'] = vote_form_url

В шаблоне, когда я попытался сослаться на это, я написал его с ошибкой

 action="{{ vote_form_url }}" >

Меня огорчает то, что это не приводит к ошибке в шаблоне, если я добавляю что-то, по умолчанию это URL родительского представления.Я должен был заметить, что POST шел по неправильному URL, но мне интересно, есть ли параметр или журнал, который бы сказал мне, что я ссылаюсь на что-то в шаблоне, который не существует.Надеюсь, что это резюме поможет кому-то, кто застрянет в подобной ситуации.

0 голосов
/ 13 декабря 2018

Попробуйте добавить 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'))
...