2

I am creating a taskToDo web application. Most of the html files under templates are extending base.html file which includes a navbar in which i want to show the user profile picture under navbar of base.html. The profile picture is getting saved under profile_pics directory of 'media' folder.

I have tried giving {{user.profile_pic.url}} as the source for image, but still the image is not getting linked My models.py , project urls.py, settings.py, relevant part of views.py are as follows:-

models.py

from django.db import models
from django.contrib.auth.models import User
from django.conf import settings
from django.core.exceptions import ValidationError
from datetime import datetime
# Create your models here.

class UserCustom(models.Model):
    user=models.OneToOneField(User,on_delete=models.CASCADE)

    profile_pic=models.ImageField(upload_to='profile_pics',blank=True)

    def __str__(self):
        return self.user.username   #user os object defined above


class UserTask(models.Model):
    author = models.ForeignKey(User,on_delete=models.CASCADE)
    label=models.CharField(max_length=264)
    date=models.DateField()
    status=models.BooleanField(default=False)


    def __str__(self):
        return str(self.label)

settings.py

from django.contrib import admin
from django.urls import path,include
from taskApp import views
from django.conf.urls.static import static
from django.conf import settings # new
urlpatterns = [
    path('admin/', admin.site.urls),
    path('',views.index,name='index'),
    path('taskApp/',include('taskApp.urls')),
    path('logout/',views.user_logout,name='logout'),
]+static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

forms.py

from django import forms
from django.forms.fields import DateField
from django.core import validators
from django.contrib.auth.models import User
from taskApp.models import UserCustom,UserTask
from django.contrib.admin.widgets import AdminDateWidget
from datetime import datetime,timedelta

class UserForm(forms.ModelForm):
    password=forms.CharField(widget=forms.PasswordInput())

    class Meta():
        model=User
        fields=('username','email','password')

class UserCustomForm(forms.ModelForm):
    class Meta():
        model=UserCustom
        fields=('profile_pic',)


class UserTaskForm(forms.ModelForm):
    date=DateField(widget=forms.DateInput(attrs={'placeholder': 'YYYY-MM-DD', 'required': 'required'}))
    status=forms.BooleanField(required=False)
    class Meta():
        model=UserTask
        fields=('label','date')

    def clean(self):
        cleaned_data=self.cleaned_data
        date2=cleaned_data.get('date')
        if str(date2)<=(datetime.today()-timedelta(days=1)).strftime('%Y-%m-%d'):
            raise forms.ValidationError("The date cannot be in the past!")
        return cleaned_data

views.py (relevant part)

@login_required
def my_task(request):
    task_obj=UserTask.objects.filter(author=request.user)
    return render(request,'taskApp/task.html',{'task_obj':task_obj,'user_key':request.user})

def register(request):

registered=False

if request.method == "POST":

    user_form=UserForm(data=request.POST)
    profile_form=UserCustomForm(data=request.POST)

    if user_form.is_valid() and profile_form.is_valid():
        user=user_form.save()
        user.set_password(user.password)
        user.save()

        profile=profile_form.save(commit=False)
        profile.user=user

        if 'profile_pic' in request.FILES:
            profile.profile_pic=request.FILES['profile_pic']

        profile.save()
        registered=True

    else:
        print(user_form.errors,profile_form.errors)

else: #no request=POST yet
    user_form=UserForm()
    profile_form=UserCustomForm()

return render(request,'taskApp/registration.html',{'user_form':user_form,'profile_form':profile_form,'registered':registered })


def register(request):
    registered=False

    if request.method == "POST":

        user_form=UserForm(data=request.POST)
        profile_form=UserCustomForm(data=request.POST)

        if user_form.is_valid() and profile_form.is_valid():
            user=user_form.save()
            user.set_password(user.password)
            user.save()

            profile=profile_form.save(commit=False)
            profile.user=user

            if 'profile_pic' in request.FILES:
                profile.profile_pic=request.FILES['profile_pic']

            profile.save()
            registered=True

        else:
            print(user_form.errors,profile_form.errors)

    else: #no request=POST yet
        user_form=UserForm()
        profile_form=UserCustomForm()

    return render(request,'taskApp/registration.html',{'user_form':user_form,'profile_form':profile_form,'registered':registered })



def user_login(request):

    if request.method=='POST':
        username=request.POST.get('username')  #name of element
        password=request.POST.get('password')

        user=authenticate(username=username,password=password)

        if user:
            if user.is_active:
                login(request,user)
                return HttpResponseRedirect(reverse('taskApp:myTask')) #myTask is the name of url , go to urls.py
            else:
                return HttpResponse("ACCOUNT NOT ACTIVE")

        else:
            print("Someone tried to login and failed!")
            print("Username: {} and password {}".format(username,password))
            return HttpResponse("invalid login details supllied!")

    else:
        return render(request,'taskApp/login.html',{})

base.html

<!DOCTYPE html>
{% load static %}
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title></title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">



    <link rel="stylesheet" href="{% static 'css/mystyle.css' %}" >

    <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/js/all.min.js" crossorigin="anonymous"></script> -->

  </head>
  <body>
    <nav class="navbar navbar-default navbar-static-top">
      <div class="container">

        <ul class="nav navbar-nav">
          <li><a class="navbar-brand" href="{% url 'index' %}"><em>ToDoList</em><img src={% static "images/1567073.png" %} width="60" height="50" alt="TASK_TO_DO"></a></li>
          <!-- <li><a class="navbar-brand" href="{% url 'index' %}">Task to do</a></li> -->
          <li><a class="navbar-link" href="{% url 'admin:index' %}">Admin</a></li>
        </ul>

        <ul class="nav navbar-nav">
          {% if user.is_authenticated %}
            <li><a class="navbar-link" href="{% url 'taskApp:myTask' %}">My Tasks</a></li>
            <li><a class="navbar-link" href="{% url 'taskApp:addTask' %}">Add Task</a></li>

        </ul>

        <ul class="nav navbar-nav navbar-right">
              <li><a class="navbar-link" href="#"> {{user}} <span class="glyphicon glyphicon-user"></span></a></li>
              <img class="rounded-circle article-img" src="{{user.profile_pic.url}}" width='240' alt={{user}}> <!--PROBLEM IS HERE-->
              <li><a class="navbar-link" href="{% url 'logout' %}">Logout</a></li>
        </ul>
        <ul class="nav navbar-nav navbar-right">
        {% else %}
            <li><a class="navbar-link" href="{% url 'taskApp:register' %}">Register</a></li>
            <li><a class="navbar-link" href="{% url 'taskApp:user_login' %}">Login</a></li>
        {% endif %}
        </ul>


      </div>

    </nav>

    <div class="container">

      {% block body_block %}
      {% endblock %}


  </body>
</html>
Dharmesh Singh
  • 107
  • 2
  • 11

1 Answers1

2

Where did you use UserCustomForm? There is nothing related with this form in your views.py for passing image to DB. I will consider as you are trying to add image on admin panel for now.

On your html file, you can't access profile_pic directly from user. Try this src="{{user.usercustom.profile_pic.url}}"

from django.core.files.storage import FileSystemStorage add this to top of views.py

and edit related lines in register function with this

image = request.FILES['profile_pic']
if image:
    filename = FileSystemStorage().save('profile_pics/' + image.name, image)
    profile.profile_pic = filename
profile.save()

Edit: image =request.FILES['profile_pic] is not string although we have to pass it to DB as string. image.name is a string we need but without MEDIA_ROOT value. FileSystemStorage appends the MEDIA_ROOT value to any file it saves

Mehmet Can
  • 116
  • 5
  • i am using UserCustom in registration part ( I have edited the question by adding **register view** ) please look to it. Through registration page only user saves the profile picture in database. – Dharmesh Singh May 29 '20 at 19:45
  • Can you see the image file on your admin panel? Your problem is saving file or rendering on html? And did you change the part I mentioned? – Mehmet Can May 29 '20 at 20:00
  • I need to see the image in the navbar(under base.html) which i extended using template inheritance in all the html files.....still the image cannot be linked/displayed.(the problem is in rendering image in base.html).. yes i tried using {{user.usercustom.profile_pic.url}} ..still no difference – Dharmesh Singh May 29 '20 at 20:33
  • 1
    You can find your solution with searching on FileSystemStorage. But I edited my previous answer and add a code. Please try it and let me know – Mehmet Can May 29 '20 at 21:31
  • Thanks it worked, but may i know why it was not working earlier allthough the following lines **if 'profile_pic' in request.FILES: profile.profile_pic=request.FILES['profile_pic']** were already present in register views ...... i had to add the above lines of the answer... Also does it become redundant as the both the code snippets are quite similar ? – Dharmesh Singh May 30 '20 at 04:41
  • 1
    First of all, the above code is not an addition. You should delete your previous code and change with the new one. Your previous code didn't work because `request.FILES['profile_pic]` is not string although we have to pass it to DB as string. You can check with printing the type of image and fieldname. And image.name is a string we need but without MEDIA_ROOT value. FileSystemStorage appends the MEDIA_ROOT value to any file it saves. – Mehmet Can May 30 '20 at 09:57
  • thanks i got it... also why i need to add **usercustom** before accessing profile picture url in base.html as i have not created instance of this name (case sensitive) anywhere else, nor i have passed it in the base template from any view. – Dharmesh Singh May 30 '20 at 19:18
  • 1
    All models are represented with lower cases on html files. Like **user** actually it is **User** on your views. Likewise, your **UserCustom** model is represented with **usercustom** on html file. And the model which has **profile_picture** object is **UserCustom** , so you exactly need this. You have OneToOne relationship between User and UserCustom model. You can access UserCustom model from User, then you can access objects of UserCustom. Or, you can pass UserCustom to template from your view. You will no longer need User model. But in any case, you exactly need UserCustom model. – Mehmet Can May 30 '20 at 19:46