You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Django的自由职业者平台计时功能实现技术问询

实现自由职业者计时功能的Django方案

针对你的需求,我会一步步拆解实现思路,从模型设计到视图、前端的完整流程:

1. 新增计时记录模型(TimeEntry)

首先需要创建一个专门的模型来存储每次计时的起止时间戳,直接关联到Freelancer模型。把这个模型放在你的models.py里(和现有User、Freelancer等模型同文件即可):

from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils import timezone

# 你的现有User、Freelancer、Hirer模型...

class TimeEntry(models.Model):
    freelancer = models.ForeignKey(Freelancer, on_delete=models.CASCADE, related_name="time_entries")
    start_time = models.DateTimeField(default=timezone.now)
    end_time = models.DateTimeField(null=True, blank=True)
    # 可选:如果后续需要关联具体项目,可以加外键到Project模型
    # project = models.ForeignKey(Project, on_delete=models.SET_NULL, null=True, blank=True)

    @property
    def duration(self):
        """计算单次计时的时长(返回小时数)"""
        if self.end_time:
            delta = self.end_time - self.start_time
            return delta.total_seconds() / 3600
        return 0

    def __str__(self):
        return f"{self.freelancer.user.username} - {self.start_time.strftime('%Y-%m-%d %H:%M')}"

这个模型的核心是start_time(开始计时自动记录当前时间)和end_time(停止计时才填充),duration属性用来快速计算单次工作时长,方便后续报表统计。

2. 编写计时操作的视图

接下来需要两个视图函数,分别处理「开始计时」和「停止计时」的请求,同时限制只有登录的自由职业者才能访问:

# views.py
from django.shortcuts import get_object_or_404, redirect
from django.views.generic import View
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import Freelancer, TimeEntry
from django.utils import timezone

class StartTimerView(LoginRequiredMixin, View):
    def post(self, request):
        # 获取当前登录用户对应的Freelancer实例
        freelancer = get_object_or_404(Freelancer, user=request.user)
        # 先检查是否已有未结束的计时,避免重复创建
        active_entry = freelancer.time_entries.filter(end_time__isnull=True).exists()
        if not active_entry:
            TimeEntry.objects.create(freelancer=freelancer)
        return redirect('freelancer_dashboard')  # 替换成你的仪表盘URL名称

class StopTimerView(LoginRequiredMixin, View):
    def post(self, request):
        freelancer = get_object_or_404(Freelancer, user=request.user)
        # 找到该自由职业者最近的一条未结束的计时记录
        active_entry = freelancer.time_entries.filter(end_time__isnull=True).last()
        if active_entry:
            active_entry.end_time = timezone.now()
            active_entry.save()
        return redirect('freelancer_dashboard')

记得在urls.py里配置这两个视图的路由:

# urls.py
from django.urls import path
from .views import StartTimerView, StopTimerView

urlpatterns = [
    # 你的其他路由...
    path('timer/start/', StartTimerView.as_view(), name='start_timer'),
    path('timer/stop/', StopTimerView.as_view(), name='stop_timer'),
]

3. 前端添加「开始/停止」按钮

在自由职业者的仪表盘模板里,添加两个按钮,用AJAX发送POST请求(避免页面刷新,提升体验):

<!-- freelancer_dashboard.html -->
{% if user.is_freelancer %}
    {% with active_entry=user.freelancer.time_entries.filter(end_time__isnull=True).last %}
        {% if active_entry %}
            <button id="stop-timer-btn" class="btn btn-danger">停止计时</button>
        {% else %}
            <button id="start-timer-btn" class="btn btn-success">开始计时</button>
        {% endif %}
    {% endwith %}

    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
        $(document).ready(function() {
            // 开始计时
            $('#start-timer-btn').click(function() {
                $.post("{% url 'start_timer' %}", function() {
                    location.reload();
                });
            });

            // 停止计时
            $('#stop-timer-btn').click(function() {
                $.post("{% url 'stop_timer' %}", function() {
                    location.reload();
                });
            });
        });
    </script>
{% endif %}

4. 周工作报表计算

要生成周报表,可以通过聚合查询统计每周的总时长和报酬:

# 在视图或模型方法中实现
from django.db.models import Sum
from django.utils import timezone
from datetime import timedelta

def get_weekly_report(freelancer):
    # 按周一到周日计算本周范围(可根据需求调整为周日到周六)
    today = timezone.now().date()
    start_of_week = today - timedelta(days=today.weekday())
    end_of_week = start_of_week + timedelta(days=6)

    # 过滤本周已完成的计时记录
    weekly_entries = freelancer.time_entries.filter(
        start_time__date__gte=start_of_week,
        start_time__date__lte=end_of_week,
        end_time__isnull=False
    )

    total_hours = round(sum(entry.duration for entry in weekly_entries), 2)
    total_earnings = round(total_hours * freelancer.hourly_rate, 2)

    return {
        'start_date': start_of_week,
        'end_date': end_of_week,
        'total_hours': total_hours,
        'total_earnings': total_earnings,
        'entries': weekly_entries
    }

在视图里调用这个函数,把数据传递给模板即可渲染出周报表。

注意事项

  • 权限加固:可以在视图里额外检查request.user.is_freelancer,避免非自由职业者访问计时功能。
  • 时区配置:确保settings.py里的TIME_ZONE设置正确(比如'Asia/Shanghai'),避免时间戳出现偏差。
  • 异常处理:可以在视图里添加try-except块,处理计时操作中的意外情况(比如数据库写入失败)。

内容的提问来源于stack exchange,提问作者Urvin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:34:28