Django 我需要建议将应用程序集成到我的项目中

Django 我需要建议将应用程序集成到我的项目中,django,Django,我创建了一个应用程序来审核对象上的操作。创建、更新或删除对象时,将在“我的审核表”(Auditor模型)中创建一条新记录 Audit应用程序现在正在运行,但要在我的模型上使用它,需要一些工作和大量代码,我相信用最优化的方法可以避免这些工作和代码 我可以使用哪种django资源或方法在我的模型上集成Audit应用程序,而不用编写这么多代码?我需要一种简化的方式来归档Auditor应用程序与我的所有模型和其他项目的集成 我将给出一个示例,说明如何将Auditor模型与要审核的模型(Car)结合使用

我创建了一个应用程序来审核对象上的操作。创建、更新或删除对象时,将在“我的审核表”(Auditor模型)中创建一条新记录

Audit应用程序现在正在运行,但要在我的模型上使用它,需要一些工作和大量代码,我相信用最优化的方法可以避免这些工作和代码

我可以使用哪种django资源或方法在我的模型上集成Audit应用程序,而不用编写这么多代码?我需要一种简化的方式来归档Auditor应用程序与我的所有模型和其他项目的集成

我将给出一个示例,说明如何将Auditor模型与要审核的模型(Car)结合使用

多谢各位

车型

class Car(models.Model):
    name = models.CharField(max_length=50)
    brand = models.CharField(max_length=50)
    color = models.CharField(max_length=50)
    is_available = models.BooleanField(default=True)
class Auditor(models.Model):
    field = models.CharField(max_length=255, blank=True)
    action = models.CharField(max_length=6)
    old_value = models.TextField(blank=True)
    new_value = models.TextField(blank=True)
    stamp = models.DateTimeField(auto_now_add=True)
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    content_type = models.ForeignKey(ContentType, blank=True)
    object_id = models.PositiveIntegerField(blank=True)
    content_object = GenericForeignKey('content_type', 'object_id')
    deleted_object = models.CharField(max_length=255, blank=True)
审计师模式

class Car(models.Model):
    name = models.CharField(max_length=50)
    brand = models.CharField(max_length=50)
    color = models.CharField(max_length=50)
    is_available = models.BooleanField(default=True)
class Auditor(models.Model):
    field = models.CharField(max_length=255, blank=True)
    action = models.CharField(max_length=6)
    old_value = models.TextField(blank=True)
    new_value = models.TextField(blank=True)
    stamp = models.DateTimeField(auto_now_add=True)
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    content_type = models.ForeignKey(ContentType, blank=True)
    object_id = models.PositiveIntegerField(blank=True)
    content_object = GenericForeignKey('content_type', 'object_id')
    deleted_object = models.CharField(max_length=255, blank=True)
汽车视图

from audittest.apps.auditor.models import Auditor
from django.contrib.contenttypes.models import ContentType

#Function for audit creation. I know that the view is not the right place to put this function, but I put this here for test.
    def create_audit(obj, request, action, obj_id=False):
        if action == 'CREATE':
            audit = Auditor(content_type = ContentType.objects.get_for_model(obj), object_id = obj.id, user = request.user, action = action)
        elif action == 'DELETE':
            audit = Auditor(content_type = ContentType.objects.get_for_model(obj), object_id = obj_id, user = request.user, action = action, deleted_object = obj)
        audit.save()

def new(request, template_name='cars/form.html'):
    form = CarForm(request.POST or None)
    if form.is_valid():
        obj = form.save()
        create_audit(obj, request, 'CREATE')
        return redirect('car:admin')
    return render(request, template_name, {'form':form, 'title':u'Novo Car'})


def edit(request, pk, template_name='cars/form.html'):
    car = get_object_or_404(Car, pk=pk)
    form = CarForm(request.POST or None, instance=car, request=request)
    if form.is_valid():
        form.save()
        return redirect('car:admin')
    return render(request, template_name, {'form':form,'title':u'Editar Car'})


def delete(request, pk, template_name='cars/confirm_delete.html'):
    car = get_object_or_404(Car, pk=pk)
    obj_id = car.id
    if request.method=='POST':
        car.delete()
        create_audit(car, request, 'DELETE', obj_id=obj_id)
        messages.success(request, u'Car excluído com sucesso.')
        return redirect('car:admin')
    return render(request, template_name, {'object':car})
汽车形态

class CarForm(ModelForm):

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)
        super(CarForm, self).__init__(*args, **kwargs)  

    def clean(self):
        cleaned_data = super(CarForm, self).clean()

        # Audit updated fields
        if self.instance.pk is not None:
            fields = []
            for field in self.instance._meta.get_all_field_names():
                if field != 'id' and getattr(self.instance, field) != cleaned_data[field]:
                    #fields.append((field, getattr(self.instance, field), cleaned_data[field]))
                    audit = Auditor(content_type = ContentType.objects.get_for_model(self.instance), object_id = self.instance.pk, user = self.request.user, action = 'UPDATE', field = self.instance._meta.get_field(field).verbose_name, old_value = getattr(self.instance, field), new_value = cleaned_data[field])
                    audit.save()

        return cleaned_data

在应用程序中使用基于类的视图,这样您就可以充分利用cool
mixin的优势,
我通常创建一个
Mixin
,可以添加到任何CreateView或UpdateView

class withAudit(object):

    """
    A mixin that will create an audit record wither the action is 
    Create or Update
    """
    def get_success_url(self):
        """
        This will be called when the form is valid and saved. 
        """

        # create the record
        audit = Auditor(content_type= ContentType.objects.get_for_model(self.model))
        audit.object_id = self.object.pk
        audit.user = request.user

        # You will need a way to capture this action. 
        # there are many ways to do it. 
        audit.action = "Create"
        audit.save()

        return super(withAudit, self).get_success_url()
在你看来,你必须这样使用它

class CarCreate(withAudit, CreateView):
    model = Car
更新

class CarUpdate(withAudit, UpdateView):
    model = Car
您可以对应用程序中的任何UpdateView或CreateView执行以下操作。但是,对于删除对象,我认为您需要另一个mixin,它将在执行操作之前捕获数据。您需要查看基于类的视图文档,以便根据需要自定义这些文档

如果你真的想继续使用基于方法的视图,同样的想法也可以在装饰器上实现。



如果您有一个具有高流量的大型应用程序,那么这个过程应该在后台完成,您可以在后台定义一个堆栈或队列,然后不断地将这些信息传递给它,这将提供更好的性能。一些大型应用程序使用另一个数据库进行日志和审计

谢谢@Othman。在Mixin中,如何确定对象是否为新对象,以便设置适当的操作?我是一个真正的mixin初学者。@bleroy检查这个@bleroy检查
表单。应该在视图调用方法
get\u success\u url
之前完成实例
。阅读基于类的视图文档,了解应该使用哪种方法。谢谢@Othman。现在,我可以使用form\u valid方法确定操作,并通过pass获得\u success\u url。但是,我在获取原始对象数据以与get_success_url方法中的self.object进行比较以确定哪些字段被更新时遇到了问题。如何从mixin中的更新表单中获取初始数据?@bleroy您可以在同一个
mixin
中使用多种方法,例如
form\u valid
您可以在其中执行
deepcopy
并将其作为类中的变量存储在旧对象中,将来在
get\u success\u url
中使用它。