ListCreateAPIView создает новый объект, даже если он уже существует.Django-Rest-Framework - PullRequest
0 голосов
/ 05 июня 2018

Я создаю API, который будет возвращать периоды выплат и отчеты о начислениях.У меня есть модель рабочих заказов, в которой хранится вся необходимая информация, и я создал приложение отчетов в рамках проекта, которое использует SerializerMethodField для возврата необходимых мне вычислений.Моя проблема заключается в том, что если я сделаю почтовый запрос с данными в полях для существующего объекта, он создаст новый объект.Я использую ListCreateAPIView, и из того, что я могу сказать, он должен извлечь объект, если он уже существует.Что мне не хватает?Спасибо за чтение!

models.py

class PayPeriodReport(models.Model):
    tech = models.ForeignKey(Employee, null=True, on_delete=models.CASCADE, 
related_name='employee')
    start_date = models.DateField()
    end_date = models.DateField()

urls.py

    urlpatterns = [
    path('payperiodreport/<employee>/<start_date>/<end_date>', views.PayPeriodReportView.as_view(), name='payperiod-report')
]

views.py

class PayPeriodReportView(generics.ListCreateAPIView):
    serializer_class = PayPeriodReportSerializer

serializers.py

class PayPeriodReportSerializer(serializers.ModelSerializer):

    break_down = serializers.SerializerMethodField()

    class Meta:
        model = PayPeriodReport
        fields = '__all__'


    # Get all work orders associated with report
    def get_all_workorders(self, obj):
        return WorkOrder.objects.filter(tech=obj.tech, start_date__range=(obj.start_date, obj.end_date))

    # Get days as a list of strings to be used as keys in dictinoary.
    def get_list_of_days(self, obj):
        days = obj.end_date - obj.start_date
        return [obj.start_date + timedelta(days=time) for time in range(days.days +1)]

    # returns a list of the week numbers to be used in weekly breakdown dictinoary.
    def get_payperiod_weeks(self, obj):
        days = obj.end_date - obj.start_date
        week_breakdown = {'weekly_total': timedelta(0), 'weekly_overtime': timedelta(0), 'weekly_regular': timedelta(0)}
        return list(dict.fromkeys([day.isocalendar()[1] for day in [obj.start_date + timedelta(days=time) for time in range(days.days +1)]]))

    # Returns dates of the week that the start date is in.  So that they can be checked for weekly overtime.
    def get_first_week_dates(self, obj):
        last_day_of_week = obj.start_date + timedelta(days=(6-obj.start_date.weekday()))
        first_day_of_week = last_day_of_week - timedelta(days=6)
        return[first_day_of_week + timedelta(days=time) for time in range(7)]



    # Return a dictionary with the following structure
    # break_down{daily_breakdown:
    #                    {date: {
    #                            days_workorders: [],
    #                            daily_total: total time for days workorders,
    #                            daily_regular: total non overtime time on workorders,
    #                             daily_overtime: total overtime on workorders,
    #                             },
    #            weekly_breakdown:{week:{total_overtime: , total_time: , total_regular:}}
    #            total_overtime: total overtime for entire report,
    #            total_regular: total regular time for report,
    #            total_time: total time for report,
    #                                     }
    #

    def get_break_down(self, obj):
        workorders = self.get_all_workorders(obj)
        days = self.get_list_of_days(obj)
        pay_period_weeks = self.get_payperiod_weeks(obj)
        total_hours = total_overtime = total_regular = timedelta(0)
        break_down = {'daily_breakdown': {}, 'weekly_breakdown': {}}
        weekly_breakdown = {}
        first_week = self.get_first_week_dates(obj)
        #To know when to stop calculating first weeks overtime.
        last_day_of_week = first_week[-1]
        #To access week
        first_week_key = first_week[0].isocalendar()[1]
        #Variable to store total of work orders for first week that are on selected pay period
        first_pay_period_week_total = timedelta(0)
        #Variable to store total of work orders for all of first week, including days not on selected pay period
        first_week_of_payperiod_total = timedelta(0)

        #Add week numbers as keys to dictinoaries
        for week in pay_period_weeks:
            weekly_breakdown[week] = {'weekly_total': timedelta(0), 'weekly_regular': timedelta(0), 'weekly_overtime': timedelta(0)}


        for day in days:
            #Checks that there were any work orders that day.
            if sum([workorder.id for workorder in workorders if day == workorder.start_date]):
                daily_breakdown = {}
                daily_breakdown['days_workorders'] = [workorder.WO_number for workorder in workorders if day == workorder.start_date]
                # Reset variables at start of loop
                daily_total = daily_overtime = daily_regular = timedelta(0)
                #Convert date to string so it can be used as a key
                date = day.strftime('%x')
                weekly_total = timedelta(0)
                for workorder in [workorder for workorder in workorders if day == workorder.start_date]:
                    daily_total += (workorder.end_time - workorder.start_time - workorder.non_billable_total)
                    if workorder.start_date.isocalendar()[1] != first_week_key:
                        weekly_breakdown[workorder.start_date.isocalendar()[1]]['weekly_total'] += (workorder.end_time - workorder.start_time - workorder.non_billable_total)
                # Add daily total to dictionary for that day
                daily_breakdown['daily_total'] = daily_total/3600
                #Add daily overtime and regular time to dictionary
                if daily_total > timedelta(hours=8):
                    daily_breakdown['daily_overtime'] = (daily_total - timedelta(hours=8))/3600
                    daily_breakdown['daily_regular'] = timedelta(hours=8)/3600
                else:
                    daily_breakdown['daily_overtime'] = timedelta(0)
                    daily_breakdown['daily_regular'] = daily_total/3600

                break_down['daily_breakdown'][date] = daily_breakdown
            else:
                pass

        #Checks first week for weekly overtime
        for day in first_week:
            for workorder in workorders:
                if day == workorder.start_date:
                    first_week_of_payperiod_total += (workorder.end_time - workorder.start_time - workorder.non_billable_total)
                    if day >= obj.start_date and day <= last_day_of_week:
                        first_pay_period_week_total += (workorder.end_time - workorder.start_time - workorder.non_billable_total)

        if first_week_of_payperiod_total > timedelta(hours=40):
            weekly_breakdown[first_week_key]['weekly_overtime'] = (first_week_of_payperiod_total - timedelta(hours=40))/3600
            weekly_breakdown[first_week_key]['weekly_regular'] = (first_pay_period_week_total/3600 - weekly_breakdown[first_week_key]['weekly_overtime'])
            weekly_breakdown[first_week_key]['weekly_total'] = first_week_of_payperiod_total /3600
        else:
            weekly_breakdown[first_week_key]['weekly_regular'] = first_pay_period_week_total/3600

        #Starts at index 1 to check the rest of the weeks.
        for week in range(1,(len(pay_period_weeks))):
            if weekly_breakdown[pay_period_weeks[week]]['weekly_total'] > timedelta(hours=40):
                weekly_breakdown[pay_period_weeks[week]]['weekly_overtime'] =  (weekly_breakdown[pay_period_weeks[week]]['weekly_total'] - timedelta(hours=40)) / 3600
                weekly_breakdown[pay_period_weeks[week]]['weekly_regular'] = weekly_breakdown[pay_period_weeks[week]]['weekly_total']/3600 - weekly_breakdown[pay_period_weeks[week]]['weekly_overtime']
                weekly_breakdown[pay_period_weeks[week]]['weekly_total'] = weekly_breakdown[pay_period_weeks[week]]['weekly_total']/3600
            else:
                weekly_breakdown[pay_period_weeks[week]]['weekly_regular'] = weekly_breakdown[pay_period_weeks[week]]['weekly_total']
                weekly_breakdown[pay_period_weeks[week]]['weekly_total'] = weekly_breakdown[pay_period_weeks[week]]['weekly_total']/3600

        break_down['weekly_breakdown'] = weekly_breakdown

        value_sums = lambda inner_key: reduce(lambda x, y: x + y, [break_down['daily_breakdown'][key][inner_key] for key in break_down['daily_breakdown'].keys()]) if [break_down['daily_breakdown'][key][inner_key] for key in break_down['daily_breakdown'].keys()] else timedelta(0)
        break_down['total_overtime'] = value_sums('daily_overtime')
        break_down['total_regular'] = value_sums('daily_regular')
        break_down['total_time'] = break_down['total_regular'] + break_down['total_overtime']

        return(break_down)

1 Ответ

0 голосов
/ 05 июня 2018

Если вы не хотите сохранять повторяющиеся данные, вам необходимо внести некоторые изменения в вашу модель.Например, в вашей модели установлено уникальное = True для технического поля

tech = models.ForeignKey(Employee, null=True,  on_delete=models.CASCADE, related_name='employee', unique=True)

, поэтому, когда вы хотите сохранить повторяющиеся данные в db, ListCreateAPIView может понять, что это повторяющиеся данные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...