创建由外键字段关联的 2 个 Django 模型的 Excel 报告

Create a Excel report of 2 Django Models related by a ForeignKey Field

我有两个这样的模型:

class NominaEnc(models.Model):
    G1 = "PERSONAL"
    G2 = "SUPERVISOR"
    G3 ="AUXILIAR"

    GRUPO_CHOICES = (
        (G1, 'PERSONAL'),
        (G2, 'SUPERVISOR'),
        (G3, 'AUXILIAR'),
    )

    fecha_nomina= models.DateField()
    planta =models.ForeignKey(PlantaNomina,to_field='descripcion_planta',on_delete=models.CASCADE)
    area=models.ForeignKey(AreaNomina, on_delete=models.CASCADE, to_field='descripcion_area')
    linea =models.ForeignKey(lineaNomina, on_delete=models.CASCADE, to_field='descripcion_linea')
    grupo=models.CharField(choices=GRUPO_CHOICES, max_length=30, blank=True, null =True)
    supervisor=models.ForeignKey(SupervisorNomina, on_delete=models.CASCADE, 
        to_field='nombre_supervisor')
    semana = models.IntegerField(default=1 )
    plantilla = models.IntegerField(default=0)

    def __str__(self):
        return'{} {} {} {} {}'.format(self.semana, self.area, self.linea, self.grupo, 
        self.supervisor)

    class Meta:
        verbose_name_plural ="Encabezados Nomina"
        verbose_name = "Encabezado Nomina"

class NominaDet(models.Model):

    nomina = models.ForeignKey(NominaEnc, related_name='detalles' ,on_delete=models.CASCADE)
    concepto=models.ForeignKey(ConceptoNomina, on_delete=models.CASCADE, to_field='concepto')
    cantidad =models.FloatField(default=0.0)


    def __str__(self):
        return "{} {}".format(self.nomina,self.concepto)


    class Meta:
        verbose_name_plural ="Detalles Nomina"
        verbose_name = "Detalle Nomina"

我的观点是:

class NominaList( generic.ListView):
    model=NominaEnc
    template_name='nomina/nomina_list.html'
    context_object_name='nomina'

class NominaCompletaList(generic.ListView):
    template_name='nomina/nomina_completa.html'
     context_object_name='nomina'
    queryset = NominaEnc.objects.all()

    def get_context_data(self, **kwargs):
        context = super(NominaCompletaList, self).get_context_data(**kwargs)
        context['detalles'] = NominaDet.objects.all()
        context['encabezado'] = self.queryset
        return context

和 url 是:

urlpatterns = [
path('nomina/', NominaList.as_view(), name="nomina_list"),
path('nomina_completa/', NominaCompletaList.as_view(), name="nomina_completa")
]

我想创建一个显示两个模型数据的 XLSX 文件 (Excel)。我已经完成了 NominaEnc 模型(父模型),但我无法将 NominaEnc 和 NominaDet 模型的数据加入其中。

创建报告我是这样做的:

from django.shortcuts import render

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views .generic.base import TemplateView
from django.http.response import HttpResponse
from openpyxl import Workbook
from openpyxl.styles import Alignment, Border,Font,PatternFill,Side

from django.views import generic
from django.urls import reverse_lazy

from .models import NominaEnc, NominaDet

class ReporteNomina(TemplateView):
def get (self, request, *args, **kwargs):

    query = NominaEnc.objects.all()
    wb = Workbook()

    ws = wb.active
    ws.tittle='Nomina'


    #Establer el nombre del archivo
    nombre_archivo = "Reporte Nomina.xlsx"
    ws['B1'].alignment= Alignment(horizontal='left', vertical='center')
    ws['B1'].border =Border(left=Side(border_style='thin'),right=Side(border_style='thin'),
                        top=Side(border_style='thin'), bottom=Side(border_style='thin'))

    ws['B1'].fill = PatternFill(start_color='66FFCC', end_color='66FFCC', fill_type='solid')
    ws['B1'].font = Font(name='calibri', size=12, bold=True)
    ws['B1']='Company'

    ws.merge_cells('B1:F1')

    ws['B2'].alignment= Alignment(horizontal='left', vertical='center')
    ws['B2'].border =Border(left=Side(border_style='thin'),right=Side(border_style='thin'),
                        top=Side(border_style='thin'), bottom=Side(border_style='thin'))

    ws['B2'].fill = PatternFill(start_color='66FFCC', end_color='66FFCC', fill_type='solid')
    ws['B2'].font = Font(name='calibri', size=12, bold=True)
    ws['B2']='Department'

    ws.merge_cells('B2:F2')
    ws['B3'].alignment= Alignment(horizontal='left', vertical='center')
    ws['B3'].border =Border(left=Side(border_style='thin'),right=Side(border_style='thin'),
                        top=Side(border_style='thin'), bottom=Side(border_style='thin'))

    ws['B3'].fill = PatternFill(start_color='66FFCC', end_color='66FFCC', fill_type='solid')
    ws['B3'].font = Font(name='calibri', size=12, bold=True)
    ws['B3']='Reporte de Nomina'

    ws.merge_cells('B3:F3')

    ws.row_dimensions[1].height=20
    ws.row_dimensions[2].height=20
    ws.row_dimensions[3].height=20

    ws.column_dimensions['B'].width=20
    ws.column_dimensions['C'].width=20
    ws.column_dimensions['D'].width=20
    ws.column_dimensions['E'].width=20


    ws['B6'].alignment= Alignment(horizontal='center', vertical='center')
    ws['B6'].border =Border(left=Side(border_style='thin'),right=Side(border_style='thin'),
                        top=Side(border_style='thin'), bottom=Side(border_style='thin'))
    ws['B6'].fill = PatternFill(start_color='66CFCC', end_color='66CFCC', fill_type='solid')
    ws['B6'].font = Font(name='calibri', size=11, bold=True)
    ws['B6']='Semana'


    ws['C6'].alignment= Alignment(horizontal='center', vertical='center')
    ws['C6'].border =Border(left=Side(border_style='thin'),right=Side(border_style='thin'),
                        top=Side(border_style='thin'), bottom=Side(border_style='thin'))
    ws['C6'].fill = PatternFill(start_color='66CFCC', end_color='66CFCC', fill_type='solid')
    ws['C6'].font = Font(name='calibri', size=11, bold=True)
    ws['C6']='Area'

    controlador = 7
    for q in query:
        ws.cell(row=controlador,column=2).alignment= Alignment(horizontal='center', vertical='center')
        ws.cell(row=controlador,column=2).border =Border(left=Side(border_style='thin'),right=Side(border_style='thin'),
                            top=Side(border_style='thin'), bottom=Side(border_style='thin'))
        ws.cell(row=controlador,column=2).fill = PatternFill(start_color='66CFCC', end_color='66CFCC', fill_type='solid')
        ws.cell(row=controlador,column=2).font = Font(name='calibri', size=11, bold=True)
        ws.cell(row=controlador,column=2).value=q.semana

        ws.cell(row=controlador,column=3).alignment= Alignment(horizontal='center', vertical='center')
        ws.cell(row=controlador,column=3).border =Border(left=Side(border_style='thin'),right=Side(border_style='thin'),
                            top=Side(border_style='thin'), bottom=Side(border_style='thin'))
        ws.cell(row=controlador,column=3).fill = PatternFill(start_color='66CFCC', end_color='66CFCC', fill_type='solid')
        ws.cell(row=controlador,column=3).font = Font(name='calibri', size=11, bold=True)
        ws.cell(row=controlador,column=3).value=q.area

        #contador+=1
        controlador +=1

    response = HttpResponse(content_type='application/ms-excel')
    contenido = "attachment; filename = {0}".format(nombre_archivo)
    response["Content-Disposition"] = contenido
    wb.save(response)
    return response

问题是如何在NominaDet模型的字段nomina中定义连接两个模型数据的查询?

您应该使用 NominaEnc 对象示例

nom = NominaEnc.objects.first()

nom.detalles.all()

或类似 .first(), .filter() 等...