17

'through'クラステーブルを含むm2mデータの保存に問題があります。選択したすべてのメンバー(フォームで選択)をスルーテーブルに保存したいと思います。しかし、ビューの「through」テーブルを初期化する方法がわかりません。

私のコード:

class Classroom(models.Model):
     user = models.ForeignKey(User, related_name = 'classroom_creator')
     classname = models.CharField(max_length=140, unique = True)
     date = models.DateTimeField(auto_now=True)
     open_class = models.BooleanField(default=True)
     members = models.ManyToManyField(User,related_name="list of invited members", through = 'Membership')

class Membership(models.Model): 
      accept = models.BooleanField(User)
      date = models.DateTimeField(auto_now = True) 
      classroom = models.ForeignKey(Classroom, related_name = 'classroom_membership')
      member = models.ForeignKey(User, related_name = 'user_membership')

とビューで:

def save_classroom(request):
   classroom_instance = Classroom()
   if request.method == 'POST':
        form = ClassroomForm(request.POST, request.FILES, user = request.user) 
        if form.is_valid():
           new_obj = form.save(commit=False)
           new_obj.user = request.user 
           new_obj.save()
           membership = Membership(member = HERE SELECTED ITEMS FROM FORM,classroom=new_obj)

           membership.save() 

Membershipテーブルに正しく入力されるようにメンバーシップを初期化するにはどうすればよいですか?

4

4 に答える 4

23

通常の m2m リレーション (中間テーブルを介さない) を使用する場合は、次のように置き換えることができます。

membership = Membership(member = HERE SELECTED ITEMS FROM FORM,classroom=new_obj)
membership.save()

form.save_m2m()

ただし、中間テーブルを使用する場合は、手動で POST データを処理し、必要なすべてのフィールドを持つメンバーシップ オブジェクトを作成する必要があります (同様の問題)。最も基本的な解決策は、ビューを次のように変更することです。

def save_classroom(request):
    if request.method == 'POST':
        form = ClassroomForm(request.POST, request.FILES)

        if form.is_valid():
           new_obj = form.save(commit=False)
           new_obj.user = request.user 
           new_obj.save()

           for member_id in request.POST.getlist('members'):
                membership = Membership.objects.create(member_id = int(member_id), classroom = new_obj)
           return HttpResponseRedirect('/')
    else:
        form = ClassroomForm()
    return render_to_response('save_classroom.html', locals())

request.POST の操作方法 (.getlist) に注意してください。これは、post と get が何らかの意味を持つQueryDictオブジェクトであるためです (request.POST['members'] は常に 1 つのオブジェクトを返します!)。

このコードを変更して、信頼性を高め (エラー処理など)、より冗長にすることができます。たとえば、次のようになります。

member = get_object_or_404(User, pk = member_id)
membership = Membership.objects.create(member = member , classroom = new_obj)

ただし、ループ内でいくつかの db クエリを実行していることに注意してください。これは、一般的に (パフォーマンスの点で) 良い考えではありません。

于 2010-06-26T20:25:11.900 に答える
5

dzida が行ったことと同様ですが、request.post の代わりに form.cleaned_data を使用します。

def save_classroom(request):
    if request.method == 'POST':
        form = ClassroomForm(request.POST, request.FILES)

        if form.is_valid():
           new_obj = form.save(commit=False)
           new_obj.user = request.user
           new_obj.save()

           for member in form.cleaned_data['members'].all():
                Membership.objects.create(member = member,  classroom = new_obj)

           return HttpResponseRedirect('/')
    else:
        form = ClassroomForm()
    return render_to_response('save_classroom.html', locals())

一部のメンバーシップが削除される可能性があることも考慮する必要があるため、次のようになります。

def save_classroom(request):
    if request.method == 'POST':
        form = ClassroomForm(request.POST, request.FILES)

        if form.is_valid():
           new_obj = form.save(commit=False)
           new_obj.user = request.user
           new_obj.save()

           final_members = form.cleaned_data['members'].all()
           initial_members = form.initial['members'].all()

           # create and save new members
           for member in final_members:
                if member not in initial_members:
                    Membership.objects.create(member = member,  classroom = new_obj)

           # delete old members that were removed from the form
           for member in initial_members:
               if member not in final_members:
                   Membership.objects.filter(member = member, classroom = new_obj).delete()

           return HttpResponseRedirect('/')
    else:
        form = ClassroomForm()
    return render_to_response('save_classroom.html', locals())

モデル フォームを使用する場合 (一般的な CBV: のようにform_class=ClassroomForm)、オーバーライドして、上記の保存ロジックをsaveメソッドに配置します。次のようになります。

ClassroomForm(forms.ModelForm):
    members = ModelMultipleChoiceField(
        queryset=Classroom.objects.all(),
        widget=SelectMultiple
    )

    def save(self, commit=True):
        classroom = super().save(commit=False)
            if commit:
                classroom.save()
                if 'members' in self.changed_data:
                   final_members = self.cleaned_data['members'].all()
                   initial_members = self.initial['members']

                   # create and save new members
                   for member in final_members:
                        if member not in initial_members:
                            Membership.objects.create(member = member,  classroom = new_obj)

                   # delete old members that were removed from the form
                   for member in initial_members:
                       if member not in final_members:
                           Membership.objects.filter(member = member, classroom = new_obj).delete()

         return classroom
于 2016-11-26T20:19:06.033 に答える
1

メンバーシップのクラスルームも指定する必要があります。

membership = Membership(member = request.user,
                        classroom=new_obj) #if new_obj if your classroom
membership.save()

Userで削除する必要があると思いますaccept = models.BooleanField(User)auto_now!を使用している場合は、保存時に日付を設定する必要はありません。しかし、おそらく `auto_now_add が必要な可能性が高いです ( http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.DateField )

于 2010-06-19T11:14:12.693 に答える
0

これは、form_valid メソッドを使用して、同様であるが異なるアプリケーションのために、一般的な UpdateForm クラスベースのビュー (django 1.8) でそれを行った方法です。

def form_valid(self, form):
    """
    If the form is valid, save the associated model.
    """
    self.object.members.clear()
    self.object = form.save(commit=False)
    self.object.user = self.request.user 
    self.object.save()

    list_of_members = form.cleaned_data['members']

    ClassRoom.objects.bulk_create([
            Membership(
                Course=self.object,
                member=member_person,
                order=num)
            for num, member_person in enumerate(list_of_members)
        ])
    return super(ModelFormMixin, self).form_valid(form)
于 2015-12-31T14:22:39.543 に答える