Search code examples
djangodjango-formsvcf-vcarddjango-uploads

Django upload and read vcard object - loosing my mind


I am trying to let users of my Django app upload vcards through a form, parse those vcards on the fly and then serve some of the content back to the front-end without storing the vcards on server.

I have successfully found a way to read and extract content from vcards that are stored on my machine using the vobject library and a few lines of code like the one below

 with open(vcard_path) as source_file:
        for vcard in vobject.readComponents(source_file):
            full_name = vcard.contents['fn']
            ....

However, I am failing to replicate this approach when accessing a vcard file that has been uploaded through a django form.

I have this form

<form action="{% url "action:upload_vcard" %}" method="POST" enctype="multipart/form-data" class="form-horizontal">
{% csrf_token %}
<div class="form-group">
    <label for="name" class="col-md-3 col-sm-3 col-xs-12 control-label">File: </label>
    <div class="col-md-8">
        <input type="file" name="vcard" id="vcard_file" required="True" class="form-control">
    </div>
</div>
<div class="form-group">
    <div class="col-md-3 col-sm-3 col-xs-12 col-md-offset-3" style="margin-bottom:10px;">
         <button class="btn btn-primary"> <span class="glyphicon glyphicon-upload" style="margin-right:5px;"></span>Upload </button>
    </div>
</div>
</form>

and this is the view

def upload_vcard(request):

    data = {}
    if "GET" == request.method:
        return render(request, "action/upload_test.html", data)
    # if not GET, then proceed

    file = request.FILES["vcard"]

    with open(file) as source_file:
        for vcard in vobject.readComponents(source_file):
            full_name = vcard.contents['fn']

    
    return HttpResponseRedirect(reverse("action:upload_vcard"))

In this case I get the error that TypeError: expected str, bytes or os.PathLike object, not InMemoryUploadedFile . I looked around and some suggested to remove the "open()" part of the code and just consider the file as already opened.

I tried that by changing

with open(file) as source_file:
        for vcard in vobject.readComponents(source_file):
            full_name = vcard.contents['fn']

with just the below code but I still got the error TypeError: cannot use a string pattern on a bytes-like object

for vcard in vobject.readComponents(file):
        full_name = vcard.contents['fn']

Any help? I tried for hours and can't figure out the problem.


Solution

  • This did the trick

    file = request.FILES["vcard"].read()
    
    vcard_path=file.decode("utf-8")