Django - 根据模型字段生成 excel 报告

Posted

技术标签:

【中文标题】Django - 根据模型字段生成 excel 报告【英文标题】:Django - Generate excel reports based on model fields 【发布时间】:2016-08-21 20:00:40 【问题描述】:

该应用程序基于 django/angular 构建。我想根据模型和用户选择的字段生成一个excel报告。您可以在下面找到搜索 UI。我在 django 中有 4 个模型。 CoachPlayerParticipation,外键引用Club(一对多关系)。各个Django模型将作为选择输入和模型字段作为选项

models.py

from datetime import datetime
from django.db import models


class Club(models.Model):
    name = models.CharField(max_length=200)
    estd = models.IntegerField()
    address = models.CharField(max_length=200)



    def __unicode__(self):
        return "%s" % self.name


class Coach(models.Model):
    fname = models.CharField(max_length=80)
    lname = models.CharField(max_length=80)
    age = models.IntegerField()
    fk = models.ForeignKey(Club, related_name='coaches')

    def __unicode__(self):
        return "%s" % self.fname


class Player(models.Model):
    fname = models.CharField(max_length=80)
    lname = models.CharField(max_length=80)
    country = models.CharField(max_length=42)
    fk = models.ForeignKey(Club, related_name='players')

    def __unicode__(self):
        return "%s" % self.fname


class Participation(models.Model):
    league = models.CharField(max_length=80)
    startdate = models.DateTimeField()
    fk = models.ForeignKey(Club, related_name='participations')

    def __unicode__(self):
        return "%s" % self.league

搜索用户界面(选择下拉菜单)

#####       ######      #######     #############
Club        Coach       Player      Participation
#####       ######      #######     #############
name        fname       fname       league
estd        lname       lname       startdate
address     age         country     

用例

- User have to select at least one field from the Club dropdown. 
- User can select one or more fields from Coach, Player and Participation dropdown.

HTML

<select class="form-control" data-ng-model="selected" data-ng-options="item.tablefield for item in coach" ng-click="addField()"></select>

<select class="form-control" data-ng-model="selected" data-ng-options="item.tablefield for item in player" ng-click="addField()"></select>

<select class="form-control" data-ng-model="selected" data-ng-options="item.tablefield for item in participation" ng-click="addField()"></select>


<button type="button" class="btn btn-default" ng-click="report()">Generate report</button>

Angular JS

    $scope.club = [

            'tablename': 'Club',
            'tablefield': 'name'
        ,
        
            'tablename': 'Coach',
            'tablefield': 'estd'
        ,
        
            'tablename': 'Coach',
            'tablefield': 'address'
        
    ];

    $scope.coach = [

            'tablename': 'Coach',
            'tablefield': 'fname'
        ,
        
            'tablename': 'Coach',
            'tablefield': 'lname'
        ,
        
            'tablename': 'Coach',
            'tablefield': 'age'
        
    ];

    $scope.player = [

            'tablename': 'Player',
            'tablefield': 'fname'
        ,
        
            'tablename': 'Player',
            'tablefield': 'lname'
        ,
        
            'tablename': 'Player',
            'tablefield': 'country'
        
    ];

    And Similar for participation



    $scope.queryfields = [];

    // add fields
    $scope.addField = function()

        var found = $scope.queryfields.some(function (el) 
            return el.value === $scope.selected.tablefield;
        );


        if (!found) 
            var searchkey = $scope.selected.tablename,
                searchvalue = $scope.selected.tablefield;

            $scope.queryfields.push(
                key:   searchkey,
                value: searchvalue
            )
        
        else
            console.log('field already exist');  
        
    ;



    // SEARCH 
    $scope.report = function()   
        if($scope.queryfields.length > 1)
            // post search fields data 
            $http.post('/api/gamify/advancesearch/', $scope.queryfields)
                .success(function (response) 
                    $scope.queryset = response;
                )
                .error(function (data, status, headers, config) 
                    console.log('error');
            );
        
    ;

选择输入中的选定字段被发送到 django 视图以进行查询和结果连接。 发送到 django 视图的数据如下所示

[u'value': u'name', u'key': u'Club', u'value': u'fname', u'key': u'Coach', u'value': u'lname', u'key': u'Coach', u'value': u'fname', u'key': u'Player',  u'value': u'league', u'key': u'Participation']

观看次数

def report(request):
    qfields = json.loads(request.body)

    print query
    """ [u'value': u'name', u'key': u'Club', u'value': u'fname', u'key': u'Coach', u'value': u'lname', u'key': u'Coach', u'value': u'fname', u'key': u'Player',  u'value': u'league', u'key': u'Participation']"""

    # TO-DO
    # Get all records of Club (field: name)
    # Get all records of Coach (fields: fname, lname) which is reference of Club.
    # Get all records of Player (field: fname) which is reference of Club.
    # Get all records of Participation (field: league) which is reference of club.
    # Export to excel
    # Response json object

    records = Player.objects.order_by('id').values('id', *qfields)

    return HttpResponse(json.dumps(list(records)))

这就是 json 响应的样子。 JSON 响应将被转换为 excel 文件

  
    "datarow1":  
        "Club":[  
              
                "club.name":"FC Bar"
            ,
              
                "coach":  
                    "coach.fname":[  
                        "Hari",
                        "Shyam",
                        "Parbe"
                    ]
                
            ,
              
                "player":[  
                      
                        "player.fname":[  
                            "King",
                            "Leo",
                            "Singh"
                        ]
                    ,
                      
                        "player.lname":[  
                            "Dev",
                            "Fin"
                        ]
                    
                ]
            ,
              
                "participation":[  
                      
                        "participation.league":[  
                            "la liga",
                            "UEFA"
                        ]
                    
                ]
            
        ]
    , 
    "datarow2":  
        "Club":[  
              
                "club.name":"FC TU"
            ,
              
                "coach":  
                    "coach.fname":[  
                        "Xavi",
                        "Hola",
                        "Them"
                    ]
                
            ,
              
                "player":[  
                      
                        "player.fname":[  
                            "Sab",
                            "Hi",
                            "Suz"
                        ]
                    ,
                      
                        "player.lname":[  
                            "Messi",
                            "Aura"
                        ]
                    
                ]
            ,
              
                "participation":[  
                      
                        "participation.league":[  
                            "Italian",
                            "Premier"
                        ]
                    
                ]
            
        ]
    , 


帮助

如何根据选定的模型字段获取俱乐部的所有记录和与之相关的外键数据(教练、球员、参与)? 报告示例如上所示。

感谢任何帮助和反馈。

【问题讨论】:

添加您的模型的代码。否则无法为您提供具体答案。 models 代码已添加! 在您的示例输出中,同一俱乐部的球员可以有不同的教练,但这并未反映在您的模型中。为此,您必须在 Player 模型中向 Coacher 添加一个 ForeignKey。 @Risadinha 球员和教练在这种情况下没有关系!我只想根据他们的字段获取Club 和相关models (Coach, Player, Participation) 的所有记录。够清楚吗? 然后修正你的例子。您的模型无法实现您的示例结果。您必须了解自己的数据关系是什么以及要输出什么。 【参考方案1】:

您尚未提供模型的代码。

一般来说,您可以使用QueryManager 中非常有用的方法.values().values_list() 来获取某些字段的列表。您可以使用__ 引用值的关系,例如club__name

我想你的导出中的一行是指一位玩家。因此,您必须从玩家模型开始建立关系。

例子:

Player.objects.order_by('lname').values('lname', 'coach__fname', 'coach__lname', 'club__name', 'club__league')

ManyToMany 字段更难。它们可能需要在 QueryManager 上进行聚合或 extraselect 调用。

【讨论】:

Export to excel line 你的意思是? 我正在使用选择相关方法获取重复数据!有什么解决办法吗? distinct() 在查询集上可能会有所帮助。您应该了解为什么会出现重复 - 这样您就可以确定 distinct 是否确实是正确的方法或查询是否错误。【参考方案2】:

试试这个代码

def report(request):
    query = json.loads(request.body)

    print query
    """ [u'value': u'name', u'key': u'Club', u'value': u'fname', u'key': u'Coach', u'value': u'lname', u'key': u'Coach', u'value': u'fname', u'key': u'Player',  u'value': u'league', u'key': u'Participation']"""

    clubs = Club.objects.all()
    result = 
    for index, club in enumerate(clubs):
        coach_fname = club.coach_set.all().values_list('fname', flat=True)
        player_fname = club.player_set.all().values_list('fname', flat=True)
        player_lname = club.player_set.all().values_list('lname', flat=True)
        participation_leage = club.participation_set.all().values_list('league')

        out_put = []
        club_details = "club.name": club.name 
        coach_details = "coach":"coach.fname": list(coach_fname) 
        player_details =  "player":[   "player.fname": list(player_fname),  "player.lname": list(player_lname)]
        participation_details =  "participation":[   "participation.league": list(participation_leage)]

        out_put.append(club_details)
        out_put.append(coach_details)
        out_put.append(player_details)
        out_put.append(participation_details)

        result.update( ['datarow'.format(index)]['Club']: out_put)


    return HttpResponse(json.dumps(result))

【讨论】:

谢谢@Anoop! AttributeError: club object has no attribute coach_set.all()。注意:示例中提供的模型字段只是一个用例。 模型字段根据用户在前端选择的内容而有所不同。看起来我们已经很接近了! 我修复了AttributeError: club object has no attribute coach_set.all() 错误! 我使用了选择相关键而不是club.coach_set.all()。所以club.coaches.all().【参考方案3】:

事实上,有一个实用程序可以让您从 Django 查询集中导出 csv 数据,它具有从链接到查找字段的所有功能:django-queryset-csv。

使用示例:

from djqscsv import render_to_csv_response

def csv_view(request):
  qs = Player.objects.order_by('lname').values('lname', 'coach__fname', 'coach__lname', 'club__name', 'club__league')
  return render_to_csv_response(qs)

查看azavea blog 了解更多使用示例。希望对您有所帮助。

【讨论】:

感谢您提及django-queryset-csv 我正在使用选择相关方法获取重复数据!有什么解决办法吗? 您能分享您的尝试以及有关该问题的更多详细信息吗? records = Player.objects.order_by('id').values('id', *qfields)。当我进行这样的查询时,我会看到数据中有一些重复。 重复是在records还是在csv数据中?

以上是关于Django - 根据模型字段生成 excel 报告的主要内容,如果未能解决你的问题,请参考以下文章

django 模型-----定义模型

django模型详解

从显示自定义字段的 Django 模型呈现可排序表的最佳方法?

django基础知识之定义模型:

django form表单

根据另一个字段的值验证 Django 模型字段?