Django file upload path error

I am trying to create file_upload_path but for some reason it is not working, i am getting the error:

I want users to upload images to that file path which i have in models.py

from django.db import models
# import abstract user
from django.contrib.auth.models import AbstractUser

# when using file upload path, the error appears when editing profile
def file_upload_path(instance, filename):
    return f'user-{instance.user.id}/images/{filename}'

# DEFINE OUR CUSTOM USER
class User(AbstractUser):
    class Role(models.TextChoices):
        ADMIN = 'ADMIN', 'Admin'
        OWNER = 'OWNER', 'Owner'
        EMPLOYEE = 'EMPLOYEE', 'Employee'
        MODERATOR = 'MODERATOR', 'Moderator'
        CUSTOMER = 'CUSTOMER', 'Customer'
    
    email = models.EmailField(unique=True, max_length=50)
    username = models.CharField(unique=True, max_length=50)
    role = models.CharField(max_length=20, choices=Role.choices, null=True, blank=True)
    phone_number = models.CharField(max_length=20, null=True, blank=True)
    image = models.ImageField(upload_to=file_upload_path, null=True, blank=True, default='default-images/profile.png')

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

    agree_to_terms = models.BooleanField('I agree to TOS', default=False, blank=False, null=False)

    def __str__(self):
        return self.email
    
    # to show full name
    def full_name(self):
        return f'{self.first_name} {self.last_name}'
    
    # to check the role
    def get_role(self):
        if self.role == User.Role.ADMIN:
            user_role = 'Admin'
        elif self.role == User.Role.OWNER:
            user_role = 'Owner'
        elif self.role == User.Role.EMPLOYEE:
            user_role = 'Employee'
        return user_role

# when user is created, create a profile for that user via signals
class UserProfile(models.Model):
    # relation to User
    user = models.OneToOneField(User, on_delete=models.CASCADE)

    def __str__(self):
        return self.user.email


In the template i have this:

 <form action="" method='POST' enctype="multipart/form-data">
            {% csrf_token %}
            {{form|crispy}}
            <button type='submit' class="default-submit-button w-inline-block">Update profile</button>
          </form>

Url is

path('profile/', views.profile, name='profile'),

Now, i can add the image via template, but i get the error in the admin, and only when trying to change the image.

I hope someone can clarify a bit, am i doing it correct…

Thank you as always!

Please don’t post images of text or browser pages for errors. Copy/paste the errors and traceback from the console screen where you’re running runserver into the body of your post (surrounded by lines of ```, just like you do with code.)

Sorry, okay, here it is.

AttributeError at /admin/accounts/user/1/change/
'User' object has no attribute 'user'
Request Method:	POST
Request URL:	http://127.0.0.1:8000/admin/accounts/user/1/change/
Django Version:	4.2.2
Exception Type:	AttributeError
Exception Value:	
'User' object has no attribute 'user'
Exception Location:	D:\Sass\F3\accounts\models.py, line 7, in file_upload_path
Raised during:	django.contrib.admin.options.change_view
Python Executable:	D:\Sass\F3\venv\Scripts\python.exe
Python Version:	3.11.1
Python Path:	
['D:\\Sass\\F3',
 'C:\\Users\\Dell\\AppData\\Local\\Programs\\Python\\Python311\\python311.zip',
 'C:\\Users\\Dell\\AppData\\Local\\Programs\\Python\\Python311\\DLLs',
 'C:\\Users\\Dell\\AppData\\Local\\Programs\\Python\\Python311\\Lib',
 'C:\\Users\\Dell\\AppData\\Local\\Programs\\Python\\Python311',
 'D:\\Sass\\F3\\venv',
 'D:\\Sass\\F3\\venv\\Lib\\site-packages']
Server time:	Sun, 25 Jun 2023 09:58:19 +0000
Traceback Switch to copy-and-paste view
D:\Sass\F3\venv\Lib\site-packages\django\core\handlers\exception.py, line 55, in inner
                response = get_response(request)
                               ^^^^^^^^^^^^^^^^^^^^^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\core\handlers\base.py, line 197, in _get_response
                response = wrapped_callback(request, *callback_args, **callback_kwargs)
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\contrib\admin\options.py, line 688, in wrapper
                return self.admin_site.admin_view(view)(*args, **kwargs)
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\utils\decorators.py, line 134, in _wrapper_view
                    response = view_func(request, *args, **kwargs)
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\views\decorators\cache.py, line 62, in _wrapper_view_func
        response = view_func(request, *args, **kwargs)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\contrib\admin\sites.py, line 242, in inner
            return view(request, *args, **kwargs)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\contrib\admin\options.py, line 1889, in change_view
        return self.changeform_view(request, object_id, form_url, extra_context)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\utils\decorators.py, line 46, in _wrapper
        return bound_method(*args, **kwargs)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\utils\decorators.py, line 134, in _wrapper_view
                    response = view_func(request, *args, **kwargs)
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\contrib\admin\options.py, line 1747, in changeform_view
            return self._changeform_view(request, object_id, form_url, extra_context)
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\contrib\admin\options.py, line 1798, in _changeform_view
                self.save_model(request, new_object, form, not add)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\contrib\admin\options.py, line 1227, in save_model
        obj.save()
              ^^^^^^^^^^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\contrib\auth\base_user.py, line 76, in save
        super().save(*args, **kwargs)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\db\models\base.py, line 814, in save
        self.save_base(
             ^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\db\models\base.py, line 877, in save_base
            updated = self._save_table(
                            …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\db\models\base.py, line 981, in _save_table
            values = [
                           …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\db\models\base.py, line 985, in <listcomp>
                    (getattr(self, f.attname) if raw else f.pre_save(self, False)),
                                                               ^^^^^^^^^^^^^^^^^^^^^^^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\db\models\fields\files.py, line 317, in pre_save
            file.save(file.name, file.file, save=False)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\db\models\fields\files.py, line 92, in save
        name = self.field.generate_filename(self.instance, name)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ …
Local vars
D:\Sass\F3\venv\Lib\site-packages\django\db\models\fields\files.py, line 332, in generate_filename
            filename = self.upload_to(instance, filename)
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ …
Local vars
D:\Sass\F3\accounts\models.py, line 7, in file_upload_path
from django.db import models
# import abstract user
from django.contrib.auth.models import AbstractUser
# when using file upload path, the error appears when editing profile
def file_upload_path(instance, filename):
    return f'user-{instance.user.id}/images/{filename}'
                      ^^^^^^^^^^^^^ …
# DEFINE OUR CUSTOM USER
class User(AbstractUser):
    class Role(models.TextChoices):
        ADMIN = 'ADMIN', 'Admin'
        OWNER = 'OWNER', 'Owner'
Local vars

This is just profile edit page, where i want users to be able to edit their profile. This error appears only when new image is being uploaded…

instance here represents the class User(AbstractUser): It has not any “user” field try to use

def file_upload_path(instance, filename):
    return f'user-{instance.id}/images/{filename}'

instead of instance.user.id

hope that helps.

Thank you very much :slight_smile:

I hope i can continue on this thread and get some advice. I have followed the advice and edited out the “user” part before .id.

So i have defined a dynamic file upload path:

def course_file_upload_path(instance, filename):
    return f'user-{instance.id}/courses/files/{filename}'

Course model has an image field with upload_to set to that path. Also, PDF model has the FileField with the same upload path.

So, in the admin, for Course image i do see “user-1…” but for the PDF model i don’t, there i see “user-None/courses/files/pdfdemo_7pGZyM6.pdf”

This is the models.py

from django.db import models
from django.conf import settings
from django.urls import reverse

def course_file_upload_path(instance, filename):
    return f'user-{instance.id}/courses/files/{filename}'

class Course(models.Model):
    title = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=110, unique=True)
    image = models.ImageField(upload_to=course_file_upload_path, default='default-images/post.png')
    description = models.TextField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True) 
    updated_at = models.DateTimeField(auto_now=True)

    # relations
    # to owner of the course = logged in user who is creating the course
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

    def __str__(self):
        return self.title
    
    def get_absolute_url(self):
        return reverse('courses:view_course', args=[str(self.slug)])
    
    def clean(self):
        self.title = self.title.capitalize()
        self.slug = self.slug.lower()


class Module(models.Model):
    title = models.CharField(max_length=50)

    # relation to Course
    course = models.ForeignKey(Course, on_delete=models.CASCADE)

    def __str__(self):
        return self.title

class Lesson(models.Model):
    title = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=110, unique=True)
    content = models.TextField(null=True, blank=True)
    video = models.FileField(upload_to=course_file_upload_path, null=True, blank=True)
    created_at = models.DateField(auto_now_add=True)
    updated_at = models.DateField(auto_now=True)

    # relations
    course = models.ForeignKey(Course, on_delete=models.CASCADE)
    module = models.ForeignKey(Module, on_delete=models.CASCADE)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

    def __str__(self):
        return self.title
    
    def get_absolute_url(self):
        return reverse('course:view_lesson', args=[str(self.course.slug), str(self.slug)])
    
    def clean(self):
        self.title = self.title.capitalize()
        self.slug = self.slug.lower()


class Pdf(models.Model):
    title = models.CharField(max_length=100)
    file = models.FileField(upload_to=course_file_upload_path)

    # relation to Lesson
    lesson = models.ForeignKey(Lesson, on_delete=models.CASCADE)

    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

    def __str__(self):
        return self.title


Am i missing something?

Thank you!

Is this being done as part of the same admin page, or are you doing this on the admin page for your Pdf model?

Thank you, sorry i don’t understand the question.

You are uploading files in the Admin, correct?

If I’m understanding you correctly, these uploads are working for the image field in the Course model, but the upload is not working for the file field in the Pdf model.

What is the admin page where you are uploading these files that are being placed in the Pdf model?

Oh, okay. I just wanted to create a few objects before i start with crud views for models, so i am using Django admin, yes.

Ok, so is it the Admin page for the Pdf model where you are uploading this, or are you uploading these files on a different page?

Yes, i am in the admin, for that Pdf Model.

As I can see the method of uploading file def course_file_upload_path
It can be as the following :

def course_file_upload_path(instance, filename):
    return f'user-{instance.user.id}/courses/files/{filename}'

Because the instance here represents the class Course() that has already field user and the class Pdf() that also has field user
So you can use instance.user.id