Django 管理器、ModelForms 和一些混乱
Django Managers, ModelForms and some confusion
我正计划使用 Django 编写一个基本的 clock-in/clock-out 应用程序来跟踪工作时间。现在我的代码可以工作(start/stop 轮班或暂停),但我不使用任何 ModelForms 或 ModelManagers。所有业务代码都在我的视图和一个 services.py 文件中,这似乎不是正确的方法。
我试图阅读 ModelManagers 和 ModelForms,但我认为这让我很困惑。
假设我有一个模型 WorkTime:
class WorkTime(models.Model):
employee = models.ForeignKey(User)
created_at = models.DateTimeField(auto_now_add=True)
shift_started = models.DateTimeField()
shift_finished = models.DateTimeField(blank=True, null=True)
shift_duration = models.DurationField(blank=True, null=True)
work_reason = models.TextField(null=True)
我现在想有两种可能:
- 用户可以通过访问特定视图 (/clock/start/) 开始轮班。仅添加开始时间。
- 用户访问停止视图(/clock/stop/)以结束他当前的班次,结束时间添加到相应的行中。
- 用户在结束后手动添加班次,因此添加了开始和结束时间。
就像我现在的代码一样,它不是真正的美,绝对不是 DRY。我怎样才能以最聪明的方式解决问题,比如定义一个适合所有可能情况的 ModelForm(只需开始一个新班次,结束 运行 班次(仅通过访问浏览器中的视图)或手动添加整个班次使用 HTML 形式)。或者我会把它分成一个 ModelManager 来执行 shift starting/stopping 部分和一个 ModelForm 用于手动添加狗屎作为实际的 HTML-form?
仅通过普通 GET 请求输入一些 URL 来更改班次开始和停止时间不是一个好主意。浏览器可以缓存该请求或触发多个请求(刷新页面时不会弹出它可以执行两次操作,例如 POST 请求)。所以你最好把它改成 POST requests.
对于所有这些视图,您当然可以使用一个 ModelForm
:
class SiftForm(forms.ModelForm):
class Meta:
model = WorkTime
fields = ('created_at', 'shift_started', 'shift_finished') # you shouldn't pass user and duration time here
class ShiftStartView(CreateView):
model = WorkTime
form_class = ShiftForm
success_url = "some_url" # after creating WorkTime, view will redirect to that url. You can (and really should) pass reverse_lazy() here, instead of URL as string, if you don't want to hardcode URL.
def dispatch(self, request, *args, **kwargs):
# if you want to prevent creating 2 started but not stopped WorkTimes for one user, you should put logic preventing it here.
return super(ShiftStartView, self).dispatch(self, request, *args, **kwargs)
def form_valid(self, form):
worktime = form.save(commit=False)
worktime.employee = self.request.user
worktime.save()
return super(ShiftStartView, self).form_valid(form)
这样您还可以创建用于手动创建 WorkTime
的表单。要创建停止视图,您应该使用 UpdateView
并在 get_object
方法中为用户获取当前 WorkTime
。
我正计划使用 Django 编写一个基本的 clock-in/clock-out 应用程序来跟踪工作时间。现在我的代码可以工作(start/stop 轮班或暂停),但我不使用任何 ModelForms 或 ModelManagers。所有业务代码都在我的视图和一个 services.py 文件中,这似乎不是正确的方法。
我试图阅读 ModelManagers 和 ModelForms,但我认为这让我很困惑。
假设我有一个模型 WorkTime:
class WorkTime(models.Model):
employee = models.ForeignKey(User)
created_at = models.DateTimeField(auto_now_add=True)
shift_started = models.DateTimeField()
shift_finished = models.DateTimeField(blank=True, null=True)
shift_duration = models.DurationField(blank=True, null=True)
work_reason = models.TextField(null=True)
我现在想有两种可能:
- 用户可以通过访问特定视图 (/clock/start/) 开始轮班。仅添加开始时间。
- 用户访问停止视图(/clock/stop/)以结束他当前的班次,结束时间添加到相应的行中。
- 用户在结束后手动添加班次,因此添加了开始和结束时间。
就像我现在的代码一样,它不是真正的美,绝对不是 DRY。我怎样才能以最聪明的方式解决问题,比如定义一个适合所有可能情况的 ModelForm(只需开始一个新班次,结束 运行 班次(仅通过访问浏览器中的视图)或手动添加整个班次使用 HTML 形式)。或者我会把它分成一个 ModelManager 来执行 shift starting/stopping 部分和一个 ModelForm 用于手动添加狗屎作为实际的 HTML-form?
仅通过普通 GET 请求输入一些 URL 来更改班次开始和停止时间不是一个好主意。浏览器可以缓存该请求或触发多个请求(刷新页面时不会弹出它可以执行两次操作,例如 POST 请求)。所以你最好把它改成 POST requests.
对于所有这些视图,您当然可以使用一个 ModelForm
:
class SiftForm(forms.ModelForm):
class Meta:
model = WorkTime
fields = ('created_at', 'shift_started', 'shift_finished') # you shouldn't pass user and duration time here
class ShiftStartView(CreateView):
model = WorkTime
form_class = ShiftForm
success_url = "some_url" # after creating WorkTime, view will redirect to that url. You can (and really should) pass reverse_lazy() here, instead of URL as string, if you don't want to hardcode URL.
def dispatch(self, request, *args, **kwargs):
# if you want to prevent creating 2 started but not stopped WorkTimes for one user, you should put logic preventing it here.
return super(ShiftStartView, self).dispatch(self, request, *args, **kwargs)
def form_valid(self, form):
worktime = form.save(commit=False)
worktime.employee = self.request.user
worktime.save()
return super(ShiftStartView, self).form_valid(form)
这样您还可以创建用于手动创建 WorkTime
的表单。要创建停止视图,您应该使用 UpdateView
并在 get_object
方法中为用户获取当前 WorkTime
。