IntegrityError,NOT NULL 约束失败:更新记录时 contest_contestant.contest_id

IntegrityError, NOT NULL constraint failed: contest_contestant.contest_id while updating record

我有两个模型Contest和Contestant,用户可以发起一个比赛,其他用户可以在任何比赛下注册为参赛者...

models.py
class Contest(models.Model):
    contest_title = models.CharField(max_length=30)
    contest_post = models.CharField(max_length=100)
    created_on = models.DateTimeField(auto_now_add=True)
    updated_on = models.DateTimeField(auto_now=True)

    

class Contestant(models.Model):
    contest = models.ForeignKey(Contest, on_delete=models.CASCADE, related_name='participating_contest')
    contestant_name = models.CharField(max_length=10, blank=True, null=True)
    votes = models.IntegerField(default=0)
    created_on = models.DateTimeField(auto_now_add=True)
    updated_on = models.DateTimeField(auto_now=True)

任何参赛者的粉丝都可以为他们最喜欢的参赛者投出无限数量的选票,只要有粉丝投票我想增加 Contestant.votes 随着投票数量的增加,我已经尝试使用 FBV 但它对于我的 django 水平来说太复杂了,我现在正在使用 CBV,但是我收到一个 IntegrityError 说 IntegrityError at /contests/contestant/2/ NOT NULL constraint failed: contest_contestant.contest_id

这个错误对我来说没有意义,因为 contest_id 已经在创建时分配给参赛者,我什至可以从数据库中确认

view.py

class ContestantCreateView(CreateView):
    model = Contestant
    fields = ['contestant_name']

    def form_valid(self, form):
        form.instance.contest_id = self.kwargs.get('pk')
        return super().form_valid(form)

投票逻辑位于参赛者详情视图中,由来自表单

的POST请求触发
views.py

class ContestantDetail(DetailView, FormMixin):
    model = Contestant
    context_object_name = 'contestants'
    template_name = 'contest/contestant_detail.html'
    form_class = VoteForm

    def get_success_url(self):
        return reverse('contest:contestant-detail', kwargs={'pk': self.object.pk})

    def get_context_data(self, *args, **kwargs):
        context = super(ContestantDetail, self).get_context_data(*args, **kwargs)
        context['vote_contestant'] = Contestant.objects.get(pk=self.kwargs.get('pk'))
        return context

    def post(self, request, *args, **kwargs):
        form = self.get_form()
        self.object = self.get_object()

        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

    def form_valid(self, form, *args, **kwargs):
        contestant = Contestant.objects.get(pk=self.kwargs['pk'])
        vote_count = form.cleaned_data['votes']
        contestant.votes += vote_count
        form.save()
        messages.success(self.request, f'You have successfully casted your vote.')
        return super().form_valid(form)



forms.py

class VoteForm(forms.ModelForm):
    class Meta:
        model = Contestant
        fields = ['votes']

html form template

<form action="" method="post">
                {% csrf_token %}
                {% include 'contest/bs4_form.html' with form=form %}

                <button type="submit">Vote Now</button>
            </form>

下面是我的urls.py

    path('contestant/<int:pk>/new/', views.ContestantCreateView.as_view(), name='new-contestant'),
    path('contestant/<int:pk>/edit/', views.ContestantUpdateView.as_view(), name='edit-contestant'),
    path('contestant/<int:pk>/', views.ContestantDetail.as_view(), name='contestant-detail'),

通过使用 form.save() 您正在保存表单,因为您没有将实例传递给表单,这意味着 form.save() 将尝试创建一个 new 记录。因此,您应该从 form_valid(…) 方法中省略 form.save()

from django.db.models import F

def form_valid(self, form, *args, **kwargs):
    contestant = Contestant.objects.get(pk=self.kwargs['pk'])
    vote_count = form.cleaned_data['votes']
    contestant<b>.votes = F('votes') + vote_count</b>
    contestant.save()
    # <strong>no</strong> form.save()
    messages.success(self.request, f'You have successfully casted your vote.')
    return super().form_valid(form)