You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于外键筛选批量编辑Django现有Choice模型条目求助

Hey there! Let's get this sorted out for your Django 2.0.4 poll app. You're on the right track with modelformset—probably just missing a few key bits like filtering the formset to the specific Question and handling the foreign key association when saving. Here's a step-by-step working solution:

1. Confirm Your Model Setup (align with official tutorial)

First, make sure your polls/models.py matches the base structure (adjust if you've modified it):

from django.db import models

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

2. Create Choice Form & FormSet

Create a polls/forms.py file (if it doesn't exist) to define your form and formset:

from django import forms
from django.forms import modelformset_factory
from .models import Choice

# Simple form for Choice - we only expose the editable field
class ChoiceForm(forms.ModelForm):
    class Meta:
        model = Choice
        fields = ['choice_text']

# Generate a formset with 2 extra empty fields for new options
ChoiceFormSet = modelformset_factory(
    Choice,
    form=ChoiceForm,
    extra=2,
    can_delete=False  # Remove this line if you want to let users delete options
)

3. Build the Login-Protected View

Add this view to polls/views.py to handle editing choices for a specific Question:

from django.shortcuts import get_object_or_404, render, redirect
from django.contrib.auth.decorators import login_required
from .models import Question
from .forms import ChoiceFormSet

@login_required
def edit_choices(request, pk):
    # Fetch the target Question instance
    question = get_object_or_404(Question, pk=pk)
    
    if request.method == 'POST':
        # Initialize formset with POST data, filtered to this Question's choices
        formset = ChoiceFormSet(
            request.POST,
            queryset=Choice.objects.filter(question=question)
        )
        if formset.is_valid():
            # Save each form, ensuring the foreign key links to the current Question
            for form in formset:
                if form.cleaned_data:  # Skip empty extra forms the user didn't fill
                    choice = form.save(commit=False)
                    choice.question = question
                    choice.save()
            # Redirect back to the edit page (or to your question detail page)
            return redirect('polls:edit_choices', pk=pk)
    else:
        # Load existing choices for the Question on GET request
        formset = ChoiceFormSet(queryset=Choice.objects.filter(question=question))
    
    return render(request, 'polls/edit_choices.html', {
        'question': question,
        'formset': formset
    })

4. Update Your URL Configuration

Add this pattern to polls/urls.py:

from django.urls import path
from . import views

app_name = 'polls'
urlpatterns = [
    # ... your existing URLs ...
    path('question/<int:pk>/edit-choices/', views.edit_choices, name='edit_choices'),
]

5. Create the Edit Template

Make polls/templates/polls/edit_choices.html to render the formset:

<!DOCTYPE html>
<html>
<head>
    <title>Edit Choices: {{ question.question_text }}</title>
</head>
<body>
    <h1>Edit Choices for "{{ question.question_text }}"</h1>
    
    <form method="post">
        {% csrf_token %}
        {{ formset.management_form }}  <!-- DO NOT OMIT THIS - critical for formset functionality -->
        
        {% for form in formset %}
            <div style="margin: 10px 0;">
                {{ form.id }}  <!-- Hidden field to track existing forms -->
                <label>Option {{ forloop.counter }}:</label>
                {{ form.choice_text }}
                {% if form.errors %}
                    <span style="color: red; margin-left: 10px;">{{ form.choice_text.errors }}</span>
                {% endif %}
            </div>
        {% endfor %}
        
        <button type="submit">Save Changes</button>
    </form>
    
    <p style="margin-top: 20px;"><a href="{% url 'polls:detail' question.id %}">Back to Question</a></p>
</body>
</html>

Key Tips to Avoid Pitfalls:

  • Never skip formset.management_form: This hidden form contains metadata Django needs to process the formset correctly (like how many forms exist). Omitting it will throw errors.
  • Filter the queryset: By limiting the formset to the current Question's choices, you ensure you're only editing options tied to that specific question.
  • Skip empty extra forms: The if form.cleaned_data check prevents saving blank options if the user doesn't fill out the extra fields.
  • Login protection: The @login_required decorator enforces your requirement that only logged-in users can access this page.

Test it out by navigating to /polls/question/<your-question-pk>/edit-choices/ after logging in—you'll see existing choices plus 2 empty fields to add new options. All edits and new choices will be saved to the correct Question.

内容的提问来源于stack exchange,提问作者johntkrpt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:03:16