Django中python paramiko错误:'str'对象没有'get_name'属性

1 投票
2 回答
5237 浏览
提问于 2025-04-18 16:47

我听说把媒体文件和你的Django/Apache网站放在同一个服务器上是个非常糟糕的主意。为了改善我的iOS应用的性能,我打算先把图片上传到Django服务器,然后再把这些新上传的图片转移到一个专门用来存放用户头像的服务器上。

我可以使用Paramiko直接把文件发送到我想要的目录,但在我的Django视图中似乎不太奏效。

这里有一个非常简单的Python脚本,使用Paramiko,可以通过SMTP把文件上传到远程服务器:

import base64
import getpass
import os
import socket
import sys
import traceback

import paramiko
#from paramiko.py3compat import input


# setup logging
#paramiko.util.log_to_file('demo_sftp.log')
port = 22
hostname = '198.199.101.115'
password = 'XXXXXXXXX'
username = 'root'
hostkeytype = 'ecdsa-sha2-nistp256'
hostkey = 'XXXXXXXXX'


try:
    host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
except IOError:
    try:
        # try ~/ssh/ too, because windows can't have a folder named ~/.ssh/
        host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/ssh/known_hosts'))
    except IOError:
        print('*** Unable to open host keys file')
        host_keys = {}

if hostname in host_keys:
    hostkeytype = host_keys[hostname].keys()[0]
    hostkey = host_keys[hostname][hostkeytype]
    print('Using host key of type %s' % hostkeytype)


# now, connect and use paramiko Transport to negotiate SSH2 across the connection
t = paramiko.Transport((hostname, port))
t.connect(username=username, password=password, hostkey=hostkey)
sftp = paramiko.SFTPClient.from_transport(t)

    # dirlist on remote host
dirlist = sftp.listdir('.')
print("Dirlist: %s" % dirlist)

    # copy this demo onto the server
target_directory = '3COOL'

sftp.put('test_image.jpg', target_directory+'/test_image.jpg')

t.close()

当我在我的远程服务器上运行这个脚本时,它能完美地把jpeg图片转移到我拥有的另一个远程服务器上。所以我想把这个脚本直接复制粘贴到我的Django视图中,这样就能把所有新上传的图片转移到另一个服务器,下面是这个样子:

def profile_picture(request):
    if request.POST:
        form = UserProfileForm(request.POST, request.FILES)
        obj = form.save(commit=False)
        obj.user_id = request.user.id
        obj.profile_picture = obj.profile_picture

        check = UserProfile.objects.filter(user_id=request.user.id)
        if check:
            oldup = UserProfile.objects.get(user_id=request.user.id)
            oldup.delete()
        obj.save()
        formNew = UserProfileForm()
        args = {}
        args.update(csrf(request))
        args['uid'] = request.user.id
        args['form'] = formNew

        # CONVERT THE IMAGE TO A SMALLER SIZE
        basewidth = 256
        img = Image.open('var/www/bitcraft/static/'+str(obj.profile_picture))
        wpercent = (basewidth/float(img.size[0]))
        hsize = int((float(img.size[1])*float(wpercent)))
        img = img.resize((basewidth,hsize), PIL.Image.ANTIALIAS)
        img.save('var/www/bitcraft/static/'+str(obj.profile_picture))

        import getpass
        import os
        import socket
        import sys
        import traceback
        import paramiko
        from paramiko.py3compat import input

        # TRANSFER THIS IMAGE TO MEDIA HOSTING SERVER  
        port = 22
        hostname = '198.199.101.115'
        password = 'pcorysatqwrw'
        username = 'root'
        hostkeytype = 'ecdsa-sha2-nistp256'
        hostkey = 'pcorysatqwrw'
        try:
            host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
        except IOError:
            try:
                host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/ssh/known_hosts'))
            except IOError:
                print('*** Unable to open host keys file')
                host_keys = {}
        if hostname in host_keys:
            hostkeytype = host_keys[hostname].keys()[0]
            hostkey = host_keys[hostname][hostkeytype]
            print('Using host key of type %s' % hostkeytype)
        t = paramiko.Transport((hostname, port))
        t.connect(username=username, password=password, hostkey=hostkey)
        sftp = paramiko.SFTPClient.from_transport(t)
        dirlist = sftp.listdir('.')
        print("Dirlist: %s" % dirlist)
        target_directory = '3COOL'
        sftp.put('var/www/bitcraft/static/'+str(obj.profile_picture), target_directory+str(obj.profile_picture))
        t.close()    
        return render_to_response('profile.html', args, RequestContext(request))

    else:
        formNew = UserProfileForm()
        args = {}
        args.update(csrf(request))
        args['uid'] = request.user.id
        args['form'] = formNew
        return render_to_response('profile.html', args, RequestContext(request))

不过,添加这个简单的Python脚本并没有成功,出现了一个奇怪的错误:

在/upload_profile/出现AttributeError:'str'对象没有'get_name'这个属性

异常位置:/usr/local/lib/python2.7/dist-packages/paramiko-1.14.0-py2.7.egg/paramiko/transport.py的connect,行873

/srv/www/django/chatfeed/views.py中的profile_picture t.connect(username=username, password=password, hostkey=hostkey)

我不明白是什么导致了这个问题……这和目录权限被拒绝有关吗?

2 个回答

2
key = paramiko.RSAKey.from_private_key_file(filename='openssh key f',password='passphrase')  

这个密钥文件不支持 .ppk 格式。

4

问题在于你传递了一个字符串给 hostkey。根据文档,这里应该是一个 PKey,也就是说,它是一个用来包装私钥的对象。

如果你点击 PKey,你会发现 PKey 有一个 get_name 方法。而字符串显然没有这个方法。所以就出现了错误。


你有一些代码是用来通过 Paramiko 从 ~/.ssh/known_hosts 加载 hostkey 的,代码在你的脚本顶部。但是如果 hostname in host_keys 是假的,它就不会做任何事情,你最终会得到你在脚本顶部设置的默认值:

hostkeytype = 'ecdsa-sha2-nistp256'
hostkey = 'XXXXXXXXX'

我不知道你在实际代码中用什么替代了 'XXXXXXXXX',但可以推测它是一个字符串,因此不是一个有效的 hostkey


我不明白是什么导致了这个问题……这和目录权限被拒绝有关吗?

你需要告诉我们你在说什么。具体是什么错误、警告或者其他信息,你在哪里看到的?如果服务器以一个没有访问自己 ~/.ssh 权限的用户身份运行,那么你可能会看到某种“目录权限被拒绝”的警告,这样你的主机密钥就无法加载了。那么是的,这个问题间接和那个有关——也就是说,如果主机确实在 known_keys 中,并且你解决了权限问题,那么这会掩盖你代码中的错误,让你没有注意到。但还有很多其他情况,你可能想说的事情,答案就是否定的,那和这个没有关系。

撰写回答