【问题标题】:Django form validation when editing existing Model with a FileField使用 FileField 编辑现有模型时的 Django 表单验证
【发布时间】:2019-02-12 11:02:33
【问题描述】:

我是 Django 新手,在编辑具有 FileField 的模型时遇到表单验证问题。

我的模型有两个FileField,一个是强制的,一个不是:

models.py

class Entrega(models.Model):
    """ People's submissions """

    tid = models.AutoField(_('Código de entrega'), primary_key=True)
    titulo = models.CharField(max_length=500)
    memoria = models.FileField(upload_to=user_upload_memoria_directory_path)
    anexos = models.FileField(null=True, blank=True, upload_to=user_upload_anexos_directory_path)

同一个视图应该能够创建新的Entrega 或编辑现有的。

urls.py

urlpatterns = [
    ...
    path('entregas/<int:pk>/edit/', views.edit_or_create_Entrega, name='edit_create_entrega'),
    path('entregas/new/', views.edit_or_create_Entrega, name='edit_create_entrega'),
    ...
]

views.py(不工作,见下文)

@login_required
def edit_or_create_Entrega(request, pk=None):
    """ Shows the form to create/edit Entrega's """
    if request.method == "POST":
        # create form instance and populate it with data from the request
        form = EntregaForm(request.POST, request.FILES)
        if form.is_valid():
            nueva_entrega = form.save()
            return HttpResponseRedirect(reverse('list_all_entregas'))
        else:
            return render(request, 'envio/base.html', {'avisos': _("Errors were found...")})
    else:
        if not pk:
            # if a GET (or any other method) and no pk is provided, create a blank form
            form = EntregaForm()
        else:
            # if GET (or any other method) and pk is provided, we'll fill the form with
            # entrega, if it exists and it belongs to the user
            e = get_object_or_404(Entrega,pk=pk)
            if not e.matricula.persona.user==request.user:
                return render(request, 'envio/base.html', {'avisos': _("You cannot edit other users submissions")})
            else:
                form = EntregaForm(instance=e)

    return render(request, 'envio/entrega_form.html', {'form': form})

views.py(新版本,有效,见下文)

@login_required
def edit_or_create_Entrega(request, pk=None):
    """ Shows the form to create/edit Entrega's """
    if request.method == "POST" and not pk:
        # create form instance and populate it with data from the request
        form = EntregaForm(request.POST, request.FILES)
        if form.is_valid():
            nueva_entrega = form.save()
            return HttpResponseRedirect(reverse('list_all_entregas'))
    elif request.method == "POST" and pk:
        e = get_object_or_404(Entrega,pk=pk)
        if not e.matricula.persona.user==request.user:
            return render(request, 'envio/base.html', {'avisos': _("Solo puedes editar tus propias Entregas")})
        else:
            form = EntregaForm(request.POST, request.FILES, instance=e)
            if form.is_valid():
                edit_entrega = form.save()
                return HttpResponseRedirect(reverse('list_all_entregas'))
    else:
        if not pk:
            # if a GET (or any other method) and no pk is provided, we'll create a blank form
            form = EntregaForm()
            matriculas = Matricula.objects.filter(persona__user=request.user)
            if not matriculas:
                return render(request,'envio/base.html', {'avisos': _("No hay matriculas disponibles")})
        else:
            # if GET (or any other method) and pk is provided, we'll fill the form with
            # entrega, if it exists and it belongs to the user
            e = get_object_or_404(Entrega,pk=pk)
            if not e.matricula.persona.user==request.user:
                return render(request, 'envio/base.html', {'avisos': _("Solo puedes editar tus propias Entregas")})
            else:
                form = EntregaForm(instance=e)

forms.py

class EntregaForm(ModelForm):
    """ Modela un formulario para realizar Entregas """

    class Meta:
        model = Entrega
        fields = ['titulo', ... , 'memoria', 'anexos']

由于不工作,见下文,这就是发生的事情:

  • 我第一次访问entregas/6/edit 时,表单已正确地预填充了存储在数据库中的值。它甚至显示“当前”memoria 值(并提供上传新文件的选项)
  • 如果我在某些字段中进行更改,例如 titulo 并提交表单而不上传新的 memoriafile,form.is_valid()returns false(并且实例未更新)。
  • 如果我在memoriatitle字段中进行更改,则会保存一个新的Entrega(不会更新现有的)。

现在有了新版本,它可以工作了它确实更新了现有的 Entrega。

为了完整起见,我将用两个处理models.py中未使用的文件的函数来完成我的代码:

models.py

@receiver(models.signals.post_delete, sender=Entrega)
def auto_delete_file_on_delete(sender, instance, **kwargs):
    """
    Deletes file from filesystem
    when corresponding 'Entrega' object is deleted.
    Refactor? Perhaps it would be better to use django-cleanup https://github.com/un1t/django-cleanup
    """
    if instance.memoria:
        if os.path.isfile(instance.memoria.path):
            os.remove(instance.memoria.path)
    if instance.anexos:
        if os.path.isfile(instance.anexos.path):
            os.remove(instance.anexos.path)

@receiver(models.signals.pre_save, sender=Entrega)
def auto_delete_file_on_change(sender, instance, **kwargs):
    """
    Deletes old file from filesystem when corresponding 'Entrega' object is updated with new file.
    This function assumes that EVERY entrega has a mandatory 'memoria' field!!
    Refactor? Perhaps it would be better to use django-cleanup https://github.com/un1t/django-cleanup
    """
    if not instance.pk:
        return False

    try:
        old_memoria = Entrega.objects.get(pk=instance.pk).memoria
    except Entrega.DoesNotExist:
        return False
    new_memoria = instance.memoria
    if new_memoria and not old_memoria == new_memoria:
        if os.path.isfile(old_memoria.path):
            os.remove(old_memoria.path)

    old_anexos = None
    try:
        old_anexos = Entrega.objects.get(pk=instance.pk).anexos
    except Entrega.DoesNotExist:
        return False
    # if there were NO old_anexos, no need to do nothing...
    if not old_anexos:
        return True
    # if there were old_anexos, remove them... 
    new_anexos = instance.anexos
    if new_anexos and not old_anexos == new_anexos:
        if os.path.isfile(old_anexos.path):
            os.remove(old_anexos.path)  

【问题讨论】:

  • 我错过了在 POST 中传递实例。编辑我的原始帖子。
  • 是您更改后发生的最后一期(新 Entraga 已保存)吗?你应该从你的帖子中删除“不工作”的版本,现在还不清楚什么不工作。
  • 用有效的views.py 更新了原始问题。
  • 所以您应该将下面的答案标记为正确,因为这有助于您回答问题。
  • @dirkgroten 完成,谢谢! :)

标签: python django


【解决方案1】:

您的代码中有一些错误。当您发出 POST 请求时,您必须检查 pk 值。如果 pk 存在,那么您应该更新模型,否则保存新实例。

if request.method == "POST":
    if pk and form.is_valid():
        // here update the model

【讨论】:

    猜你喜欢
    • 2011-04-22
    • 2011-08-14
    • 2015-05-22
    • 1970-01-01
    • 2012-12-26
    • 1970-01-01
    • 2010-12-29
    • 2017-06-14
    • 2014-12-19
    相关资源
    最近更新 更多