模型上的Django FileField,删除模型和确认时删除文件

时间:2015-08-05 13:19:29

标签: python django

我有一个上传信息中心,上传表单和显示文件的表格。在最后一列中是诸如删除之类的操作。但是当我按下删除它会删除数据库中的模型,但文件仍然在文件夹中。我想要从这个文件夹中删除文件,如果我可以将删除的文件移动到另一个类似回收站的目录,那么甚至更好,这样管理员即使被上传的用户删除也可以查看文件。 (用户基数低于10,因此可以很简单)

除此之外,我很奇怪是否有办法在pre_delete中包含某种确认警告框,这样当他们按下删除时它会在对话框中要求确认。

这是我到目前为止的代码:

我的视图一个用于仪表板,另一个用于删除:

@login_required(login_url='/dashboard-login/')
def dashboard(request):
    current_user = request.user
    current_client = request.user.client

    files = ClientUpload.objects.filter(client=current_client)

    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            dz_files = request.FILES.getlist('file_upload')
            for f in dz_files:
                new_file = ClientUpload(client=current_client, file_upload=f)
                new_file.save() 
                logger = logging.getLogger(__name__)
                logger.info("File uploaded from " + current_client.company)
        else:
            logger = logging.getLogger(__name__)
            logger.warning("Upload Failed")

        return HttpResponseRedirect(reverse('dashboard'))
    else:
        form = UploadFileForm()

    data = {'form': form, 'client': current_client, 'files': files}
    return render_to_response('dashboard.html', data, context_instance=RequestContext(request))


def dashboard_delete(request, upload_id):
    current_user = request.user
    current_client = request.user.client
    form = UploadFileForm()

    p = ClientUpload.objects.get(pk=upload_id)
    p.delete()

    files = ClientUpload.objects.filter(client=current_client)
    data = {'form': form, 'client': current_client, 'files': files}

    return render_to_response('dashboard.html', data, context_instance=RequestContext(request))

我的模特和信号:

@python_2_unicode_compatible
class ClientUpload(models.Model):

    client = models.ForeignKey(Client)
    created_at = models.DateTimeField(auto_now_add=True)

    file_upload = models.FileField(upload_to=generate_filename)

    def __str__(self):
        return self.client.company

    class Meta:
        verbose_name_plural = _("Client Uploads")
        verbose_name = _("Client Upload")

@receiver(post_delete, sender=ClientUpload)
def clientupload_delete(sender, instance, **kwargs):
    if instance.file:
        # Pass false so FileField doesn't save the model.
        instance.file.delete(False)
    else:
        # log failure

我的文件列表模板:

{% load i18n %}
{% load staticfiles %}
{% load sasite_filters %}

<table class="table">
<tr>
    <th>{% blocktrans %}Filename{% endblocktrans %}</th>
    <th>{% blocktrans %}Size (Bytes){% endblocktrans %}</th>
    <th>{% blocktrans %}Upload Time{% endblocktrans %}</th>
    <th>{% blocktrans %}Actions{% endblocktrans %}</th>
</tr>
{% for file in files %}
    {% with uploaded_file=file.file_upload %}  
 <tr>
    <th><a href='{{ uploaded_file.url }}'>{{ uploaded_file.name|pathend}}</a></th>
    <th>{{ uploaded_file.size }}</th>
    <th>{{ file.created_at }}</th>
    <th><a href="{% url 'dashboard-delete' file.id %}">Delete</a></th>
    {% endwith %}
{% endfor %}
</tr>   
</table>

我的信息中心的网址已删除:

url(r'^dashboard/delete/(?P<upload_id>\d+)$', views.dashboard_delete, name='dashboard-delete'),

这是否需要我确保删除文件?我是否正确使用了信号?我错过了一步吗?我只想确定,因为我试图添加信号,我希望将文件复制到&#34;回收站&#34;在我擦除之前的目录,此时它不需要模型,只能是目录中的文件。但无论如何,在我完成删除模型之前,我希望将其从upload_to目录中删除并移至另一个目录。

前或后删除正确的在线使用?并删除确认框?我应该使用pre_delete还是应该使用JavaScript进行确认对话?我不确定。任何示例/建议都有很大的帮助。

提前致谢。

编辑:

我不完全确定发布/预删除信号是如何工作的,但它似乎适用于删除文件。但我不确定它是否也能用于移动文件。使用FileStorageSystem或自定义文件存储会更好吗?基本上我想在删除之前将文件移动到另一个目录。有人能举例说明我在post_delete中做过的信号吗?如果FileStorage有更好的方法,那么这个例子将是一个很大的帮助,因为我不能为我的生活找到如何实现这一目标。

我的第二个问题是添加确认删除,我认为通过JS / jQuery可以更好地实现?有人告诉我,如果我使用DeleteView CBV会有删除确认,但是我无法让它工作。

再次感谢。

EDIT2:

以下是我在删除文件之前尝试移动文件的情况,请告诉我,如果我搞砸了它,它似乎有用,但我不太确定,因为我从来没有真的之前使用过这样的信号。

@receiver(post_delete, sender=ClientUpload)
def clientupload_postdelete(sender, instance, **kwargs):
    if instance.file:
        with f as open(settings.MEDIA_ROOT + '/uploads/Recycle', 'w+'):
            f.write(instance.file)
            f.close()
        # Pass false so FileField doesn't save the model.
        instance.file.delete(False)
    else:
        logger = logging.getLogger(__name__)
        logger.Warn("Failed to delete %s" % instance.file)

1 个答案:

答案 0 :(得分:0)

我找到的解决方案是像这样使用shutil.move()

@receiver(post_delete, sender=ClientUpload)
def clientupload_postdelete(sender, instance, **kwargs):
    if instance.file_upload:
        filename = os.path.basename(instance.file_upload.path)
        client = instance.client.company

        folder_path = os.path.join(settings.MEDIA_ROOT, 'uploads/Recycle/', client + '/')
        if not os.path.exists(folder_path):
            os.makedirs(folder_path)

        if os.path.exists(os.path.join(folder_path, filename)):
            filename = append_id(filename)

        shutil.move(instance.file_upload.path, os.path.join(folder_path, filename))

        logger = logging.getLogger(__name__)
        logger.info("File %s moved to %s" % (filename, settings.MEDIA_ROOT + '/uploads/Recycle/' + client + '/'))
        # Pass False so FileField doesn't save the model.
        instance.file_upload.delete(False)
    else:
        logger = logging.getLogger(__name__)
        logger.warning("Failed to find file for copying to %s." % (settings.MEDIA_ROOT + '/uploads/Recycle/'))