Django m2m 表单保存”通过“桌子

发布于 2024-09-06 02:46:43 字数 1296 浏览 9 评论 0原文

我在保存包含“通过”类表的 m2m 数据时遇到问题。 我想将所有选定的成员(在表单中选择)保存在直通表中。 但我不知道如何初始化视图中的“通过”表。

我的代码:

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() 

我应该如何初始化成员资格以便正确填充成员资格表?

I'm having trouble in saving a m2m data, containing a 'through' class table.
I want to save all selected members (selected in the form) in the through table.
But i don't know how to initialise the 'through' table in the view.

my code:

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')

and in the view:

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() 

How should I initialise the membership for the Membership table to be populated right?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

朕就是辣么酷 2024-09-13 02:46:43

如果使用正常的 m2m 关系(不通过中间表),您可以替换:

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

with

form.save_m2m()

但如果使用中间表,您需要手动处理 POST 数据并创建包含所有必填字段的 Membership 对象 (类似问题)。最基本的解决方案是将您的视图更改为以下内容:

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'] 将始终返回一个对象!)。

您可以修改此代码以使其更可靠(错误处理等),并且更详细,例如:

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

但请注意,您正在循环中执行一些数据库查询,这通常不是一个好主意(就性能而言)。

In case of using normal m2m relation (not through intermediary table) you could replace:

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

with

form.save_m2m()

But in case of using intermediary tables you need to manually handle POST data and create Membership objects with all required fields (similar problem). The most basic solution is to change your view to something like:

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())

Note how request.POST is manipulated (.getlist). This is because post and get are QueryDict objects which has some implications (request.POST['members'] will return always one object!).

You can modify this code to get it more reliable (error handling etc.), and more verbose, eg:

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

But note that you are performing some db queries in a loop which is not a good idea in general (in terms of performance).

眸中客 2024-09-13 02:46:43

就像 dzida 所做的那样,但使​​用 form.cleaned_data 而不是 request.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 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

Like what dzida did, but use form.cleaned_data instead of request.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 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())

You also need to consider some memberships might be deleted, so:

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())

If you use model forms (like in a generic CBV: form_class=ClassroomForm), override and put the saving logic above in the save method, something like:

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
蓝海似她心 2024-09-13 02:46:43

您还需要为成员指定教室:

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

我想您还应该删除 accept = models.BooleanField(User) 中的 User 。如果您使用 auto_now,则无需在保存时设置日期!但也许 `auto_now_add 更可能是您所需要的(http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.DateField

You also need to specify the classroom for the membership:

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

I guess you should also remove User in accept = models.BooleanField(User). It shouldn't be necessary to set the date upon saving if you are using auto_now! But maybe `auto_now_add is more likely what you need (http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.DateField)

爱已欠费 2024-09-13 02:46:43

这就是我在通用 UpdateForm 基于类的视图 (django 1.8) 中使用 form_valid 方法为类似但不同的应用程序执行此操作的方法。

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)

This is how I did it in a generic UpdateForm class-based view (django 1.8) for a similar yet different application using the form_valid method.

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文