Home > Software design >  django - submit multiple forms in one post request (different from one click cause I need to process
django - submit multiple forms in one post request (different from one click cause I need to process

Time:12-09

I have three models jobposition, wage, kitfee and they are related by a OneToMany relation.

class JobPosition(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    title = models.ForeignKey(Title, on_delete=models.CASCADE)
    ...    

class Wage(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    amount = models.FloatField(blank=True,null=True)
    type = models.CharField(choices=WAGETYPE, max_length=30)
    position = models.ForeignKey(JobPosition, related_name='wages', on_delete=models.CASCADE, blank=True, null=True)

class KitFee(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    kit_name = models.CharField(max_length=20, blank=True, null=True)
    amount = models.FloatField(blank=True, null=True)
    type = models.CharField(choices=WAGETYPE, max_length=30)
    position = models.ForeignKey(JobPosition, related_name='kit_fees', on_delete=models.CASCADE, blank=True, null=True)

I am building a user interface where a user can create a position with associated wage and kit_fee (let's say just one wage and one kit fee for now).

The problem I am facing is that I am not sure how to make a post request in the right way.

I created these two forms and served them to a django template using a templateview.

class JobPositionForm(forms.ModelForm):
        class Meta:
            model = JobPosition
            fields = ['title','city','dept_head','files','department_budget']
       ...

class WageForm(forms.ModelForm):
        class Meta:
            model = Wage
            exclude = ['id']

my view

class NewPosition(MyLoginRequiredMixin,TemplateView):
    template_name = 'action/crew/position.html'
    def get_context_data(self, **kwargs):
        self.project = get_object_or_404(JobProject, id=kwargs['project_id'])
        context = super().get_context_data(**kwargs)
        context['position_form'] = JobPositionForm(project=self.project, user=self.request.user)
        context['wage_form'] = WageForm()
        context['kit_fee_form'] = KitFeeForm()
        return context

    def post(self,request, **kwargs):
        print(request.POST)
        self.project = get_object_or_404(JobProject, id=kwargs['project_id'])
        position_form = JobPositionForm(request.POST, project=self.project, user=self.request.user)
        wage_form = WageForm(request.POST)
        kit_fee_form = KitFeeForm(request.POST)
        print(kit_fee_form.data['amount'])
        print(wage_form.data['amount'])

The page is rendered smoothly, however I am now realizing that I don't know how to submit those two forms together inside a single post request and also how to initialize the forms in the view when processing the post request.

I thought about using formset but I don't know how to use it with different forms.

I guess I can always do this manually using Javascript to parse each value and place it into the same POST... but I was hoping there was a work around it using some nice django functionality. Especially cause the manual approach doesn't scale well.

<form id="position_form">
    <div id="title_div" style="margin-top: 20px;">
        <label for="id_title" style="margin-bottom: 5px;" >Title</label><br/>
        {{position_form.title}}
    <div id="city_div" style="margin-top: 20px;" onfocus="$('#title_creation_div').hide();">
        <label for="id_city" style="margin-bottom: 5px;" >City</label><br/>
        {{position_form.city}}
    </div>
    <br>
    <div  style="display: inline-block;margin-right: 5px;margin-left: 5px; text-align: center">
            <label for="OtherComp">Department Budget</label><br/>
            {{position_form.department_budget}}
    </div>
    <div  style="display: inline-block;margin-right: 5px;margin-left: 5px; text-align: center">
        <label for="TeamInfo">Department Head</label><br/>
        {{ position_form.dept_head }}
    </div>
   </form>

<form id="wage_form">
 <div id="outer" style="width:100%; margin-top: 20px ">
        <div  style="display: inline-block;margin-right: 5px;margin-left: 5px">
            <label for="{{ wage_form.amount.id_for_label }}">Rate</label><br/>
            {{wage_form.amount}}
        </div>
        
        <div  style="display: inline-block;margin-right: 5px;margin-left: 5px; text-align: center">
         <label for="{{ wage_form.type.id_for_label }}">Rate Type</label><br/>
         {{wage_form.type}}
          </div>
    </div>

</form>

Any idea?

Edit I am using this javascript to send all forms into the same post request and it seems to be working ok. However, I am noticing that many fields have the same id so I can't initiate the forms properly. Also, the process doesn't seem to be scalable if I start adding additional wages/kitfee to the screen.

$("form").submit(function (e) {
        e.preventDefault();
        let data_array = $("form").map(function(){
            return $(this).serializeArray();
        });
        data_array.push({csrfmiddlewaretoken: "{{ csrf_token }}"})
        console.log(data_array)
        $.ajax({
            type: "POST",
            url: "{% if source == 'edit' %}{% url 'action:edit_position' project.id position.id %}{% else %}{% url 'action:new_position' project.id %}{% endif %}",
            data:data_array,
            success:function(html){

                }
            });
    });

enter image description here

CodePudding user response:

Since you are using a model form, you can directly pass in the request into the form instance to process both the forms simultaneously... See a simple signup scenario below where two model forms ( User_form and User_profile_Form) are being processed,

Views.py

def signup(request):
    registered = False

    if request.method == "POST":
        
        user_form = User_form(data=request.POST)
        user_profileform = user_profile_form(data=request.POST)

        if(user_form.is_valid() and user_profileform.is_valid()):
            user = user_form.save()
            user.set_password(user.password)
            user.save()

            profile = user_profileform.save(commit=False)
            profile.user = user

                    
            if 'profile_picture' in request.FILES:
                profile.profile_picture = request.FILES['profile_picture']
            
            profile.save()

            registered = True
        
        else:
            print(user_form.errors, user_profileform.errors)

UPDATE 1 Adding template part

<!DOCTYPE html>
{% extends "base.html" %}
{% load static %}
{% load bootstrap_tags %}

{% block title %}

Signup

{% endblock %}

{% block body %}
    <div >
        {% if registered %}
            <h1>Thankyou for REGISTERING with us</h1>
            <br>
        <a href="{% url 'homepage:home' %}"> click here to continue </a>
        {% else %}
            <a href="{% url 'registration:signin' %}"> <h4 style="text-align: center;" > Already have an account ? </h4></a>
            <h3>PLEASE fill the registration form below</h3>
            <form enctype="multipart/form-data" method="POST">
                <div >
                    {% csrf_token %}
                    <h4>
                    <u>Account Information : </u>
                    {{ user_form |as_bootstrap  }}
                    <br>
                    <hr>
                    <br>
                    <u><h4>Personal Information :</h4></u>
                    {{ user_profileform |as_bootstrap  }}
                    </h4>
                    <input type="submit" class = "btn btn-primary" name="submit" value="Sign Up" style="margin: 0% 15%; width: 70%">
                </div>
            </form>
        {% endif %}

{% endblock %}
  • Related