首页 > 解决方案 > Django 2.0.7。用户尝试上传文件时缺少 url 中的完整路径。它适用于本地环境,但不适用于生产服务器

问题描述

我有一个带有 ImageField 的模型:

class Usr( User ):
    idusuario = models.AutoField( primary_key = True )
    usuario = models.CharField( blank = False, unique = True, max_length = 50 )
    contraseña = models.CharField( blank = False, max_length = 250 )
    telefono = models.CharField( max_length = 15, blank = True, null = True )
    celular = models.CharField( max_length = 15, blank = True, null = True )
    fotografia = models.ImageField( blank = True, null = True, upload_to = 'usuarios' )
    depende_de = models.ForeignKey( 'self', on_delete = models.CASCADE, related_name = '+', blank = True, null = True )
    def __unicode__( self ):
        return self.get_full_name()
    def __str__( self ):
        return self.get_full_name()

及其形式(一个 ModelForm ):

class RegUsuario( forms.ModelForm ):
    class Meta:
        model = Usr
        fields = [ 
            'usuario', 
            'contraseña', 
            'is_active', 
            'is_superuser', 
            'first_name', 
            'last_name', 
            'email', 
            'telefono', 
            'celular', 
            'fotografia', 
            'groups', 
            'depende_de' 
        ]

在视图(vw_usuario.py)中,我有:

@valida_acceso( [ 'usr.agregar_usuarios_usuario' ] )
def new( request ):
    if 'POST' == request.method:
        frm = RegUsuario( request.POST, files = request.FILES  )
        if frm.is_valid():
            obj = frm.save( commit = False )
            obj.username = obj.usuario
            obj.set_password( obj.contraseña )
            obj.save()
            for g in request.POST.getlist( 'groups' ):
                obj.groups.add( g )
            obj.save()
            return HttpResponseRedirect( reverse( 'usuario_ver', kwargs = { 'pk' : obj.pk } ) )
    frm = RegUsuario( request.POST or None )
    return render( request, 'global/form.html', {
        'menu_main' : Usr.objects.filter( id = request.user.pk )[ 0 ].main_menu_struct(),
        'footer' : True,
        'titulo' : 'Usuarios',
        'titulo_descripcion' : 'Nuevo',
        'frm' : frm
    } )

在 urls.py 中:

urlpatterns = [
    ...
    path( 'usuarios/nuevo/',            vw_usuario.new,     name = "usuario_nuevo" ),
    ...
    ]

如果我在浏览器中访问http://example.com/usuarios/nuevo/我也可以显示表单,然后我填写字段并提交表单,我得到了异常:

Page not found (404) 
Request Method: POST 
Request URL:    http://example.com/usuarios/nuevo/ 
Raised by:  seguridad.mkitsafe.validacion 
Using the URLconf defined in example.urls, Django tried these URL patterns, in this order: 
... 
usuarios/eliminar/<pk>/ [name= usuario_eliminar ] 
usuarios/nuevo/ [name= usuario_nuevo ] 
usuarios/<pk>/ [name= usuario_ver ] 
... 
The current path, nuevo/, didn t match any of these. 

我不明白为什么 url 被视为nuevo/而不是usuarios/nuevo/

在我正在设置的表单模板中method = "post"enctype="multipart/form-data"并且action=""(我也尝试过action="usuarios/nuevo"action="http://example.com/usuarios/nuevo/"

存在的路径MEDIA_ROOT并具有足够的权限。

如果我填写 ImageField 字段的表格,就会出现问题。

我注意到,如果我删除模型表单中的字段,一切正常。

seguridad.mkitsafe.validacion 的源代码是:

def valida_acceso( permisos = None ):
    url_error = 'seguridad_inicio'
    url_autenticacion = 'seguridad_login'

    def _valida_acceso( vista ):

        def validacion( *args, **kwargs ):
            usuario = args[ 0 ].user
            if not usuario.is_authenticated:
                print_error( "Vista {} negada por autenticación".format( vista.__name__ ), "Exec Info" )
                return HttpResponseRedirect( reverse( url_autenticacion ) )
            if permisos is None:
                return vista( *args, **kwargs )
            perms = []
            for perm in permisos:
                permiso = Permiso.get_from_package_codename( perm )
                if( permiso is None ):
                    print_error( "No se ha encontrado el permiso: " + perm )
                else:
                    perms.append( permiso.perm() )
                    desc = permiso.descendencia()
                    for p in desc:
                        perms.append( p.perm() )
            for perm in perms:
                p = "{}.{}".format( perm.content_type.app_label, perm.codename )
                if usuario.has_perm( p ):
                    return vista( *args, **kwargs )
            print_error( "Vista {} negada por permisos {}".format( vista.__name__, permisos ), "Exec Info" )
            return HttpResponseRedirect( reverse( url_error ) )
        return validacion

    return _valida_acceso

它是一个装饰器,用于验证烫发和身份验证。

如果我删除此装饰器,则异常会更改Raised byseguridad.vw_usuario.new

Page not found (404)
Request Method: POST
Request URL:    http://example.com/usuarios/nuevo/
Raised by:  seguridad.vw_usuario.new

Using the URLconf defined in example.urls, Django tried these URL patterns, in this order:

admin/
...
usuarios/actualizar/<pk>/ [name='usuario_actualizar']
usuarios/eliminar/<pk>/ [name='usuario_eliminar']
usuarios/nuevo/ [name='usuario_nuevo']
usuarios/<pk>/ [name='usuario_ver']
usuarios/ [name='usuario_inicio']
...

The current path, nuevo/, didn't match any of these.

我还注意到,当引发错误并且装饰器处于活动状态时,不会调用装饰器或视图函数。

我还尝试使用脚本复制 MEDIA_ROOT 路径中的文件,并且效果也很好,因此脚本有权访问此路径。

对这个问题有任何评论吗?

标签: djangoimage-uploading

解决方案


推荐阅读