Django Admin: Many-to-Many listbox doesn't show up with a through parameter

前端 未结 4 1310
灰色年华
灰色年华 2021-02-01 08:42

I have the following models:

class Message(models.Model):
    date = models.DateTimeField()
    user = models.ForeignKey(User)    
    thread = models.ForeignKey         


        
4条回答
  •  悲哀的现实
    2021-02-01 09:20

    I learned a lot from @Fedor's answer, but some comments and cleanup may be still beneficial.

    class ForumAdminForm(forms.ModelForm):
        messages = forms.ModelMultipleChoiceField(
                       queryset=Message.objects.all(),
                       widget=FilteredSelectMultiple('Message', False))
    
    
        # Technically, you don't need to manually set initial here for ForumAdminForm
        # However, you NEED to do the following for MessageAdminForm
        def __init__(self, *args, **kwargs):
            if 'instance' in kwargs:
                # a record is being changed. building initial
                initial = kwargs.setdefault('initial', {})
                initial['messages'] = [t.message.pk for t in kwargs['instance'].message_forum_set.all()]
            super(ForumAdminForm, self).__init__(*args, **kwargs)
    
        def save(self, commit=True):
            if not self.is_valid():
                raise HttpResponseForbidden
            instance = super(ForumAdminForm, self).save(self, commit)
            def save_m2m_with_through():
                messages = [t for t in self.cleaned_data['messages']
                old_memberships = instance.message_forum_set.all()
                for old in old_memberships:
                    if old.message not in messages:
                        # and old membership is cleaned by the user
                        old.delete()
                for message in [x for x in messages not in map(lambda x: x.message, old_memberships)]:                   
                    membership = Member_forum(message=messsage, forum=instance) 
                    # You may have to initialize status, position and tag for your need
                    membership.save()
            if commit:
                save_m2m_with_through()
            else:
                self.save_m2m = save_m2m_with_through
            return instance
    
        class Meta:
            model = Forum
            fields = {'name', 'messages')
    

    There's one caveat: if you have another many-to-many relationship in the models (that is without through), super(ForumAdminForm, self).save(self, commit) will set self.save_m2m in case commit is False. However, calling this would cause an error, because this function also tries to save the many-to-many with through as well. You may need to save all other many-to-many relationship manually, or catch the exception, or else.

提交回复
热议问题