In the Django framework admin management page, record the data modification and change of each field, and perform specific actions when specific field changes

Application background:

Recently, I am working on a small application using the Django framework. One of the requirements is to record the modification and change of each field in the data.

Why do you want to do this? The main application scenario is that there is an "audit" process regardless of the form, and the audit result can be passed or failed; even for the passed data, in the subsequent audit process, there is still the authority to change the audit result, so it must be recorded. The modified content of each field is convenient for traceability.

specific methods:

In response to this demand, I also checked a lot of information on the Internet, but it seems that there is no relatively perfect system, so I looked at the official Django documentation and tried it with the solutions of many netizens. The main steps:

  1. Make a good record when you initially choose to rewrite  the save_model function to save it;
  2. Create a new model to record the results of data changes; (using MySql database)
  3. Get form data in save_model;
  4. When the form is saved, the data is written to the form.

Relevant code:

Although logs can be used as data records, logs are generally in text format, and the structure is not strong, which is not convenient for later query processing. So I still choose to use the database for recording; at the same time, the log is also used; (As for the speed... I have used python, and I also consider the access speed...)

Data record sheet:

# models.py
# 简单日志记录,用于主要记录节点信息
class RzLog(models.Model):
    guid = models.UUIDField(auto_created=True, default=uuid.uuid4, editable=False)
    sheet = models.CharField('表单名称', max_length=100, default='')
    user = models.CharField('操作人员', max_length=100, default='')
    the_id = models.CharField('数据ID', max_length=255, default='')
    the_key = models.CharField('字段名称', max_length=255, default='')
    old_values = models.CharField('原数据', max_length=255, default='')
    new_values = models.CharField('新数据', max_length=255, default='')
    log_date = models.DateTimeField('修改时间', default=choice_list.date_time, null=True)  
    note = models.TextField('备注信息', null=True, default='', blank=True)
    create_user = models.ForeignKey(User,  related_name='create_user_rz', on_delete=models.CASCADE, db_constraint=False, verbose_name='创建人员', default=1000)
    update_user = models.ForeignKey(User, related_name='update_user_rz', on_delete=models.CASCADE, db_constraint=False, verbose_name='修改人员', default=1000)
    create_date = models.DateTimeField('创建时间', auto_now_add=True)
    update_date = models.DateTimeField('更新时间', auto_now=True)

Rewrite the save_model code in admin , where the data of the changed field is obtained through form.has_changed() . The following is the relevant code. A lot of log records are used in the code. This is applied during the initial debugging and step-by-step trial. It can be removed in the later formal application. In order to allow everyone to apply more clearly, all the records are kept here. and instructions.

# admin.py
def save_model(self, request, obj, form, change):
    obj.update_user = request.user
    obj.receiver = request.user.username

    # 用于记录数据变化信息
    if form.has_changed():
        change_list = form.changed_data  
        logger.info(f'表格数据变化点:{change_list}')
        try:
            changed_dict = form.cleaned_data
            
            for i in change_list:
                x = YiJieShou.objects.values_list(i, flat=True).filter(id=obj.id)  # 原数据库保存的数据
                y = changed_dict[i] # 当前新写入的数据
                # ----------------------------------
                # 如果有特殊字段需要另外的动作进行处理的,使用下面的部分代码

                # 当变更审批状态的时候
                if i == 'is_jieshou':  # 此处为特别关注的字段,针对此字段的变动如果需要有其他的操作,可以在此处进行设置相关动作
                    obj.jieshou_date = datetime.datetime.now()
                    if not y:
                        pass # 设定特殊动作
                    else:
                        pass
                elif i == 'is_doubt':
                    if y == 1:
                        pass # 设定特殊动作
                    else:
                        pass # 设定特殊动作
                else:
                     pass # 设定特殊动作
                # ---------------------------------------------------------
                # 如果不需要特殊字段的处理,跳过 -- 之间的不分代码即可

    # 将相关数据的变化,写入数据库进行存储
 RzLog.objects.create(sheet='PassJieShou',user=request.user.username,the_id=str(obj),the_key=i,old_values=str(x[0]),new_values=str(y),log_date=datetime.datetime.now(),create_user=request.user)

        except  BaseException as e:        
            logger.error(f'错误类型是:{e.__class__.__name__}\n错误原因: {e}')
            logger.error(f'详细错误信息a:{traceback.format_exc()}')
    super().save_model(request, obj, form, change)

The x and y in the above code respectively represent the data saved in the original form of x, and the newly written {modified) data of y this time;

If you only need to simply record data changes, you can directly jump to the RzLog.objects.create() part from x\y. The middle part is for setting special actions for some special fields.

Guess you like

Origin blog.csdn.net/theorycao/article/details/128296614