3

I'm quite desperate now and I cannot figure this out. To me it should be easy to do, but I have not come across any answers that explains this.

Two models with no foreign keys between them:

class Employee(models.Model):
    surname = models.CharField(max_length=100)
    name = models.CharField(max_length=100)


class Salary(models.Model):
    date = models.DateField(auto_now_add=True)
    surname = models.CharField(max_length=100)
    name = models.CharField(max_length=100)
    salary = models.DecimalField(max_digits=20, decimal_places=2)

One modelformset to save to ModelB.

SalaryFormSet = modelformset_factory(Salary, extra=0)

Then in views.py:

def createForm(request):
    formset = SalaryFormSet(queryset=Employee.objects.all())
    return render(request, 'formfile.html', {'formset': formset})

def submitForm(request)
    f = ModelBFormSet(request.POST)
    if f.is_valid():
        f.save()
        return HttpResponse('Submitted successfully')
    else:
        return HttpResponse(f.errors, request.POST)

In formfile.html:

<form action="submitForm/" method="post">
    {{ formset.management_form }}
    <table>
        {{ formset }}
    </table>
    {% csrf_token %}
    <input type="submit" value="Submit">
</form> 

As soon as I hit Submit, the formset is parsed as invalid and f.errors states (for each row in Employee):

<ul class="errorlist"><li>id<ul class="errorlist"><li>Select a valid choice. That choice is not one of the available choices.</li></ul></li></ul>

I just want to have surname and name from all rows in Employee preloaded into SalaryFormSet, and I should enter salary for each row and save them to Salary. The records in Salary should not be updated, but a new entry should be created.

The Employee model already has records created from the admin site. As employees' salaries increase, I will generate payslips from Salary model and capture the relevent salary from the latest date.

If I change the queryset to queryset=Salary.objects.none() and change SalaryFormSet to extra=2, the template is rendered empty. If I insert surnames, names and salary manually, the formset saves correctly. Two new entries in Salary. Why can't I just have the name preloaded (should I load them as str()?) and manually add the salary?

4
  • Can't understand what you're trying to do here at all. Why are you passing a queryset of modelA to the modelB formset? Perhaps a less abstract example would help. Commented Feb 20, 2015 at 8:26
  • @DanielRoseman I updated the question to be less abstract. Commented Feb 20, 2015 at 8:51
  • But you're still passing a queryset of Employees to a Salary formset, which makes no sense. And I also don't understand why you don't have a FK between them: surely a Salary belongs to an Employee? Commented Feb 20, 2015 at 9:10
  • @DanielRoseman The queryset of Employees is only to populate the Salary formset so that I don't have to enter names and surnames each time weekly salaries change. i don't see the need for the foreign key. The Salary model works independantly from the Employees models, I just want to auto fill some fields from the Employee model. I appreciate your concern for the FK, but (in this case) I just want them to work seperately. Commented Feb 20, 2015 at 9:26

2 Answers 2

1

As I said in the comment, it doesn't make sense to pass a queryset of Employees to the instantiation of the Salary formset. I think given you're trying to keep these two models completely separate for whatever reason, and you want to create new Salary instances each time, you would be better off just passing a set of initial data.

This is slightly tricky, because initial only applies to extra forms, and extra is set by the formset factory, so you need to do it in the view. Something like this:

employees = Employee.objects.values('name', 'surname')
SalaryFormSet = modelformset_factory(Salary, extra=len(employees))
formset = SalaryFormSet(initial=employees, queryset=Salary.objects.none())
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for this! It does work perfectly! I know the method is strange, but this is really all I needed! I'll answer the question with a thorough example.
1

This is just to summarize the answer, based on Daniel Roseman's solution.

In models.py:

class Employee(models.Model):
    surname = models.CharField(max_length=100)
    name = models.CharField(max_length=100)


class Salary(models.Model):
    date = models.DateField(auto_now_add=True)
    surname = models.CharField(max_length=100)
    name = models.CharField(max_length=100)
    salary = models.DecimalField(max_digits=20, decimal_places=2)

In forms.py:

employees = Employee.objects.values('surname', 'name')
SalaryFormSet = modelformset_factory(Salary, extra=len(employees)

In views.py:

def createForm(request):
    formset = SalaryFormSet(initial=employees, queryset=Salary.objects.none())
    return render(request, 'formfile.html', {'formset': formset})

def submitForm(request)
    f = ModelBFormSet(request.POST)
    if f.is_valid():
        f.save()
        return HttpResponse('Submitted successfully')
    else:
        return HttpResponse(f.errors, request.POST)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.