0

So I'm using a $5 digital ocean droplet using ubuntu and nginix to host a django website, I followed along this this tutorial and this guide. So a part of the guide said to run gunicorn --bind 0.0.0.0:8000 myproject.wsgi from the virtual env, it worked and as a test I created a highlights object to see if it would show, it did and this is what it looked like:

EDIT 3: Service file

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=apple
Group=www-data
WorkingDirectory=/home/apple/sanskar_handicrafts
ExecStart=/home/apple/sanskar_handicrafts/env/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          sanskar_handicrafts.wsgi:application

[Install]
WantedBy=multi-user.target

enter image description here

After which I added a gunicorn socket and completed the article till the point where it told me to run sudo ufw allow 'Nginx Full', however after I ran it, first of all, the css for the admin page was gone but the bigger concern was that after I added a few extra objects from the admin panel the changes didn't seem to be noticed by my views.py as when I displayed the contents of Highlights.objects.all() it only showed the one from above. But the admin page does show that the objects had been successfully added. Also the github repo's media folder didn't show any of the new images in them including the one uploaded from gunicorn --bind 0.0.0.0:8000 myproject.wsgi they only had the images I uploaded while in local development

enter image description here

However when I ls into the media folder from my virtual env running nginix it had all the media files from the images I uploaded while in local as well as all the new ones.

enter image description here

I have 2 models and this problem seems to prevail for both of them, I've tried migrations, restarting the ngnix server, and pulling and pushing to github, none have worked so far. Also the new images do seem to exist in the required url

enter image description here

Here's my models.py:

from django.db import models

class Highlights(models.Model):
    img = models.ImageField(upload_to='highlights/')

class Gallery(models.Model):
    img = models.ImageField()

and here's my views.py:

from django.shortcuts import render,get_object_or_404
from django.core.mail import send_mail
from .models import Gallery,Highlights


h_images = Highlights.objects.all()
g_images = Gallery.objects.all()

cnt = 1
rows = []
row = []
# Dividing the images into rows of 3 images per row as the maximum and creating a list of those rows
for image in g_images:
    if cnt < 3:
        row.append(image)
    else:
        row.append(image)
        cnt = 0
        rows.append(row)
        row = []
    cnt += 1

if row:
    rows.append(row)

# Seperating the rows into multiple pages to insure faster loading and better optimization
max_rows_per_page = 1
home_page = rows[:max_rows_per_page]
divided_rows_list = []
first = max_rows_per_page
last = max_rows_per_page + max_rows_per_page
curr_page = 1
for i in range(max_rows_per_page, len(rows), max_rows_per_page):
    divided_rows_list.append(rows[first:last])
    first = last
    last += max_rows_per_page


def home(request):
    return render(request, 'index.html',{'images':h_images})

def gallery(request):
    return render(request, 'gallery.html', {'rows':home_page,'nxt':1,'prev':len(divided_rows_list)})

    # return render(request,'gallery.html',{'rows':rows})

def nxt_pg(request,num):
    if num > len(divided_rows_list) or num == 0:
        return gallery(request)
    elif num < 0:
        num = len(divided_rows_list)
    return render(request, 'gallery.html', {'rows': divided_rows_list[num - 1], 'nxt': num + 1, 'prev': num - 1})

EDIT:

So Ankit told me the problem was because I hadn't run collect static but I had done it so, this is what the static part of my settings.py looks like:

STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'static'),
]
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

this is what I get when I run sudo nano /etc/nginx/sites-available/myproject

EDITED:

server {
    listen 80;
    server_name 139.59.20.1;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        alias /home/apple/sanskar_handicrafts/staticfiles;
    }

    location /media/ {
        root /home/apple/sanskar_handicrafts;
    }
    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;
    }
}

Also I do have a static_root folder and this is what happens when I try to use collectstatic now:

enter image description here

So I don't think it's a problem with collectstatic.

  • @AnkitTiwari Doing that made it so that even my website's css and javascript were removed also it didn't solve the problem either – Gamingapple Jan 23 '22 at 10:37
  • You named your static files directory as `staticfiles` but in the nginx config it is still used as `static`. Replace `root /home/apple/sanskar_handicrafts;` with `alias /home/apple/sanskar_handicrafts/staticfiles;` restart nginx server, and the static files issue should be gone. (The `root` directive [appends](https://stackoverflow.com/a/10647080/5451046) the location part as well.) – Dauros Jan 23 '22 at 12:27
  • Could you include the whole nginx config? Half of that is missing. – Dauros Jan 23 '22 at 12:28
  • Sorry man didn't work, the Highlights.objects.all() still says ]> eventhough there are like 2 others in the admin page – Gamingapple Jan 23 '22 at 12:31
  • Your question contains multiple issues, the nginx configuration was the first one, my suggestion should solve the static files issue. I'm looking into the query problem. – Dauros Jan 23 '22 at 12:36
  • @Dauros Hey I've added the rest of the config file – Gamingapple Jan 23 '22 at 12:37
  • @Dauros Yeah there was another guy who thought that it was a static problem I was justing showing him why it wasn't, strangely enough he has deleted all his comments and his answer as well lol – Gamingapple Jan 23 '22 at 12:39
  • Could you include the gunicorn systemd service file as well? I'm a little bit confused, because you said you used gunicorn bind to port 8000, but in your nginx config you used `/run/gunicorn.sock` socket file method, not a port. Aren't you having by chance two gunicorn instances, one at port 8000, and an other one at the socket server and you restarted only one of them? Or did you stopped the gunicorn on port 8000 and after you used only the socket-file one with nginx frontend? – Dauros Jan 23 '22 at 12:47
  • Yeah you can look at the article i linked where I bound it to 8000 to see if it woked then later removed it and used `sudo ufw delete allow 8000 sudo ufw allow 'Nginx Full'`, I've added the gunicorn.service file – Gamingapple Jan 23 '22 at 12:53
  • Thanks, it seems fine. Let's look into the query problem. When we import a Python file, the interpreter executes its contents. So when you import the `views.py` during gunicorn startup, it executes the `Highlights.objects.all()` etc. parts right away, saves the result to the `h_images` variable and moves to the next line. When you open the website main page that calls the `home` view function, it will use the `h_images` variable that was executed previously instead of creating a new query. – Dauros Jan 23 '22 at 13:28
  • So the fix is easy: just move everything inside a view function, or a separate function which is called by a view function. Don't put anything dynamic into the global scope, because it will be executed only once when you start the app-server. – Dauros Jan 23 '22 at 13:29
  • So I put all the global code except imports into the home function to test it out but unfortunately it still only shows the one image I pushed back when I was using `gunicorn --bind 0.0.0.0:8000 myproject.wsgi` and all the other ones aren't even mentioned... – Gamingapple Jan 23 '22 at 13:45
  • Have you restarted gunicorn? And do you still see all the images in the admin interface using the same gunicorn/nginx setup? – Dauros Jan 23 '22 at 13:58
  • @Dauros yes i did push the changes, pulled again just in case and restarted using `sudo systemctl restart nginx.service` I'm not sure what you mean by "And do you still see all the images in the admin interface using the same gunicorn/nginx setup? " but i do see the objects in the admin page listed as object 1, 2 etc – Gamingapple Jan 23 '22 at 14:01
  • When you change the Python code, you have to restart the gunicorn app server, not the nginx webserver, which is just a proxy above gunicorn and for the static files. Could you restart the gunicorn service as well? – Dauros Jan 23 '22 at 14:06
  • @Dauros how do you do that? – Gamingapple Jan 23 '22 at 14:08
  • If you created a `/etc/systemd/system/gunicorn.service` systemd unit file, the restarting command is: `sudo systemctl restart gunicorn.service` similar to the nginx one. You have to restart gunicorn service every time you push new code to the droplet. On your local dev environment, you start the Django runserver in debug mode, that restarts itself automatically on code change. But in production environment you have to restart manually. – Dauros Jan 23 '22 at 14:10
  • @Dauros Again MASSIVE THANK YOU LIKE GENUINELY you've saved me from weeks of torture for the second time now, if you don't mind I'd really love to connect with you on social media! – Gamingapple Jan 23 '22 at 14:26
  • You're welcome. The DO tutorial you used mentioned this very important detail unfortunately only in the "Further Troubleshooting" section. It's easy to miss. I did it a few times as well, after that I wrote a simple Fabric-based deploy script, that handled the service restarting automatically after the code push. I honestly don't have social media accounts, I had one many years ago, before FB, but it was a huge time waste, and bad for my mental health, so I skipped the FB/Twitter-era. But you can ping me here, I try to help if I have time. – Dauros Jan 23 '22 at 14:47
  • @Dauros Ah alright!! just thought I'd get to know you more since you seem nice and cool, and you don't see much of that in stackoverflow lol but I'll try not to bother you too much xD – Gamingapple Jan 23 '22 at 15:16
  • Just for the record, I had some time to post a summary of my relevant comments as an answer, like you asked last time. – Dauros Jan 24 '22 at 21:19

1 Answers1

1

First the static files issue: you named the static files folder as staticfiles, but the URL remained static so the nginx config needs adjustment:

location /static/ {
    alias /home/apple/sanskar_handicrafts/staticfiles;
}

The root directive appends the location part, the alias does not. Restart the nginx to apply new config.

Let's look into the query problem. When we import a Python file, the interpreter executes its contents. So when you import the views.py during gunicorn startup, it executes the Highlights.objects.all() etc. parts right away, saves the result to the h_images variable and moves to the next line.

When you open the website main page that calls the home view function, it will use the h_images variable that was executed previously instead of creating a new query. So it won't show the newly added elements.

The fix is easy: just move everything inside a view function, or a separate function which is called by a view function. Don't put anything dynamic into the global scope, because it will be executed only once when you start or restart the app-server.

After that and also after every code/settings.py/etc change don't forget to restart the gunicorn app-server by calling:

sudo systemctl restart gunicorn.service

On your local dev environment, you start the Django bultin runserver in debug mode, that restarts itself automatically on code change. But in production environment you have to restart the app server manually.

Dauros
  • 9,294
  • 2
  • 20
  • 28