使用 ModelForm Django 保存 ManytoManyField 的问题

Problem Saving ManytoManyField using ModelForm Django

models.py

from django.db import models
from django.contrib.auth.models import User


class Elements(models.Model):
    element = models.CharField(max_length=10, unique=True)

    def __str__(self):
        return self.element


class Hero(models.Model):
    added = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
    name = models.CharField(max_length=10, unique=True)
    element = models.ManyToManyField(Elements, blank=True)

    def __str__(self):
        return self.name

forms.py

from django import forms
from .models import Elements, Hero


class HeroForm(forms.ModelForm):
    class Meta:
        model = Hero
        exclude = [
            'added'
        ]
        widgets = {
            'element': forms.CheckboxSelectMultiple
        }

views.py

from django.shortcuts import render
from .forms import HeroForm


def home(request):
    form = HeroForm(request.POST or None)
    if form.is_valid():
        hero = form.save(commit=False)
        hero.added = request.user
        hero.save()


        form = HeroForm()

    return render(request, 'home.html', {'form': form})

每当我尝试像上面 views.py 中所示那样在保存前操作模型时,元素的 (manytoamyfield) 数据会自动设置为空。但是,如果我保存表单,因为它保存了用户选择的元素数据。

如何在保存表单之前操作表单数据并按原样保留 manytomanyfield 数据?

提前致谢

如果使用commit=False,则ModelForm不能保存多对多关系,因为此时对象没有主键。

您可以在 保存表格之前简单地更改表格中的实例:

from django.contrib.auth.decorators import login_required

@login_required
def home(request):
    if request.method == 'POST':
        form = HeroForm(request.POST)
        if form.is_valid():
            form<b>.instance.added = request.user</b>
            form<b>.save()</b>  # <i>no</i> commit=False
            form = HeroForm()
    else:
        form = HeroForm()
    return render(request, 'home.html', {'form': form})

Note: In case of a successful POST request, you should make a redirect [Django-doc] to implement the Post/Redirect/Get pattern [wiki]. This avoids that you make the same POST request when the user refreshes the browser.


Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.


Note: You can limit views to a view to authenticated users with the @login_required decorator [Django-doc].