6

中間モデルを使用する 2 つのモデル間に M2M 関係があります。説明のために、マニュアルの例を使用しましょう。

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __unicode__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __unicode__(self):
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

CRUD 処理ビューの作成を避けるために、Django のクラスベースのビューを利用したいと思います。ただし、デフォルトの CreateView を使用しようとすると、機能しません。

class GroupCreate(CreateView):
    model=Group

これにより、Group オブジェクトのすべてのフィールドを含むフォームがレンダリングされ、メンバー フィールドの複数選択ボックスが提供されます。これは、単純な M2M 関係に適しています。ただし、date_joined または invoke_reason を指定する方法はなく、フォームを送信すると次の AttributeError が返されます。

「中間モデルを指定する ManyToManyField に値を設定できません。代わりにメンバーシップのマネージャーを使用してください。」

一般的な CreateView の一部をオーバーライドする、または独自のカスタム ビューを作成して mixin でこれを行うためのきちんとした方法はありますか? Admin インターフェイスはインラインを使用して中間体との M2M 関係を原子的に処理するため、これはフレームワークの一部であるべきだと思われます。

4

5 に答える 5

6

拡張する必要がありますCreateView:

from django.views.generic import CreateView

class GroupCreate(CreateView):
    model=Group

をオーバーライドしますform_valid():

from django.views.generic.edit import ModelFormMixin
from django.views.generic import CreateView

class GroupCreate(CreateView):
    model = Group

    def form_valid(self, form):
        self.object = form.save(commit=False)
        for person in form.cleaned_data['members']:
            membership = Membership()
            membership.group = self.object
            membership.person = person
            membership.save()
        return super(ModelFormMixin, self).form_valid(form)

ドキュメントにあるように、membershipと の間の関係ごとに新しい を作成する必要がありgroupますperson

form_validここでオーバーライド を見ました: Using class-based UpdateView on a mtm with an intermediary model

于 2013-04-01T14:48:54.967 に答える
2
class GroupCreate(CreateView):
    model = Group

    def form_valid(self, form):
        self.object = form.save(commit=False)

        ### delete current mappings
        Membership.objects.filter(group=self.object).delete()

        ### find or create (find if using soft delete)
        for member in form.cleaned_data['members']:
            x, created = Membership.objects.get_or_create(group=self.object, person=member)
            x.group = self.object
            x.person = member
            #x.alive = True # if using soft delete
            x.save()
        return super(ModelFormMixin, self).form_valid(form)
于 2015-07-29T16:43:21.513 に答える
0

「参考までに、私はクラスベースのビューを使用することにはなりませんでした。代わりに、次のようなことを行いました。

def group_create(request):
    group_form = GroupForm(request.POST or None)
    if request.POST and group_form.is_valid():
        group = group_form.save(commit=False)
        membership_formset = MembershipFormSet(request.POST, instance=group)
        if membership_formset.is_valid():
            group.save()
            membership_formset.save()
            return redirect('success_page.html')
    else:
        # Instantiate formset with POST data if this was a POST with an invalid from,
        # or with no bound data (use existing) if this is a GET request for the edit page.
        membership_formset = MembershipFormSet(request.POST or None, instance=Group())

    return render_to_response(
        'group_create.html',
        {
            'group_form': recipe_form,
            'membership_formset': membership_formset,
        },
        context_instance=RequestContext(request),
    )

これはクラスベースの実装の出発点かもしれませんが、これをクラスベースのパラダイムに押し込もうとするのは時間の無駄であるほど単純です。

于 2012-12-22T04:39:32.843 に答える
0

CBV を使用する場合、commit=True でフォームを保存する必要があるため、グループが作成され、メンバーシップの作成に使用できる ID が与えられます。それ以外の場合、commit=False の場合、グループ オブジェクトにはまだ ID がなく、エラーが発生します。

于 2013-12-09T19:21:07.943 に答える
0

ほんの数日前、私はまったく同じ問題に直面していました。Django には、中間の m2m 関係の処理に問題があります。

これは私が便利だと思った解決策です:

1. Define new CreateView
class GroupCreateView(CreateView):
    form_class = GroupCreateForm
    model = Group
    template_name = 'forms/group_add.html'
    success_url = '/thanks'

次に、定義済みフォーム - GroupCreateForm の保存方法を変更します。保存は、変更をDBに永続化する責任があります。ORM だけではこれを機能させることができなかったので、生の SQL も使用しました。

1. Define new CreateView
class GroupCreateView(CreateView):


class GroupCreateForm(ModelForm):
    def save(self):
        # get data from the form
        data = self.cleaned_data
        cursor = connection.cursor()
        # use raw SQL to insert the object (in your case Group)
        cursor.execute("""INSERT INTO group(group_id, name)
                          VALUES (%s, %s);""" (data['group_id'],data['name'],))
        #commit changes to DB
        transaction.commit_unless_managed()
        # create m2m relationships (using classical object approach)
        new_group = get_object_or_404(Group, klient_id = data['group_id'])
        #for each relationship create new object in m2m entity
        for el in data['members']:
            Membership.objects.create(group = new_group, membership = el)
        # return an object Group, not boolean!
        return new_group

注: ご覧のとおり、モデルを少し変更しました (シリアルを使用せずに、主キーに独自の IntegerField を使用しています。get_object_or_404

于 2012-12-20T11:58:00.963 に答える