如何在点击后更新Django模型的total_points字段值?附代码示例
Is the Desired Feasible with Current Code?
No, the current setup won’t work to implement the "add/subtract points" functionality. Here’s why:
- Your
views.pyonly handles GET requests—there’s no logic to process form submissions (POST requests) from the template. - The template uses form fields (
{{ form.name }}etc.) but your view doesn’t pass a form instance to the context, so those fields won’t render properly. - The
points_filterline has a bug:total_pointsis an IntegerField, but you’re filtering withtotal_points=True(which will only match entries wheretotal_points=1, probably not what you intended). - There’s no code to adjust
total_pointsbased on the submittedpluspoints/minuspointsvalues.
Alternative Implementation Solutions
Solution 1: Server-Side Form Submission (Basic Approach)
This fixes the current code to handle form submissions and update points on the server.
- Create a ModelForm (add
forms.pyto your app):
from django import forms from .models import test class TestPointsForm(forms.ModelForm): class Meta: model = test fields = ['name', 'pluspoints', 'minuspoints']
- Update the View to handle GET/POST and update points:
from django.shortcuts import render, redirect from .models import test from .forms import TestPointsForm def points(request): # Fix the filter example: show entries with positive points points_filter = test.objects.filter(total_points__gt=0) points_count = test.objects.count() if request.method == 'POST': form = TestPointsForm(request.POST) if form.is_valid(): name = form.cleaned_data['name'] add_points = form.cleaned_data['pluspoints'] subtract_points = form.cleaned_data['minuspoints'] # Get or create a record for the given name point_record, created = test.objects.get_or_create(name=name) # Adjust total points if add_points: point_record.total_points += 1 if subtract_points: point_record.total_points -= 1 point_record.save() return redirect('points') # Prevent duplicate submissions else: form = TestPointsForm() context = { 'form': form, 'points_filter': points_filter, 'points_count': points_count, } return render(request, 'point/points.html', context)
- Optional: Make Plus/Minus Mutually Exclusive
If you don’t want users to select both options (which would cancel out), replace the two checkboxes with radio buttons in your form:
class TestPointsForm(forms.ModelForm): POINT_ACTION_CHOICES = [ ('plus', 'Add 1 Point'), ('minus', 'Subtract 1 Point'), ] point_action = forms.ChoiceField(choices=POINT_ACTION_CHOICES, widget=forms.RadioSelect) class Meta: model = test fields = ['name', 'point_action']
Then update your template to use {{ form.point_action|as_crispy_field }} instead of the two checkbox fields.
Solution 2: AJAX for Seamless Updates (No Page Reload)
For a better user experience, use AJAX to update points without reloading the page.
- Add an AJAX Handler View to
views.py:
from django.http import JsonResponse from .models import test def update_points(request): if request.method == 'POST': name = request.POST.get('name') action = request.POST.get('action') # 'plus' or 'minus' point_record, created = test.objects.get_or_create(name=name) if action == 'plus': point_record.total_points += 1 elif action == 'minus': point_record.total_points -= 1 point_record.save() return JsonResponse({'success': True, 'new_total': point_record.total_points}) return JsonResponse({'success': False})
- Add a URL Pattern for the AJAX view in
urls.py:
from django.urls import path from . import views urlpatterns = [ path('points/', views.points, name='points'), path('update-points/', views.update_points, name='update_points'), ]
- Modify the Template to use buttons and AJAX:
<div id="points_container"> {% csrf_token %} <div class="row"> <div class="col-3"> <input type="text" id="name_input" placeholder="Enter name" required> </div> <div class="col-3"> <button type="button" class="btn btn-success" id="plus_btn">Add 1 Point</button> </div> <div class="col-3"> <button type="button" class="btn btn-danger" id="minus_btn">Subtract 1 Point</button> </div> </div> <div id="update_result" class="mt-2"></div> </div> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script> $(document).ready(function() { function sendPointUpdate(action) { const name = $('#name_input').val(); if (!name) { $('#update_result').text('Please enter a name first!'); return; } $.ajax({ url: "{% url 'update_points' %}", type: "POST", data: { 'name': name, 'action': action, 'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val() }, success: function(response) { if (response.success) { $('#update_result').text(`Updated total: ${response.new_total}`); } else { $('#update_result').text('Failed to update points.'); } }, error: function() { $('#update_result').text('Something went wrong.'); } }); } $('#plus_btn').click(() => sendPointUpdate('plus')); $('#minus_btn').click(() => sendPointUpdate('minus')); }); </script>
Quick Best Practices Note
- Follow Django conventions: Rename your model from
testtoTest(PascalCase) for clarity. - Use more descriptive model names like
UserPointRecordinstead oftestto avoid confusion.
内容的提问来源于stack exchange,提问作者Yuksel Bastan
相关产品推荐
相关产品推荐

