Lextree Simply the best software for managing legal entities and documents.
The Berkman Letter Practical analysis and commentary for business, law, and more.

Django problem: list doesn't show up

I have to do this project of classified ads for Coursera. Essentially every user can post, update and delete advertisements. The problem is that even if the objects are correctly stored (I checked tables and objects via admin and manually with the command line), the ad list doesn't show up and it tells "There are no ads in the database." even though there are ads. I'm looking everywhere but I cannot find the error. I'm using django 3.2.5, here's the code:

- ad_list.html, located in mysite/ads/templates/ads ('base_menu.html' is for bootstrap):

{% extends "base_menu.html" %}
{% block content %}
{% if ad_list %}
      {% for ad in ad_list %}
            <a href="{% url 'ads:ad_detail' ad.id %}">{{ ad.title }}</a>
            {% if ad.owner == user %}
            (<a href="{% url 'ads:ad_update' ad.id %}">Edit</a> |
            <a href="{% url 'ads:ad_delete' ad.id %}">Delete</a>)
       {% endfor %}
{% else %}
  <p>There are no ads in the database.</p>
{% endif %}
<a href="{% url 'ads:ad_create' %}">Add an Ad</a> |
{% if user.is_authenticated %}
<a href="{% url 'logout' %}?next={% url 'ads:all' %}">Logout</a>
{% else %}
<a href="{% url 'login' %}?next={% url 'ads:all' %}">Login</a>
{% endif %}
{% endblock %}

- main.html, where the app should show the list, located in mysite/home/templates/home:

{% extends "base_menu.html" %}
{% block content %}

      <h1>Welcome to {{ settings.APP_NAME }}</h1>
        Hello World.
{% endblock content %}

- urls.py:

from django.urls import path, reverse_lazy
from . import views


urlpatterns = [
    path('', views.AdListView.as_view(), name='all'),
    path('ad/<int:pk>', views.AdDetailView.as_view(), name='ad_detail'),
        views.AdCreateView.as_view(success_url=reverse_lazy('ads:all')), name='ad_create'),
        views.AdUpdateView.as_view(success_url=reverse_lazy('ads:all')), name='ad_update'),
        views.AdDeleteView.as_view(success_url=reverse_lazy('ads:all')), name='ad_delete'),

- owner.py, created to subclass Generic Views and restrict them to owners:

from django.views.generic import CreateView, UpdateView, DeleteView, DetailView
from django.views.generic.list import ListView

from django.contrib.auth.mixins import LoginRequiredMixin

class OwnerListView(ListView):
    Sub-class the ListView to pass the request to the form.

class OwnerDetailView(DetailView):
    Sub-class the DetailView to pass the request to the form.

class OwnerCreateView(LoginRequiredMixin, CreateView):
    Sub-class of the CreateView to automatically pass the Request to the Form
    and add the owner to the saved object.

    # Saves the form instance, sets the current object for the view, and redirects to get_success_url().
    def form_valid(self, form):
        print('form_valid called')
        object = form.save(commit=False)
        object.owner = self.request.user
        return super(OwnerCreateView, self).form_valid(form)

class OwnerUpdateView(LoginRequiredMixin, UpdateView):
    Sub-class the UpdateView to pass the request to the form and limit the
    queryset to the requesting user.

    def get_queryset(self):
        print('update get_queryset called')
        """ Limit a User to only modifying their own data. """
        qs = super(OwnerUpdateView, self).get_queryset()
        return qs.filter(owner=self.request.user)

class OwnerDeleteView(LoginRequiredMixin, DeleteView):
    Sub-class the DeleteView to restrict a User from deleting other
    user's data.

    def get_queryset(self):
        print('delete get_queryset called')
        qs = super(OwnerDeleteView, self).get_queryset()
        return qs.filter(owner=self.request.user)

- views.py:

from ads.models import Ad
from ads.owner import OwnerListView, OwnerDetailView, OwnerCreateView, OwnerUpdateView, OwnerDeleteView

class AdListView(OwnerListView):
    model = Ad

class AdDetailView(OwnerDetailView):
    model = Ad

class AdCreateView(OwnerCreateView):
    model = Ad
    fields = ['title', 'text', 'price']

class AdUpdateView(OwnerUpdateView):
    model = Ad
    fields = ['title', 'text', 'price']

class AdDeleteView(OwnerDeleteView):
    model = Ad

- models.py:

from django.db import models
from django.core.validators import MinLengthValidator
from django.conf import settings

class Ad(models.Model) :
    title = models.CharField(
            validators=[MinLengthValidator(2, "Title must be greater than 2 characters")]
    price = models.DecimalField(max_digits=7, decimal_places=2, null=True)
    text = models.TextField()
    owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    # Shows up in the admin list
    def __str__(self):
        return self.title

What I've tried so far:

  • Changed 'ad_list' into 'ads_list';
  • Added 'context_object_name' in the template ad_list.html;
  • Modified the entire structure, using a simple view-function.
  • Deleted the db, and migrate again;
  • Get rid of owner.py and directly use a ListView in views.py;
  • Copy the template in ad_list.html into main.html. Doing this the only thing I've gained is the message "There are no ads in the database." which is supposed to be shown when a list doesn't exist. ...and the result is always the same.
If you need something else let me know. The code was originally running on pythonanywhere.com; I downloaded it on my pc but nothing changed. Thanks in advance!

This is also settings.py, maybe it can be useful:

import os

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

# Used for a default title
APP_NAME = 'Ads'   # Add

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'g$iqqu&*mw4_sg3(#ld0sqaalxebel&168^yj%i&sgrw(fmn@w'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True


# Application definition


    # Extensions - installed with pip3 / requirements.txt

    # My apps

# When we get to crispy forms :)
CRISPY_TEMPLATE_PACK = 'bootstrap3'  # Add

# When we get to tagging

    'social_django.middleware.SocialAuthExceptionMiddleware',   # Add

ROOT_URLCONF = 'mysite.urls'

        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'home.context_processors.settings',      # Add
                'social_django.context_processors.backends',  # Add
                'social_django.context_processors.login_redirect', # Add

WSGI_APPLICATION = 'mysite.wsgi.application'

# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases

#    'default': {
#        'ENGINE': 'django.db.backends.sqlite3',
#        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
#    }
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'misterObsidian$default',
        'USER': 'misterObsidian',
        'PASSWORD': 'OBS77743.jG',
        'HOST': 'misterObsidian.mysql.pythonanywhere-services.com',
         'OPTIONS': {
            'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",

# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators

        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',

# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/



USE_I18N = True

USE_L10N = True

USE_TZ = True

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

STATIC_URL = '/static/'

# Add the settings below


# Configure the social login
    from . import github_settings
    print('When you want to use social login, please see dj4e-samples/github_settings-dist.py')

# https://python-social-auth.readthedocs.io/en/latest/configuration/django.html#authentication-backends
# https://simpleisbetterthancomplex.com/tutorial/2016/10/24/how-to-add-social-login-to-django.html
    # 'social_core.backends.twitter.TwitterOAuth',
    # 'social_core.backends.facebook.FacebookOAuth2',



# Don't set default LOGIN_URL - let django.contrib.auth set it when it is loaded
# LOGIN_URL = '/accounts/login'

# Needed for 3.2 and later
# https://stackoverflow.com/questions/67783120/warning-auto-created-primary-key-used-when-not-defining-a-primary-key-type-by
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'