Я создал приложение 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'),
]
Идея заключается в том, что пользователь может щелкнуть ссылку типа «удалить прикрепление ", где его затем спрашивают, действительно ли он хочет удалить вложение, и после подтверждения его возвращают обратно на страницу с подробностями сообщения. Есть подсказки, как я могу подойти к этому?