1

Models

attendance_choices = (
    ('absent', 'Absent'),
    ('present', 'Present')
)

class Head_of_department(models.Model):
    first_name = models.CharField(max_length=200)
    last_name = models.CharField(max_length=200)
    email = models.CharField(max_length=30)

    def __str__(self):
        return self.first_name 

class Employee(models.Model):
    first_name = models.CharField(max_length=200, unique=True)
    last_name = models.CharField(max_length=200, unique=True)
    head_of_department = models.ForeignKey('Head_of_department', on_delete=models.SET_NULL, blank=True, null=True)
    email = models.EmailField(max_length=100)

     def __str__(self):
        return self.first_name + ' ' + self.last_name

class Attendance(models.Model):
    head_of_department = models.ForeignKey('Head_of_department', on_delete=models.SET_NULL, blank=True, null=True)
    employee = models.ForeignKey('Employee', on_delete=models.CASCADE, )
    attendance = models.CharField(max_length=8, choices=attendance_choices, blank=True)

Views

class Attendancecreate(CreateView):
    model = Attendance
    fields = ['employee']
    success_url = '/dashboard/'

    def get_context_data(self,** kwargs):
        context = super(Attendancecreate, self).get_context_data(**kwargs)
        context['formset'] = AttendanceFormset(queryset=Attendance.objects.none())
        context['attendance_form'] = Attendanceform()
        email = self.request.user.email
        hod = Head_of_department.objects.get(email=email)
        context["employees"] = Employee.objects.filter(head_of_department =hod)
        return context

    def get_initial(self):
        email = self.request.user.email
        hod = Head_of_department.objects.get(email=email)
        initial = super(Attendancecreate , self).get_initial()
        initial['employee'] = Employee.objects.filter(head_of_department=hod)
        return initial

    def post(self, request, *args, **kwargs):
        formset = AttendanceFormset(request.POST)
        if formset.is_valid():
            return self.form_valid(formset)

     def form_valid(self, formset):
        instances = formset.save(commit=False)
        for instance in instances:
            instance.head_of_department = get_object_or_404(Head_of_department, email=self.request.user.email)
            instance.save()
        return HttpResponseRedirect('/dashboard/')

Forms

class Attendanceform(ModelForm):
    class Meta:
        model = Attendance
        fields = ('employee','attendance','head_of_department')

AttendanceFormset = modelformset_factory(Attendance,fields=('attendance',))

Template

{% csrf_token %}
{{ formset.management_form }}
    {% for employee in employees %}
        {% for form in formset %}
            {{employee.first_name}} {{ form }}
    {   % endfor %}<br><br>
    {% endfor %}

The webapp has a login feature. The headofdepartment can mark the attendance . List of employees are rendered in the template without any issues , I want to mark attendance to the respective employees sorted in ascending order of their first_name .

That is when marking attendance employees will be listed in template, and to the right attendance form will be displayed for all the employees . It is saving only one object and not assigning the initial value for employee

Requirement :

enter image description here

Joel Deleep
  • 1,308
  • 2
  • 14
  • 36
  • Django class-based views tackle very common things, but don't solve everything. The `CreateView` is for one object. As you say, you need a view that implements a modelformset (or maybe even an inlinemodelformset), so create your own view for that. – dirkgroten May 27 '19 at 11:31
  • but is there a way to pass the rendered list of employees as employee in the attendance form ? I am unaware writing a model formset in such a way that it accepts the rendered list employees as the form value – Joel Deleep May 27 '19 at 11:33
  • 1
    Just look at the [docs](https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/). You need to create the forms with the initial values already set for each employee. You don't "pass the rendered list of employees...". – dirkgroten May 27 '19 at 11:38
  • I followed the docs and used initial (updated the question ) , but it's not assigning the initial value to attendance and only saving one object . In this for about 5 days – Joel Deleep May 28 '19 at 05:42
  • Is `AttendanceFormset` created with the `inlineformset_factory`? Then when you instantiate the formset, you need to set initial: `formset = AttendanceFormset(instance=initial_hod, initial=[{'employee': employee} for employee in self.get_initial()['employee'])` and the same for `post()` where you add `data=request.POST`. – dirkgroten May 28 '19 at 07:53
  • no it is done using modelformset , i have updated the question ,please check – Joel Deleep May 28 '19 at 07:56
  • You should use the inlineformset_factory, with fields 'employee' and 'attendance'. Also don't loop through the employees in your template, you only need to loop through the forms in the formset. – dirkgroten May 28 '19 at 07:58
  • can you help me with an answer , i would be thankful . Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/194037/discussion-between-coder13-and-dirkgroten). – Joel Deleep May 28 '19 at 08:02

1 Answers1

2

Following dirkgroten I was able to solve the issue, answer allow to render a list employees under the head_of_department(logged in hod) and mark respective attendance .

Models

attendance_choices = (
    ('absent', 'Absent'),
    ('present', 'Present')
)

class Head_of_department(models.Model):
    first_name = models.CharField(max_length=200)
    last_name = models.CharField(max_length=200)
    email = models.CharField(max_length=30)

    def __str__(self):
        return self.first_name 

class Employee(models.Model):
    first_name = models.CharField(max_length=200, unique=True)
    last_name = models.CharField(max_length=200, unique=True)
    head_of_department = models.ForeignKey('Head_of_department', on_delete=models.SET_NULL, blank=True, null=True)
    email = models.EmailField(max_length=100)

     def __str__(self):
        return self.first_name + ' ' + self.last_name

class Attendance(models.Model):
    head_of_department = models.ForeignKey('Head_of_department', on_delete=models.SET_NULL, blank=True, null=True)
    employee = models.ForeignKey('Employee', on_delete=models.CASCADE, )
    attendance = models.CharField(max_length=8, choices=attendance_choices, blank=True)

Views

class Attendancecreate(CreateView):
    model = Attendance
    form_class = Attendanceform
    success_url = '/dashboard/'

    def get_context_data(self,** kwargs):
        context = super(Attendancecreate, self).get_context_data(**kwargs)
        context['formset'] = AttendanceFormset(queryset=Attendance.objects.none(), instance=Head_of_department.objects.get(email=self.request.user.email), initial=[{'employee': employee} for employee in self.get_initial()['employee']])
        return context

    def get_initial(self):
        email = self.request.user.email
        head_of_department = Head_of_department.objects.get(email=email)
        initial = super(Attendancecreate , self).get_initial()
        initial['employee'] = Employee.objects.filter(head_of_department=head_of_department)
        return initial

    def post(self, request, *args, **kwargs,):
        formset = AttendanceFormset(request.POST,queryset=Attendance.objects.none(), instance=Head_of_department.objects.get(email=self.request.user.email), initial=[{'employee': employee} for employee in self.get_initial()['employee']])
        if formset.is_valid():
            return self.form_valid(formset)

    def form_valid(self,formset):
        instances = formset.save(commit=False)
        for instance in instances:
            instance.head_of_department = get_object_or_404(Head_of_department, email=self.request.user.email)
            instance.save()
        return HttpResponseRedirect('/dashboard/')

Forms

class Attendanceform(ModelForm):
    class Meta:
        model = Attendance
        widgets = {'employee' : HiddenInput}
        fields = ('employee','attendance','hod')
AttendanceFormset = inlineformset_factory(Head_of_department,Attendance,form=Attendanceform,fields=('attendance','employee'))

Template

{% csrf_token %}
{{ formset.management_form }}
   {% for form in formset %}
      {{ form.employee.initial }} {{ form.employee}}  {{ form.attendance }}
<br><br>
   {% endfor %}
Joel Deleep
  • 1,308
  • 2
  • 14
  • 36
  • What was the urls.py code or the way you called the index page? – Mahhdy Mar 07 '20 at 00:32
  • 1
    path('dashboard/attendance',views.attendance,name='attendance'), the answer is based on last years django version , but the basic working flow is known from the answer – Joel Deleep Mar 10 '20 at 06:25