Django之一个微型CRM系统开发小记
一. 简介
本篇博客记录在开发过程中遇到的小问题或者是心得。以此提醒自己以后多注意。
二. 关于modelform
1.通过add_error给全局钩子添加错误:
就可以不用这样获取全局错误信息了:
all_error = form.errors.get('__all__') if all_error: all_error = all_error[0]
add_error对form也是可以这么设置的。
class ResetPasswordForm(StarkForm): password = forms.CharField(label='密码', widget=forms.PasswordInput) confirm_password = forms.CharField(label='确认密码', widget=forms.PasswordInput) def clean(self): password = self.cleaned_data.get('password') confirm_password = self.cleaned_data.get('confirm_password') if password != confirm_password: self.add_error('confirm_password', '两次密码输入不一致,请重新输入') raise ValidationError('两次密码输入不一致!') self.cleaned_data['password'] = get_md5(password) return self.cleaned_data
2. 数据库DateFiled字段会被识别成textinput字段
只能手动创建一个DateInput的插件,继承DateInput:
class DateInput(forms.DateInput): input_type = 'date' class ClassListModelForm(StarkModelForm): class Meta: model = models.ClassList fields = '__all__' widgets = { 'start_date': DateTimePickerInput, 'graduate_date': DateInput }
这里也可以应用DateTimePickerInput第三方插件来输入时间。
类似这样:
具体使用方法请参照这篇博客:
3. modelformset_factory的使用
结合model,把多个form捆绑在一起进行操作。
使用举例:
# 定义一个modelform
class StudyRecordModelForm(StarkModelForm): class Meta: model = models.StudyRecord fields = ['record', ] # 相关视图函数,这里是一个类下的视图函数 def attendance_view(self, request, course_record_id, *args, **kwargs): """ 考勤的批量操作 :param request: :param course_record_id: :param args: :param kwargs: :return:
首先创建modelformset_factory对象,接收数据库model和自己写的modelform。
GET或者POST请求来的时候,接受的值有点像form中的instance和data。这里就是queryset和data
"""
study_record_object_list = models.StudyRecord.objects.filter(course_record_id=course_record_id) study_model_formset = modelformset_factory(models.StudyRecord, form=StudyRecordModelForm, extra=0) if request.method == 'POST': formset = study_model_formset(queryset=study_record_object_list, data=request.POST) if formset.is_valid(): formset.save() return render(request, 'attendance.html', {'formset': formset}) formset = study_model_formset(queryset=study_record_object_list) return render(request, 'attendance.html', {'formset': formset})
效果:
三. 关于models
1.ForeignKey定义显示字段:
consultant = models.ForeignKey(verbose_name="课程顾问", to='UserInfo', related_name='consultant', null=True, blank=True, limit_choices_to={'depart__title': '销售部'},on_delete=models.CASCADE)
2. 事务transaction使用
def action_multi_apply(self, request, *args, **kwargs): current_user_id = request.session['user_info']['id'] # 先暂时这么写,用户登录后的id..... pk_list = request.POST.getlist('pk') private_customer_count = models.Customer.objects.filter(consultant_id=current_user_id,status=2).count() if private_customer_count + len(pk_list) >= models.Customer.MAX_PRIVATE_CUSTOMER_COUNT: return HttpResponse( f'私户数量超过最大限制150!你还能申请{models.Customer.MAX_PRIVATE_CUSTOMER_COUNT - private_customer_count}') flag = False with transaction.atomic(): origin_queryset = models.Customer.objects.filter(id__in=pk_list, status=2, consultant__isnull=True).select_for_update() if len(origin_queryset) == len(pk_list): models.Customer.objects.filter(id__in=pk_list, status=2, consultant__isnull=True).update( consultant_id=current_user_id) flag = True if not flag: return HttpResponse('手速太慢了,被别人抢走了!')
四. 面向对象
1. type( self)的使用
其实本质就是通过类去调用这个方法,可以写成类名. display_edit_del,但是,如果有继承它的类重写了这个方法之后,如果你还想用你重写的方法(通过类去执行的话), 就必须通过type(self) 去调用了。
def get_list_display(self, *args, **kwargs): value = [] if self.list_display: value.extend(self.list_display) value.append(type(self).display_edit_del) return value