Django форма commit=false после как сохранить данные полей многие ко многим

Model.py

class Branch(models.Model): # Branch Master
    status_type = (
        ("a",'Active'),
        ("d",'Deactive'),
    )
    name = models.CharField(max_length=100, unique=True)
    suffix = models.CharField(max_length=8, unique=True)
    Remark = models.CharField(max_length=200, null=True, blank=True)
    created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    create_at = models.DateTimeField(auto_now_add=True)
    update_at = models.DateTimeField(auto_now=True)
    status = models.CharField(max_length=1, choices = status_type, default = 'a')
    def __str__(self):
        return self.name


class Vendor(models.Model):
    status_type = (
        ("a",'Active'),
        ("d",'Deactive'),
    )
    branch = models.ManyToManyField(Branch)
    company = models.CharField(max_length=200)
    name = models.CharField(max_length=200)
    phone = models.CharField(max_length=11, unique = True)
    email  =  models.EmailField(max_length=254, unique = True)
    gst = models.CharField(max_length=15, unique = True)
    pan_no = models.CharField(max_length=10, unique = True)
    add_1 = models.CharField(max_length=50, null=True, blank = True)
    add_2 = models.CharField(max_length=50, null=True, blank = True)
    add_3 = models.CharField(max_length=50, null=True, blank = True)
    Remark = models.CharField(max_length=200, null=True, blank=True)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE)
    create_at = models.DateTimeField(auto_now_add=True)
    update_at = models.DateTimeField(auto_now=True)
    status = models.CharField(max_length=1, choices = status_type, default = 'a')
    
    def __str__(self):
        return self.company

form.py я хочу сохранить как поле created_by

class VendorForm(ModelForm): class Meta: model = Vendor поля = 'all' exclude = ['created_by', 'branch'] виджеты = { 'company':forms.TextInput(attrs={'class':'form-control'}), 'name':forms.TextInput(attrs={'class':'form-control'}), 'phone':forms.TextInput(attrs={'class':'form-control'}), 'email':forms.EmailInput(attrs={'class':'form-control'}), 'gst':forms.TextInput(attrs={'class':'form-control'}), 'pan_no':forms.TextInput(attrs={'class':'form-control'}), 'add_1':forms.TextInput(attrs={'class':'form-control'}), 'add_2':forms.TextInput(attrs={'class':'form-control'}), 'add_3':forms.TextInput(attrs={'class':'form-control'}), 'Remark':forms.Textarea(attrs={'class':'form-control','rows':'2'}), 'status':forms.Select(attrs={'class':'form-control'}), }

Views.py У меня есть ветвь в сессии. Я хочу сохранить с веткой, которая является полем многие ко многим

    def Add_Vendor(request): # for vendor add
        msg = ""
        msg_type = ""
        branch_id = request.session['branch_id']
        branch_data = Branch.objects.get(id = branch_id)
        form = ""
        if request.method == "POST":
            try:
                form = VendorForm(request.POST)
                if form.is_valid:
                    vendor_add = form.save(commit=False)
                    vendor_add.created_by = request.user
                    vendor_add.instance.branch = branch_data.id
                    vendor_add.save()
                    form.save_m2m() # for m to m field save                
                    msg_type = "success"
                    msg = "Vendor Added."
                    form = VendorForm(initial={'branch':branch_id})
            except:
                msg_type = "error"
                msg = str(form.errors)
                print(msg)
        else:
            form = VendorForm(initial={'branch':branch_id})
        context = {
            'form':form,
            'branch_data':branch_data,
            'msg_type':msg_type,
            'msg':msg,
            'btn_type':'fa fa-regular fa-plus',
            'form_title':'Vendor Form',
            'tree_main_title':'Vendor',
            'v_url':'vendor_page',
            'tree_title':'Add Form',
        }
        return render(request, 'base/vendor_master/form_vendor.html',context)

Я бы посоветовал не работать с commit=False в первую очередь:

def Add_Vendor(request):  # for vendor add
    branch_id = request.session['branch_id']
    branch_data = get_object_or_404(Branch, pk=branch_id)
    if request.method == 'POST':
        form = VendorForm(request.POST, request.FILES)
        if form.is_valid():
            form.instance.created_by = request.user
            form.instance.branch = branch_data.id
            vendor_add = form.save()
            vendor_add.branch.add(branch_data)
            return redirect('name-of-some-view')
    else:
        form = VendorForm()
    context = {
        'form': form,
        'branch_data': branch_data,
        'btn_type': 'fa fa-regular fa-plus',
        'form_title': 'Vendor Form',
        'tree_main_title': 'Vendor',
        'v_url': 'vendor_page',
        'tree_title': 'Add Form',
    }
    return render(request, 'base/vendor_master/form_vendor.html', context)

Вы можете упростить свою форму, автоматически добавляя form-control к каждому виджету:

class VendorForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            attrs = field.widget.attrs
            attrs['class'] = attrs.get('class', '') + ' form-control'

    class Meta:
        model = Vendor
        exclude = ['created_by', 'branch']

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: You can set a field editable=False [Django-doc]. Then the field does not show up in the ModelForms and ModelAdmins by default. In this case for example with created_by.


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: Please do not pass messages manually to the template. Django has the messages framework [Django-doc], which allows to add messages to the request, which will then be delivered the next time a template renders these messages. This makes delivering multiple messages convenient, as well as setting different log levels to the messages.

Вернуться на верх