Django - 如何使用reversion

时间:2017-06-23 19:32:53

标签: python django

我在项目学位工作,我需要做一个像文档管理系统这样的应用程序。我设法做到现在为止,但我还需要对文档进行版本控制(当有人想要编辑文档时,首先需要下载文档,然后更新它并上传为现有版本的新版本。)我阅读有关Django reversion的内容,但我不明白如何将其与我在admin之外的应用程序集成。我的代码可以在这里找到:https://github.com/rasmim/DMSLic

有人可以帮我这个吗?

models.py

 import reversion
from django.conf import settings
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.contrib.auth.models import (
    BaseUserManager, AbstractBaseUser
)
from django.core.mail import send_mail
from django.core.urlresolvers import reverse
from django.db import models
from django.db import models
from django.utils import timezone
from django.utils.http import urlquote
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext_lazy as _


class CustomUserManager(BaseUserManager):
    def _create_user(self, email, password, is_staff, is_superuser, **extra_fields):
        """
        Creates and saves a User with the given email and password.
        """
        now = timezone.now()
        if not email:
            raise ValueError('The given email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email,
                          is_staff=is_staff, is_active=True,
                          is_superuser=is_superuser, last_login=now,
                          date_joined=now, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, email, password=None, **extra_fields):
        return self._create_user(email, password, False, False,
                                 **extra_fields)

    def create_superuser(self, email, password, **extra_fields):
        return self._create_user(email, password, True, True,
                                 **extra_fields)


class CustomUser(AbstractBaseUser, PermissionsMixin):
    first_name = models.CharField(max_length=100, verbose_name=_("First name"))
    last_name = models.CharField(max_length=100, verbose_name=_("Last name"))
    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )
    date_of_birth = models.DateField(blank=True, null=True)
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
    is_staff = models.BooleanField(_('staff status'), default=False,
                                   help_text=_('Designates whether the user can log into this admin '
                                               'site.'))
    is_active = models.BooleanField(_('active'), default=True,
                                    help_text=_('Designates whether this user should be treated as '
                                                'active. Unselect this instead of deleting accounts.'))

    objects = CustomUserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    def get_full_name(self):
        # The user is identified by their email address
        return u"%s %s" % (self.first_name, self.last_name)

    def get_short_name(self):
        # The user is identified by their email address
        return self.email

    def __unicode__(self):  # __unicode__ on Python 2
        return u"%s" % self.first_name

    class Meta:
        verbose_name = _("user")
        verbose_name_plural = _("users")


        # def has_perm(self, perm, obj=None):
        #     "Does the user have a specific permission?"
        #     # Simplest possible answer: Yes, always
        #     return True
        #
        # def has_module_perms(self, app_label):
        #     "Does the user have permissions to view the app `app_label`?"
        #     # Simplest possible answer: Yes, always
        #     return True

        # @property
        # def is_staff(self):
        #     "Is the user a member of staff?"
        #     # Simplest possible answer: All admins are staff
        #     return self.is_admin

@reversion.register
class Document(models.Model):
    name = models.CharField(max_length=70)
    owner = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True, related_name="created_by")
    type = models.CharField(max_length=50)
    keywords = models.TextField()
    description = models.TextField(default='some description')
    user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True, related_name="working_user")
    creation_time = models.DateTimeField(auto_now_add=True)
    status = models.CharField(max_length=50)
    path = models.FileField(upload_to='media')
    folder = models.ForeignKey('Folder', on_delete=models.CASCADE, null=True)

    # version = models.ForeignKey('Version', on_delete=models.SET_NULL,null=True, related_name="version_id")

    def get_absolute_url(self):
        return reverse('DMS:detail', kwargs={'pk': self.pk})

        # def files(self):
        #     return u'<a href="%s%s" target="_blank">' % (settings.MEDIA_URL, self.files)

        # def __str__(self):
        #     return self.name+ '-' + self.type


class Version(models.Model):
    document = models.ForeignKey(Document, on_delete=models.SET_NULL, null=True)
    time = models.DateTimeField()
    user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True, related_name="active_user")


class Folder(models.Model):
    name = models.CharField(max_length=100)

    root = models.CharField(max_length=50)

    def get_name(self):
        return "{}".format(self.name)
        # child = models.CharField(max_lenght = 20)

        # def get_absolute_url(self):
        # return reverse('DMS:folder-details', kwargs={'pk': self.pk})

    def get_absolute_url(self):
        return reverse('DMS:folder-details', kwargs={'pk': self.pk})

views.py

import reversion
from django.contrib.auth import authenticate, login, logout
from django.db.models import Q
from django.http import HttpResponseRedirect, HttpResponse, request
from django.shortcuts import render, get_object_or_404
from rest_framework import viewsets
from rest_framework import permissions

from .forms import FolderForm, DocumentForm
from .models import Document, Folder
from .serializers import DocumentSerializer


def user_login(request):
    # If the request is a HTTP POST, try to pull out the relevant information.
    if request.method == 'POST':
        # Gather the username and password provided by the user.
        # This information is obtained from the login form.
        # We use request.POST.get('<variable>') as opposed to request.POST['<variable>'],
        # because the request.POST.get('<variable>') returns None, if the value does not exist,
        # while the request.POST['<variable>'] will raise key error exception
        email = request.POST.get('email')
        password = request.POST.get('password')

        # Use Django's machinery to attempt to see if the username/password
        # combination is valid - a CustomUser object is returned if it is.
        user = authenticate(email=email, password=password)

        # If we have a CustomUser object, the details are correct.
        # If None (Python's way of representing the absence of a value), no user
        # with matching credentials was found.
        if user:
            # Is the account active? It could have been disabled.
            if user.is_active:
                # If the account is valid and active, we can log the user in.
                # We'll send the user back to the homepage.
                login(request, user)
                return HttpResponseRedirect('/DMS/first/')
            else:
                # An inactive account was used - no logging in!
                return HttpResponse("Your DMS account is disabled.")
        else:
            # Bad login details were provided. So we can't log the user in.
            print("Invalid login details: {0}, {1}".format(email, password))
            return HttpResponse("Invalid login details supplied.")

    # The request is not a HTTP POST, so display the login form.
    # This scenario would most likely be a HTTP GET.
    else:
        # No context variables to pass to the template system, hence the
        # blank dictionary object...
        return render(request, 'DMS/login.html', {})


def user_logout(request):
    # Since we know the user is logged in, we can now just log them out.
    logout(request)

    # Take the user back to the homepage.
    return HttpResponseRedirect('/DMS/login/')


def index(request):
    folder_name = Folder.objects.all()

    context = {

        'folder_name': folder_name,
    }

    return render(request, 'DMS/index.html', context)


#
# def remove(request, post_id):
#     try:
#         folder_id = Folder.objects.get(pk=question_id)
#         folder_id.remove()
#     except Folder.DoesNotExist:
#         raise Http404("Error 404")
#     return render(request, 'index.html', {'message': 'Folder was removed'})



def FolderDetail(request, pk):
    folder = get_object_or_404(Folder, pk=pk)
    folder_name = Folder.objects.all()
    # document_list = Document.objects.all()
    # query = request.GET.get("q")
    # if query:
    #     document_list = document_list.filter(Q(keywords__icontains=query)).distinct()
    #     return render(request, 'DMS/folder-details.html', {'document_list': document_list})

    context = {
        'folder': folder,
        'folder_name': folder_name,
        # 'document_list': document_list
    }

    return render(request, "DMS/folder-details.html", context)


# class FolderDetailsView(generic.DetailView):
#     model = Folder
#     template_name = 'DMS/folder-details.html'


def DocumentView(request):
    document_list = Document.objects.all()
    query = request.GET.get("q")
    if query:
        document_list = document_list.filter(Q(keywords__icontains=query)).distinct()
        return render(request, 'DMS/documents.html', {'document_list': document_list})

    return render(request, 'DMS/documents.html', {'document_list': document_list})


def create_document(request, folder_id):
    # form = forms.DocumentForm()
    form = DocumentForm(request.POST or None, request.FILES or None)
    folder = get_object_or_404(Folder, pk=folder_id)
    # foldern = get_object_or_404(Folder,)
    folder_name = Folder.objects.all()
    if form.is_valid():
        folder_document = folder.document_set.all()
        for d in folder_document:
            if d.name == form.cleaned_data.get("name"):
                context = {
                    'folder': folder,
                    'form': form,
                    'folder_name': folder_name,
                    'error_message': 'You already added that document',
                }
                # return HttpResponseRedirect('/DMS/folder-details')
                return render(request, 'DMS/folder-details.html', context)
        document = form.save(commit=False)
        document.folder = folder
        document.save()
        return HttpResponseRedirect('/DMS/' + folder.id)
    context = {
        'folder': folder,
        'form': form,
        'folder_name': folder_name
    }
    return render(request, 'DMS/create_document.html', context)


def create_folder(request):
    form = FolderForm(request.POST or None, request.FILES or None)
    folder_name = Folder.objects.all()
    if form.is_valid():
        folder = form.save(commit=False)
        folder.save()

        return HttpResponseRedirect('/DMS/first')
    context = {
        "form": form,
        "folder_name": folder_name
    }

    return render(request, 'DMS/create_folder.html', context)


def delete_document(request, folder_id, document_id):
    folder = get_object_or_404(Folder, pk=folder_id)
    folder_name = Folder.objects.all()
    document = Document.objects.get(pk=document_id)
    document.delete()
    context = {
        "folder": folder,
        "folder_name": folder_name
    }
    return render(request, 'DMS/folder-details.html', context)


def delete_folder(request, pk):
    folder = Folder.objects.get(pk=pk)
    folder_name = Folder.objects.all()
    for f in folder_name:
        if f.id == folder.id:
            if f.root == 'root':
                for child in folder_name:
                    if child.root == folder.name:
                        child.delete()
                        folder.delete()
                        # folder.delete(name= folder)
                        #     if f.root == folder.name:
                        #         folder.delete(root = folder)
                    else:
                        folder.delete()

            else:
                folder.delete()

                # for child in folder_name:
                #     if child.root == f.name:
                #         child.delete()
                #         # folder.delete()

    return render(request, 'DMS/folder-details.html', {'folder': folder, 'folder_name': folder_name})

class DocumentViewSet(viewsets.ModelViewSet):
    queryset = Document.objects.all()
    serializer_class = DocumentSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly)

with reversion.create_revision():
    obj = Document()
    obj.name = "obj v1"
    obj.save()

    reversion.set_user(request.user)
    reversion.set_comment("Created revision 1")

urls.py

from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns

from . import views
from django.conf.urls import include

app_name = 'DMS'



urlpatterns = [
    url(r'^first/$', views.index, name='index'),
    # url(r'^document/add/$', views.DocumentCreate.as_view(), name='document-add'),
    # url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
    url(r'^(?P<pk>[0-9]+)/$', views.FolderDetail, name='folder-details'),
    # url(r'^folder/add/$', views.FolderCreate.as_view(), name='folder-add'),
    url(r'^(?P<folder_id>[0-9]+)/create_document/$', views.create_document, name='create_document'),
    url(r'^create_folder/$', views.create_folder, name='create-folder'),
    url(r'^login/$', views.user_login, name='user_login'),
    url(r'^logout/$', views.user_logout, name='user_logout'),
    url(r'^doc/$', views.DocumentView, name='document'),
    url(r'^(?P<folder_id>[0-9]+)/delete_document/(?P<document_id>[0-9]+)/$', views.delete_document,
        name='delete_document'),
    url(r'^(?P<pk>[0-9]+)/delete_folder/$', views.delete_folder, name='delete_folder'),


]

urlpatterns = format_suffix_patterns(urlpatterns)

forms.py

from django import forms

from .models import Folder, Document, CustomUser


class DocumentForm(forms.ModelForm):
    EXTENSIONS = (('jpg', 'jpg'),
                  ('pdf', 'pdf'),
                  ('png', 'png'),
                  ('docx', 'docx'),
                  ('pptx', 'pptx'),
                  ('xls', 'xls'),
                  )

    type = forms.ChoiceField(choices=EXTENSIONS)
    class Meta:
        model = Document
        fields = ['name', 'owner', 'type', 'keywords', 'description', 'path']


class FolderForm(forms.ModelForm):
    CHOICES = [[x.name, x.name] for x in Folder.objects.all()]

    CHOICES.insert(0, ['root', "Root Folder"])
    root = forms.ChoiceField(choices=CHOICES)

    class Meta:
        model = Folder
        fields = ['name', 'root']


class UserForm(forms.ModelForm):
    class Meta:
        model = CustomUser
        fields = ['email', 'password']

1 个答案:

答案 0 :(得分:2)

在管理员之外,django-reversion为您提供了两个选项:

  1. Wrapping middleware for any POST/PUT/PATCH request

    MIDDLEWARE += ('reversion.middleware.RevisionMiddleware')
    
  2. A view decorator/mixin

    from reversion.views import RevisionMixin
    
    class DocumentViewSet(RevisionMixin, viewsets.ModelViewSet):
         queryset = Document.objects.all()
         serializer_class = DocumentSerializer
         permission_classes = (permissions.IsAuthenticatedOrReadOnly)
    
  3. 这两个选项都要求您通过装饰的ModelAdmin类或manually注册模型:

    @reversion.register
    class Document(models.Model):
        # ... rest of definition
        pass