Search code examples
pythondjangocsvdjango-modelsfilefield

How is the file from OneToOne Model's FileField accessed, read in views.py and passed to template?


I am developing a simple Data Visualization App, where a user can register, login upload a file and visualize its content.

I am using default User model, and a Detail Model having OneToOne relation with User Model. The Detail has 3 fields, which are:

OneToOne(User)
FileField()
TextField()

Now, I want to access the file that is saved in FileField, in views.pyand read it's content, then visualize it using Python'sNumPyandMatplotlib`, then finally show visualization results on the frontend.

I need a guidance that how should I start and approach this task? Basically, I need deep guidance in how to access and read the file in views.py?

My models.py is:

class Detail(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    file = models.FileField(verbose_name="CSV File", upload_to='csv_files/')
    file_desc = models.TextField("CSV File Description")

    def __str__(self):
        return ("{} ({} {})".format(self.user.email, self.user.first_name, self.user.last_name))

and in views.py, I am approaching it this way:

class VisualizeAPI(View):
    template_name = 'accounts/visualize.html'

    def get(self, request):
        msg = {'message': "Please login to view this page."}
        
        if request.user.is_authenticated:
            detail, _ = Detail.objects.get_or_create(user=request.user)
            context = {'detail': detail}

            return render(request, self.template_name, context)

        return render(request, self.template_name, msg)

and in template, I am approaching it this way:

<body>
    <h1>Visualized Details</h1>
 
    {% if request.user.is_authenticated %}
    {{ detail }}
    {% else %}
    <h2>{{ message }}</h2>
    {% endif %}
</body>

But it is not printing the content of the file on the frontend. I will be glad for proper approach and guidance provided.


Solution

  • You need to parse the CSV file in your view and then pass it to your template.

    import csv
    from io import StringIO
    
    
    class VisualizeAPI(View):
        template_name = "accounts/visualize.html"
    
        def get(self, request):
            msg = {"message": "Please login to view this page."}
    
            if request.user.is_authenticated:
                detail, _ = Detail.objects.get_or_create(user=request.user)
                if detail.file:
                    # Read file from detail object
                    file = detail.file.read().decode("utf-8")
                    # Parse file as csv
                    csv_data = csv.reader(StringIO(file), delimiter=",")
                else:
                    csv_data = None
                context = {
                    "detail": detail,
                    "csv_data": csv_data,
                }
    
                return render(request, self.template_name, context)
    
            return render(request, self.template_name, msg)
    

    Then you can print each row of your csv file in your template.

    <body>
      <h1>Visualized Details</h1>
    
      {% if request.user.is_authenticated %}
      {{ detail }}
      {% for row in csv_data %}
        {{ row }}
      {% endfor %}
      {% else %}
      <h2>{{ message }}</h2>
      {% endif %}
    </body>