Python / Django - Vcard照片

时间:2014-08-26 09:49:39

标签: python django vcard vobject

我正在尝试使用vobject库生成vcard,但我遇到了几个问题。

首先,我尝试使用url和base64数据添加照片,但我无法将照片显示在OS X联系人应用程序(Mavericks)或运行Android 4.4.2的Galaxy S4上。我甚至在运行Windows Phone 8.1的Lumia 1520上试过这个,但无济于事。

代码如下:

card = vobject.vCard()

attr = card.add('n')
attr.value = vobject.vcard.Name(family=agent.last_name, given=agent.first_name)

attr = card.add('fn')
attr.value = agent.get_full_name()

attr = card.add('email')
attr.value = agent.email_address
attr.type_param = 'INTERNET'

attr = card.add('tel')
attr.value = agent.cell_number
attr.type_param = 'cell'

attr = card.add('tel')
attr.value = branch.get_telephone_number()
attr.type_param = 'work'

attr = card.add('org')
attr.value = "Moe's Co"

photo_url = "http://www.abcrealestate.co.za/resize/100/150/uploads/agents/2012/03/testagent.jpg"
f = urllib.urlopen(photo_url)
data = f.read()
f.close()

attr = card.add('photo')
attr.type_param = 'JPEG'
attr.value = photo_url

response = HttpResponse(mimetype='text/x-vcard')
response['Content-Disposition'] = 'attachment; filename="%s.vcf"' % agent.get_full_name()
response.write(card.serialize())

return response

这将生成以下文件:

BEGIN:VCARD
VERSION:3.0
EMAIL;TYPE=INTERNET:test@example.com
FN:Abad Muhammed
N:Muhammed;Abad
ORG:M;o;e;';s; ;C;o
PHOTO;TYPE=JPEG:http://www.abcrealestate.co.za/resize/100/150/uploads/agents/2012/03/testagent.jpg
TEL;TYPE=cell:012 345 6789
TEL;TYPE=work:012 345 6789
END:VCARD

上述方法将图像的URL作为照片放置。基础64实现的代码(有关详细信息,请参阅here)如下所示:

photo_url = "http://www.abcrealestate.co.za/resize/100/150/uploads/agents/2012/03/testagent.jpg"
f = urllib.urlopen(photo_url)
data = f.read()
f.close()

attr = vcard.add('photo')
attr.type_param = 'jpeg'
attr.encoding_param = 'b'
attr.value = base64.encodestring(data)

结果:

BEGIN:VCARD
VERSION:3.0
EMAIL;TYPE=INTERNET:test@example.com
FN:Abad Muhammed
N:Muhammed;Abad
ORG:M;o;e;';s; ;C;o
PHOTO;TYPE=jpeg;ENCODING=b:LzlqLzRBQVFTa1pKUmdBQkFRQUFBUUFCQUFELzJ3QkRBQU1DQWdNQ0FnTURBd01FQXdNRUJRZ0ZCUVFFQlFvSEJ3WUlEQW9NREFzSwpDd3NORGhJUURRNFJEZ3NMRUJZUUVSTVVGUlVWREE4WEdCWVVHQklVRlJULzJ3QkRBUU1FQkFVRUJRa0ZCUWtVRFFzTkZCUVVGQlFVCkZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJUL3dBQVJDQUNXQUdRREFTSUEKQWhFQkF4RUIvOFFBSHdBQUFRVUJBUUVCQVFFQUFBQUFBQUFBQUFFQ0F3UUZCZ2NJQ1FvTC84UUF0UkFBQWdFREF3SUVBd1VGQkFRQQpBQUY5QVFJREFBUVJCUkloTVVFR0UxRmhCeUp4RkRLQmthRUlJMEt4d1JWUzBmQWtNMkp5Z2drS0ZoY1lHUm9sSmljb0tTbzBOVFkzCk9EazZRMFJGUmtkSVNVcFRWRlZXVjFoWldtTmtaV1puYUdscWMzUjFkbmQ0ZVhxRGhJV0doNGlKaXBLVGxKV1dsNWlabXFLanBLV20KcDZpcHFyS3p0TFcydDdpNXVzTER4TVhHeDhqSnl0TFQxTlhXMTlqWjJ1SGk0K1RsNXVmbzZlcng4dlAwOWZiMytQbjYvOFFBSHdFQQpBd0VCQVFFQkFRRUJBUUFBQUFBQUFBRUNBd1FGQmdjSUNRb0wvOFFBdFJFQUFnRUNCQVFEQkFjRkJBUUFBUUozQUFFQ0F4RUVCU0V4CkJoSkJVUWRoY1JNaU1vRUlGRUtSb2JIQkNTTXpVdkFWWW5MUkNoWWtOT0VsOFJjWUdSb21KeWdwS2pVMk56ZzVPa05FUlVaSFNFbEsKVTFSVlZsZFlXVnBqWkdWbVoyaHBhbk4wZFhaM2VIbDZnb09FaFlhSGlJbUtrcE9VbFphWG1KbWFvcU9rcGFhbnFLbXFzck8wdGJhMwp1TG02d3NQRXhjYkh5TW5LMHRQVTFkYlgyTm5hNHVQazVlYm42T25xOHZQMDlmYjMrUG42LzlvQURBTUJBQUlSQXhFQVB3RDlVNktLCktBQ2lpaWdBb29vb0FLS0thN2hGSlBTZ0NscWVxMnVpMkU5N2V6cGJXc0s3NUpwRGhWWDFyNXUrSW43Ym1qZUVneDA3dy9xMTdiSzIKMXRRdUxkb1lWLzJ0djMyWDhLNWY5b2Y0NVJhOVBQb3R1WWY3RWdrMnFWdUZXVzZrWCtKVi91ci9BQTE4amVLdkRYanJ4QTAxMXBxeQp5MmJmSzBlcGJmM2kvd0M4dTFxK1F4bWEvdlBaMHBXUjlYZ2NubFZoN1NwRSszZkJYN1oxbHJWeTBPcFd0dWpLcXliWTVOdjd0djhBCmxvck44ckwvQU44MTlDZUV2R0dsZU05TkY3cFZ5bHhGOTFnUHZJMzkxcS9HcXgwbnhsNFhhMWt2OU5sbGtzMXVMZUh5bTNOSkRNdisKcjNmM1ZiNXE5dCtDbjdTSGlUNFhhL2VGTk44K084a3Qxa2p1MlpZMlZWMnQ4MzhMZjNhTUxtVTR5NWFrdWFJOFpsWHU4MFljc2o5Ugp0dEZlUmVDZjJtL0JmaVhRWXIyOTFHRFFMb3NVa3N0UWxWWkZJNys0OUQzb3I2Tll1aS90SHpMdzlSYWNwNi9SUlJYWVloUlJSUUFVClVVVUFKMnhYbjN4eDhWbndYOE10YjFKRHRrRVloVnY3clNNSTkzL2oxZWduaXZNLzJpdkM5MTR5K0RIaXJUTE9Qekx5UzA4MkpDZnYKTkd5eUFmOEFqdGM5ZE9WS1hLYlVPWDJzZVk4RzhFL0NqVExTeHRieTVqYTZta1ZadDA3ZVp0WnZtYXVsMXpTTlBhejhsTGVOZHY4QQpzMWphVjR4azhJL0QzUjlRMVM3MHZUbS9zMk9abDFTU1RjMjJOZk1iYXRiMFhqblJkZDhGcjRoRXRxTGRsMnM4Yk50WnYrQmZOWDV5CjhMSGt1ZnA5TEVTNW94UEdQRjJoMnIzRExGdDNWNUw0ODA1YlBUWkxqeTFsamorV1JXL2lWcTlNOFFlTDRkWm04eGI3UWRQaG0zZloKZnRNMGl5WEczNzIzNWR2eTE1LzhTb3ByRHdmcWtseEdxK1hIdWJhMjVXWCs4clZ3VThQVW9WSTh4NjFXdEN0VGxGSExlSGZHK2sydQptSkhNdC9jT0Nja3RuYjdVVjRMYitLNzFwTGsyeXQ1Um1iSHkwVjczMVUrUDlvZnZwUlJSWDM1OElGRkZGQUJSUlJRQW1PS3p0ZWpWCjlIdmxmN3BnZmRqL0FIYTBxWTZCMEtrY1ZFbzNqWWNYeXl1ZUJhbm85dDloOHFXTzFXMlpmSi9mUjd0cS93QjFhODcrS0hoeExQd0sKZFB0YlRiYlNTZEZYNzFlZ2VQTEc4MHk2dTd1M3NKZFRldzgxb2JDR1JZMmtiK0hidStYZHQrN3VyenZ4cUwzeFA0ZFdWRnNZN2J5LwpNbWphL1dPYUZ2bCtWbGJiODFmQU9FcWlsSGwrRS9WY0ZKUGxtcEhtbmh2d2xEcTNodGJON1cydkxleDNSckJPdnpRN20rWmR2OE5ZCnZpVHd1dC9vdDFwYktxd3RENWFyL0N2L0FOalcxOE85U211dkVHcVc5cmEzTVZyWjIvbVhGOHpLMXRKdS93Q1dhdC9FeTBXcWZiOVMKdlBOL2VxdHF6TXYrMS9Ddi9mVmVXK2FWU05OL0VldlY1YWNaTkhnZGpvemVEMGxzSWRJRjFENWpPczdXVEV5WjRMWjc4ZzBWOXNmcwpqL0NQVWIvNFZUWGZqSFRiU2EvdU5WdW50V3VMV01uN0tDRmp4N2ZLMktLOXhZQ3M5ZVkrZi90bkF3OTNrMlByZWlpaXZ1ajh5Q2lpCmlnQW9vb29BS0tLS0FQT3ZpSGF4Mk43YjN3R3d6aG9wVDlQdXRYa0hqKzBzbXRacHJxd3Q1UTN5dDgzM3E5ZCtLdXQyTnJjYU5wTXoKcUwyOWVhU0dQKzhzY2Z6ZitoTFhoM2pmNGVXZXBMRzFwZFh6WEZ4OTIyaWszZk5YeEdZWGhYbjdNKzh5YXE2ZEdNcEhqWGlMeHZZKwpITEc0dDdObGlhVDkzdFgrN1QvZ0g1dmo3eDVwMXUwTHJveTNNYzEvZHQ5MWxWdHl4LzhBQW0yN3E3WFRmMlhiTkcrM2VJN2hwZjR2CnNrYmJWWC9lYXZFLzJwdjJzOUwrQlduemVBL2h1dHN2aVpvOXR4ZHdLclI2V3JmK2hUZitnL2VhcXkvS2FrcFJyVmZkRE1zNXB1TXEKTkxXWDRINmxSdytUR2tjUVNORkdBb0hTaXZ5SStBUC9BQVZJOFFmQ3I0YVdIaGp4RDRmdVBHVnhZdTZXK3BTM3pwTjVKd1ZqbEpCMwpzcExmTi9kMmp0UlgyVmo0TS9YNmlpaXJBS0tLS0FDaWl2UGZpSjhlZmg5OEtMbUsyOFdlTHRMMFc4bFhlbG5QTnVtWmY3M2xybHR2CisxdG9BOUNyejc0cmZIWHdIOEVORy90SHhwNGtzOURoWmN4d3l2dW5sLzY1d3JtUi93RGdLMThEZnRNZjhGU3IrNGl1dEUrRmxwSnAKa0xiby93RGhJTCtQZGNTRC9wakQ5MlAvQUhtM04vc3JYd2hkZUpkYThVYXRlYTU0aHZMbld0V3VOMGpYZW9UTk5NemY3VE5VQWZxago4WWZFSStPSHhxK0ZzL2dUVnhGZmFIL3hNdFdzN3VHUlpMZXh1TFZtVnBGL3ZmZFhidStWcEYzYmE5OWgreTZYR3F3UnJGY05Hdm1UCi93QVRmN3JmM2ErY2ZnL2NMTDhmSWZGVnJHdjlrNnA0VGh1SkdXUGR0YVJZMmpWZjlyNzFlamZIVDR0YWI4S1BBTjk0MjFlR1NLeHMKMWFPM2czZnZMcWIvQUpaeHIvdk4vd0N6ZjNheGhocWJxU3E4dnZIWlBFMUhUalNVdmRQQy93QnZEOXFKdmhQNFpid3o0ZnV2SzhXYQpsR3F3dEg4eldzUDhVMys5L0N2KzF1YitHdnkxdVBNZHByeSttYWU0bWtacEdsYmN6TTMzbVpxNnJ4eDR3MXI0b2VOTlU4WGVJSnZQCjFUVXBtbVpWKzdHdjhNYS83S3I4cTFodzJ2MnE0V1psWHk0L3VzMzhUZjNxN0RqSUxiVG96Q3BmY1dORmF2bE5SUUIvU0xSUlJVQUYKRkZGQUhHZkZ2NGxhWDhIdmgzcmZqRFd2TmZUOUxoOHhvNFYzUEl4WUtpTC9BTHpNcTErRGZqVDRoNnQ4UlBHWGlMeFpyTncwK3FheApmU1RUU00zM1YzZktxLzdLL2RWZjdxMStoSC9CVHI5b3E0c0dzL2hWb2Q1NWZuUnJlYTk1ZjhVYmY2bTNiLzBZMy9iT3Z6QjFDOVd3CnM1R2IrRnBQL1FxamxBZGZOOW84UVJ4L3c3dk1yVzMvQUhWck5odDltcGVZMy9QUGJWeGJqWXpTTjkxZm1xK1VEOWJQMkE5TTFEVy8KMlovRE45cUxMY3pOY1hrTnJLMGZ6UjJjTXpSd3gvN1g4VzJ2ajcvZ294OGNCOFR2aXZINEgwZTQzZUZmQ0ROYnNJMitXZSsvNWJTZgo4Qi8xYS83cmYzcStzOUkrSmtmN012OEF3VHc4SjYxR3l4NnkzaCszaDAxRy9pdnJwV2tWditBN21rLzREWDVQelhFaitaTTdOUGRUCk16YnBHK2FSbSs4emYraFZZRk82VDdSSjlsVCs3KytiKzZ2OTMvZ1ZXRjJvdjkxZnVyVWNLYlY4dFczTXpicEpmN3pWUisyTGM2MU4KQ1A4QVUyc2FyLzIwYi83R3FBdE5ja241UHUwVWprQnVldEZBSDlKVkZGRlpBRll2aTN4UnAvZ3J3MXF1dmF2UDlsMHpUTGFTOHVwcwpaMnh4cnVhdHF2anIvZ3AzOFYwOEMvczVYUGg4TEtMenhWT3RoSE5IS0Y4bU5HV1NSbVg3eksyMVkvbC81NmZlb0EvTG40MmZFbTQrCkp2eE84U2VLcnhuV2JWcjZTNlZXL3dDV2NiTis3ai80REdxci93QUJyeUh4WmRMY1c5cnNiNzF3cXRXOWZYdjJoZm0rV1QrSmE0M3gKRlA4QTZQd3UzeTdoVy84QUhhc0R2cnB0alZSdkoyWFQ3eHY3c0xmK2cxWXZwZjNLeWYzbXJZK0Z1azJ2aWo0a2VHOUwxRnR1bXpYMApjbDgzOTIxai9mVGYrUTQ1S29ENlcvYnErSmJYODN3OStHTnZKNVduK0Q5QnMydkYzZjhBTDVKYXgvSzMvWE9OVi83K05YeW5KdWxYCnpQOEFWYmwycXJmd3JXMTQ4OFpYWHhFOGJhOTRtdmYrUGpXTDZiVUpsYitGWkpHWlkvOEFnUHlyL3VyWE56VHMrNXQxQUVjbDU5bFcKUmxWZmxXc1R3azhzdzFHOE9OczB2RGZ4VlBxQ3pYRUxSd0swczBueXF0VDZaWS8ySnBpVzd5TDVtNW1rWmY3MUFFenNkM0xVVlRlUwpNdDk5RFJWZ2YweVVVVVZ6Z1kzaW54UnBmZ3J3M3FXdmF6ZHg2ZnBPbXdTWFYxY3ljTEhHbzNNMWZqRjhWdmlMcXY3Yy93QzByWjJTCjZoQm9PbTN6U2FicE1kOXVhTzF0MVZtWGNxL2VrazI3bS8ybTIvdzE5Sy84RlN2Mm43ZTN0WXZoRDRldTJudW04dTg4UU5iTnU4dGYKdlEycmY3VGZMSXkvM2ZML0FMMWZudjhBQ09LenYvaTE0Wi90ZldydnducHYyeFpwdGJnaithMVpWM0xJck44djNsVmYrQlZFdmhOYQpLaktwR01qN08rSS83UHZnRWFwNEw4VHA0SHRsMGZ3M0l0bjRtMHV5M0xIY1JySHRhUmxYNXBHVnRzMzk1bDNWOGhmdGFmQStMNFk2Ci93RDJwb051emVEdFkyeldNcXllWXNmOFNydS91c3JmTFgzemZmRi93YkZwUDJyVC9FV21UcnFFZjJYVU50d3NpK1p1K1c0LzNkemYKOTh0L3MxOC9lT3J6U2Izd0g0bCtIMnU2NVlwQmEvNlpvc3ZtTElza01uemVTckx1L3dCWEo4eS83TEwvQUhhK1pvNHF2Q3I3K3g5OQppc0ZoS3RCOG5MSHpQa1pyenovRGxyTi9zeDFzZkRtNmExdC9GV3JLMjM3UHBiV01iZjNaTHFSWWYvUmYyaXVlc2RFdjQ5RG5zR1NNCk9yTXNaOHhmbSthdm83NFZmc2RlTy9GSHdoZTN0L3NHbVgydFhkdnFoKzNUTnUreHJESXNMTXFxMjNkNWtqS3JmZVhhMzNXV3ZxS3QKV25SajdTcExsaWZBd3BUcXk5blRqek0rZHRRdjlza2NLZkxKY2Z2Ry93QjMrSC94Mm9kVXY0N0NGVjNmTlgxWGUvOEFCT3p4SzJycApkUytMZE9VcXZLcFp6Ti83TXRZdmpIOWlmVGZBV2c2ajRpOFplTGI2NnNiVlYvMGJSOVBWWkpHWnRxcnVrWnR2ek45N2JYbkxOTUhLClhMR1Y1Zk05TCt5Y1hHUE5LUHUrcVBtN1E3eFpkMXh0WmwrN3VYK0dyRjFjUjd0ejBsM2FRNlVqUVdFYnhXNVptK1krWTMvQW1xZ3IKeHY4QU16SzFldWVRT2E4WFB5cTJLS2dlZDkzeXEyS0tzRCtuQ3VOK0xueERzZmhOOE12RXZqSFVCdXROR3NaYnhrSC9BQzBaVitWZgorQk50WC9nVmRsWGduN2RYaGU3OFcvc2xmRXl4c2QvMmlQUy90bTJQK0pZSkZtWmYrK1kycm5BL0RYWFBFZDU0ajhSYWhyV28zRWx6CnFWOWNTWFZ4T3pibWtta2JkSXpmN1RNMVZadFVrVmY3ek4vRC9lckprdWxWV2JkOHRReDM3UmZNcXEwemZkLzJhMUExR0xiVzgxbGEKNGtYL0FJREd0VFd0MTluaFdHTDVZVi9oL3ZWaHgzVFB1K2JlMzhUZjNxc1EzUzdmdkx1cFdRN3M5ci9aaitHY2Z4dCtPUGhYd25jZgo4Z3U0dUd1dFJaZitmT0ZmTW0vNzZWZHYvQXEvUXY0SitJWlBFdmcvVVBGRjE1Y0UydGFoY2FoNUMvZGpqWnRzTWEvM1ZXRlkxWC9kCnI0Ni80SjRlTWZEL0FJQytMK3BlSVBFT29XZGpicnBzbW54L2FabGozZWF5N3R1Ny9aajIvd0RBcTVuNG5mR0RXdmhIZDZwNEMwSHgKQnArczIwYzBqV04zYlNlWkg5bFptOHZ6R1g1VmsyL0t5MTRXYVlhdGlveGpUUGZ5bkUwTU5LY3FwK2d1cGVJSVpXVm9HYVZXKzd0Kwphdmp2OXJEOXBQVDViVzY4RjZIYjZmck1kMURKRHF6U1NTSzF1Mjc1VmpaZmwzSzN6ZnhmZDIxODNQOEF0QmZFT1d6azBtNDE2U0NHCmFML1dXMzd0djlwZHkvdzE1eGVYRTNtTXpTYldiK0pmdXRYUGc4bjluVTlwVk9ySFp4N1NuN09nTnV0THQvTWE0dFZhS1RkOTNjeTEKSHFFdXhvMmpadDIzNWxhbS9OdC85bHFuY2RLK3BQbFJmdFVuL1BScUtvbDZLeTVnUDZrcW82bHA5dHFtbjNkamRRclBhWEVaaG5oYgo3cnhzTnJLZndvb3FBUDUxdjJpL2h2RjhIL2poNHk4RTI5eDlwczlGMU9XQzNrSSs5RnkwZTcvYThzaFc5eFhtMGtoMk1lN2ZMUlJRCkJQQ3lydFhiV3JONGowZGRIYTNqMGtyZHRHc1lueU9HL3ZVVVZyRURsZFcxaG5tYU9KZHErOVhORmtTR3lCU01lYS9WNktLVWZpQWYKUGNlZnNWOG5MZkkvOFMxSC9hakxONU1xN20vdkxSUlRBY1pWQzhMVks3a0xMUlJSSUNsUlJSV1FILy9aCg==
TEL;TYPE=cell:012 345 6789
TEL;TYPE=work:012 345 6789
END:VCARD

除了两张照片都没有显示外,我还注意到设置为“Moe's Co”的公司名称在输出文件中的每个字符之间都有半冒号。

有人能指出我做错了什么吗?任何建议将不胜感激。

提前致谢。

3 个答案:

答案 0 :(得分:1)

在第二种情况下,您对Base64数据进行了双重编码。您无需在base64.encodestring上使用data,因为vobject代码会在设置encoding_param = 'b'时为您执行此操作。在我查看消息来源以发现正在发生的事情之前,这一点并不明显。

至于您使用基于URL的方法的第一种情况,我还没有看到一个客户端(Ubuntu上的Evolution,Win 7上的Outlook 2010)在vCard中正常工作。您的客户正在忽略该URL,我的也是。

http://microformats.org/wiki/vcard-implementations处的vCard实施摘要提供了关于不同应用程序中的怪癖的想法,但它并不完整。

答案 1 :(得分:0)

对于公司名称,值应为数组(例如,您可以在公司内部拥有一个部门)。所以只需将公司名称括在括号中:

attr = card.add('org')
attr.value = ["Moe's Co"]

答案 2 :(得分:0)

要获取图像数据,请改用请求库。就像提到的@davidjb一样,您无需将其编码为base64。

import requests
attr.value = requests.get(photo_url).content