Удалить файлы из сообщения - PullRequest
0 голосов
/ 02 августа 2020

Я создал приложение Django Content, в котором пользователь может создавать сообщения. Он также должен иметь возможность загружать несколько файлов в каждое сообщение. Пока это работает нормально.

Где я борюсь: как я могу реализовать, что пользователь, учитывая разрешения, может удалять загруженные файлы в определенном c сообщении? Я попытался написать собственный DeleteView для модели «многие к одному», но это почему-то не работает.

Я был бы признателен за каждый ввод. Ниже приведены мои модели, представления, формы и шаблоны URL:

Модель:

class SoftDeletionModel(models.Model):
deleted_date = models.DateTimeField(blank=True, null=True, default=None)

objects = SoftDeletionManager()
all_objects = SoftDeletionManager(alive_only=False)

class Meta:
    abstract = True

def delete(self):
    self.deleted_date = timezone.now()
    self.save()

def hard_delete(self):
    super(SoftDeletionModel, self).delete()


class Categories(models.Model):
    """
    Categories are used to specify the highes level structure. For example like 'wiki' or 'news'
    which we will use in our CMS. Categories need to be unique.
    """
prepopulated_fields = {"slug": ("name",)}

id = models.UUIDField(
    primary_key=True,
    default=uuid.uuid4,
    editable=False
)

slug = models.SlugField(max_length=50)
name = models.CharField(max_length=50, unique=True, verbose_name='categories')

class Meta:
    ordering = ['name']
    verbose_name = 'Category'
    verbose_name_plural = 'Categories'

def __str__(self):
    return self.name


class SubCategories(models.Model):
    """
    Subcategories belong to the Categories. Subcategories shall be used as menu-items in navbars, etc.
    You can't delete a Category without deleting all the SubCategries first (on delete=Protect).
    """
prepopulated_fields = {"slug": ("name",)}

id = models.UUIDField(
    primary_key=True,
    default=uuid.uuid4,
    editable=False
)
slug = models.SlugField()
category = models.ForeignKey('Categories', on_delete=models.PROTECT, verbose_name='categories')
name = models.CharField(max_length=50, unique=True, verbose_name='sub categories')

class Meta:
    ordering = ['name']
    verbose_name = 'Sub Category'
    verbose_name_plural = 'Sub Categories'

def __str__(self):
    return self.name

def get_absolute_url(self):
    return reverse('cms_detail', args=[str(self.id)])

class Contents(SoftDeletionModel):
"""
This class will be used to store any content. Those might be wikis, news articles, investment ideas, etc.
"""

class StatusChoice(models.TextChoices):
    DRAFT = 'DRAFT', _('draft')
    PUBLISHED = 'PUBLISHED', _('published')

id = models.UUIDField(
    primary_key=True,
    default=uuid.uuid4,
    editable=False
)
title = models.CharField(max_length=250, verbose_name='title')
summary = models.CharField(max_length=250, blank=True, verbose_name='summary')
content = models.TextField(verbose_name='content')
author = models.ForeignKey(
    settings.AUTH_USER_MODEL,
    on_delete=models.PROTECT,
    verbose_name='author',
    related_name='author',
    related_query_name='author'
)
creation_date = models.DateTimeField(auto_now=False, auto_now_add=True, verbose_name='creation date')
status = models.CharField(
    max_length=15,
    choices=StatusChoice.choices,
    default=StatusChoice.DRAFT,
    verbose_name='status'
)
modified_author = models.ForeignKey(
    settings.AUTH_USER_MODEL,
    on_delete=models.PROTECT,
    verbose_name='modified author',
    related_name='modified_author',
    related_query_name='modified_author'
)
modified_date = models.DateTimeField(auto_now=True, auto_now_add=False, verbose_name='modified date')
category = models.ForeignKey('Categories', on_delete=models.PROTECT, verbose_name='category')
sub_category = models.ForeignKey('SubCategories', on_delete=models.PROTECT, verbose_name='sub category')
comments_allowed = models.BooleanField(default=False, verbose_name='comments allowed')

class Meta:
    verbose_name = 'Content'
    permissions = [
        ('can_add_wiki', 'Can add Wiki'),
        ('can_change_wiki', 'Can change Wiki'),
        ('can_delete_wiki', 'Can delete Wiki'),
        ('can_view_wiki', 'Can view Wiki'),
    ]

def __str__(self):
    return self.title

Просмотры

# Create your views here.
class SubCategoryCMSListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
"""
This view filters the Contents Model based on the sub_categories that belong to the wiki
category.
"""
model = Contents

template_name = 'cms/cms_list_by_subcategory.html'
context_object_name = 'cms_list'

status = None
sub_category = None

raise_exception = True
permission_denied_message = 'No permission to add Content!'

def get_permission_required(self):
    self.sub_category = get_object_or_404(SubCategories, slug=self.kwargs['sub_category'])
    category = str(Categories.objects.filter(subcategories=self.sub_category).first()).lower()
    return ('cms.can_view_' + category,)

def get_object(self, queryset=None):
    return queryset.get(status=self.status)

def get_queryset(self):
    # self.sub_category = get_object_or_404(SubCategories, slug=self.kwargs['sub_category'])
    return Contents.objects.filter(sub_category=self.sub_category).filter(status=self.status.upper())

def get_context_data(self, **kwargs):
    """ get_context_data let you fill the template context """
    context = super().get_context_data(**kwargs)
    context['sub_category'] = SubCategories.objects.filter(name=self.sub_category).first()
    context['category'] = Categories.objects.filter(subcategories=self.sub_category).first()
    context['add_perm'] = 'cms.can_add_' + str(
        Categories.objects.filter(subcategories=self.sub_category).first().name).lower()
    return context


class CMSDetailView(LoginRequiredMixin, DetailView):
"""
This view shows the Detail of a certain content of the generic CMS database
"""
model = Contents

template_name = 'cms/cms_detail.html'
context_object_name = 'cms_detail'

def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context['change_perm'] = 'cms.can_change_' + str(self.get_object().category).lower()
    context['delete_perm'] = 'cms.can_delete_' + str(self.get_object().category).lower()
    context['files'] = ContentsFiles.objects.filter(content=self.get_object())
    return context


class CMSCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
model = Contents
form_class = ContentsForm

template_name = 'cms/cms_new.html'

raise_exception = True
permission_denied_message = 'No permission to add Content!'

def get_permission_required(self):
    category = self.kwargs['category'].lower()
    return ('cms.can_add_' + category,)

def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    category = get_object_or_404(Categories, name=self.kwargs['category'])
    context['category'] = get_object_or_404(Categories, name=self.kwargs['category'])
    context['form'].fields['sub_category'].queryset = SubCategories.objects.filter(category=category)
    return context

def form_valid(self, form):
    form.instance.author = self.request.user
    form.instance.modified_author = self.request.user
    form.instance.category = get_object_or_404(Categories, name=self.kwargs['category'])
    form.instance.comments_allowed = False
    files = self.request.FILES.getlist('files')

    response = super().form_valid(form)

    for f in files:
        content = get_object_or_404(Contents, id=self.object.pk)
        ContentsFiles.objects.create(content=content, document=f)

    return response

def get_success_url(self):
    sub_category = get_object_or_404(SubCategories, name=self.object.sub_category)
    return reverse('cms', kwargs={'sub_category': sub_category.slug})


class CMSDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
    model = Contents
context_object_name = 'cms_detail'

raise_exception = True
permission_denied_message = 'No permission to add Content!'

def get_success_url(self):
    sub_category = SubCategories.objects.filter(name=self.get_object().sub_category).first().slug
    success_url = reverse_lazy('cms', args=[sub_category])
    return success_url

def get_permission_required(self):
    category = str(self.get_object().category).lower()
    return ('cms.can_add_' + category,)


class CMSUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
    model = Contents
context_object_name = 'cms_detail'
template_name_suffix = '_update_form'

raise_exception = True
permission_denied_message = 'No permission to add Content!'

form_class = ContentsForm

def get_permission_required(self):
    category = str(self.get_object().category).lower()
    return ('cms.can_add_' + category,)

def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context['form'].fields['sub_category'].queryset = SubCategories.objects.filter(
        category=self.get_object().category)
    context['form2'] = ContentsUpdateForm()
    return context

def get_success_url(self):
    sub_category = SubCategories.objects.filter(name=self.get_object().sub_category).first().slug
    success_url = reverse_lazy('cms', args=[sub_category])
    return success_url

Формы

class ContentsForm(ModelForm):
    content = SummernoteTextFormField()
    files = FileField(widget=ClearableFileInput(attrs={'multiple': True}), required=False)

    class Meta:
        model = Contents
        fields = [
            'title',
            'summary',
            'content',
            'status',
            'sub_category',
            'tags',
            'files',
        ]

Шаблоны URL

urlpatterns = [
    # Wiki
    path('<sub_category>/', SubCategoryCMSListView.as_view(status='published'), name='cms'),
    path('<sub_category>/drafts/', SubCategoryCMSListView.as_view(status='draft'), name='cms_draft'),
    path('<uuid:pk>', CMSDetailView.as_view(), name='cms_detail'),
    path('<category>/new', CMSCreateView.as_view(), name='cms_create'),
    path('<uuid:pk>/delete', CMSDeleteView.as_view(), name='cms_delete'),
    path('<uuid:pk>/update', CMSUpdateView.as_view(), name='cms_update'),
]

Идея заключается в том, что пользователь может щелкнуть ссылку типа «удалить прикрепление ", где его затем спрашивают, действительно ли он хочет удалить вложение, и после подтверждения его возвращают обратно на страницу с подробностями сообщения. Есть подсказки, как я могу подойти к этому?

...