0

I have a Django project that has got an image field in the models.py. It works fine in the development environment but in the production environment, it leads to the page not found error when I save the object.

Here is my product model in models.py

class Product(models.Model):
    PRODUCT_CHOICES = (
        ('Whisky', (
                    ('BLENDED SCOTCH', 'BLENDED SCOTCH',),
                    ('BOURBON WHISKIES', 'BOURBON WHISKIES',),
                    ('IRISH WHISKIES', 'IRISH WHISKIES',),
                    ('SINGLE MALT', 'SINGLE MALT',),
                    ('TENESEE WHISKIES', 'TENESEE WHISKIES',),
                )
            ),
        ('vodka', 'vodka',),
        ('Wine', (
                    ('RED WINE', 'RED WINE',),
                    ('WHITE WINE', 'WHITE WINE',),
                    ('ROSE WINE', 'ROSE WINE',),
                )
            ),
        ('Champagne', 'Champagne',),
        ('Brandy', 'Brandy',),
        ('Cognac', 'Cognac',),
        ('Beer', (
                    ('CIDER', 'CIDER',),
                    ('LAGER', 'LAGER',),
                    ('MALT', 'MALT',),
                    ('DRAUGHT', 'DRAUGHT',),
                )
            ),
        ('Tequila', 'Tequila',),
        ('Rum', 'Rum',),
        ('Gin', 'Gin',),
        ('Liquer', 'Liquer',),
        ('Extras', 'Extras',),
    )
    product_type = models.CharField(max_length=255, choices=PRODUCT_CHOICES, default=None)
    picture = models.ImageField(upload_to='uploads', height_field=None, default=None, width_field=None, max_length=None)
    name = models.CharField(max_length=200, default=None)
    capacity = models.CharField(max_length=200)
    cash = models.DecimalField(max_digits=7, decimal_places=2)
    digital = models.BooleanField(default=False, null=True, blank=False)
    date_uploaded = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return self.name

    @property
    def imageURL(self):
        try:
            url = self.picture.url
        except:
            url = ''
        return url

I have also modified my settings.py correctly to serve media and static files while in production. And should i also consider absolute or relative path for upload to in picture = models.ImageField(upload_to='uploads', ? to be picture = models.ImageField(upload_to='home/uptowndrinks/public_html/uploads', because i tried but still got the 404 error

STATIC_URL = '/static/'
MEDIA_ROOT='/home/uptowndrinks/public_html/uploads'
MEDIA_URL = '/uploads/'
STATICFILES_DIRS=[BASE_DIR + "/static",]
STATIC_ROOT='/home/uptowndrinks/public_html/static'

My static and media files settings in settings.py

Kindly help, I have really tried but I need your assistance

miruni
  • 87
  • 11

1 Answers1

1

i guess, /home/uptowndrinks/public_html/ is the public folder used apparently to hold any web application (not only your current django project) that uptowndrinks user wants to make them publicly accessible, but when i see /home/uptowndrinks/public_html/uploads and /home/uptowndrinks/public_html/static i think you are using the whole /home/uptowndrinks/public_html/ folder as the root folder for your current django project and you are not anticipating some future scenarios, so what if you (or other developer) decided to upload an other web application for the same user (let say wordpress blog) that should coexist with your current django project ? then the only option is to create a sub folder under the root folder of your main project .. which can lead you to some ambiguous errors. i think you are doing things the bad way even it's technically possible but hard to maintain. the solution it to hold each web application in its own root folder, all of them under /home/uptowndrinks/public_html/.

it's a good practice to name the root folder of an application after its domain name when it's possible, let say uptowndrinks.com.

you may find this structure does more sens:

/home/uptowndrinks/public_html/
.. uptowndrinks.com
   .. app1
      .. locale
      .. migration
      .. static (*)
      .. templates
      .. templatetags
      .. [ other folder & files ]

   .. app2
      .. locale
      .. static (*)
      .. templates
      .. templatetags
      .. [ other folder & files ]

   .. uptowndrinks ( the main app )
      .. __init __.py
      .. settings.py
      .. urls.py
      .. wsgi.py


   .. public (this folder is used to serve "static" and "media" files with web server like "apache")
      .. assets ( rename your "static" folder to avoid confusion with default "django" app static folder name )
      .. uploads ( the same with assets, just avoid "media" as folder name )

   .. locale
   .. static ( the global project level static folder )
   .. templates

   .. [ other folder & files ]

.. blog.uptowndrinks.com
   .. 
.. otherapp.com

as you may know, django adopt the Divisional structure approach (versus Functional structure), meaning you are encouraged to break down your django project into loosely coupled apps (logically independent as possible) so each app can has its own assets among others the static folder, but it happens that some assets could be app-independent (e.g: static css and js like bootstrap lib that should be loaded for each page) and shared by many apps then the global /static folder under the root folder of your project comes handy.

That being said and before going right to your issue, i would recommend you first this good thread (Differences between STATICFILES_DIR, STATIC_ROOT and MEDIA_ROOT).

in settings.py

[..]

# make sure "BASE_DIR" points to "root folder" of your project
# in this case it should be "/home/uptowndrinks/public_html/uptowndrinks.com"
#
# add os.path.dirname() as needed to go up to "root folder" of your project

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

[..]



# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/

# i suggest you one main "public" folder to collect all "static" and "media" files 
STATIC_URL = '/public/assets/'
MEDIA_URL = '/public/uploads/'

# Absolute paths to the directory where "static" and "media" files will be collected.
STATIC_ROOT = os.path.join(BASE_DIR, 'public/static')
MEDIA_ROOT = os.path.join(BASE_DIR, 'public/media')

# the two settings below are for "DEVELOPMENT" environment only.
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder'
)

you may want to serve static files during development, then in urls.py add:

[..]

# the settings below are for "DEVELOPMENT" environment only.

# DEBUG = True
if settings.DEBUG:

    from django.conf.urls.static import static

    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

now collect static files with this command

$ python manage.py collectstatic

and you'll see /public/assets folder is created automatically and all static files are collected from all apps and installed extensions.

Once you make your first upload you'll see /public/uploads folder automatically created.

and finally in your vhost conf, you should have something similar to (for e.g purposes, i assume you are serving your django project using apache and mod_wsgi)

<VirtualHost *:80>

    ServerName uptowndrinks.com

    DocumentRoot "/home/uptowndrinks/public_html/uptowndrinks.com"

    [..]

    WSGIScriptAlias / "/home/uptowndrinks/public_html/uptowndrinks.com/uptowndrinks/wsgi.py"
    
    <Directory "/home/uptowndrinks/public_html/uptowndrinks.com/uptowndrinks">
        <Files wsgi.windows.py>
            Require all granted
        </Files>
    </Directory>

    # serving public assets files
    Alias /public/assets "/home/uptowndrinks/public_html/uptowndrinks.com/public/assets"
    <Directory "/home/uptowndrinks/public_html/uptowndrinks.com/public/assets">
        Require all granted
    </Directory>

    # serving public uplods files
    Alias /public/uploads  "/home/uptowndrinks/public_html/uptowndrinks.com/public/uploads"
    <Directory "/home/uptowndrinks/public_html/uptowndrinks.com/public/uploads">
        Require all granted
    </Directory>

    [..]

</VirtualHost>

of course, you then adapt it to your needs, you may using nginx as web server with let's Encrypt.

cizario
  • 3,995
  • 3
  • 13
  • 27
  • still incooperating your answer @cizario, i ran into the error again App 24678 output: [ pid=24678, time=2020-07-02 11:55:18,540 ]: Not Found: /admin/store/product/add/ when i try to add product – miruni Jul 02 '20 at 08:57