0

Django 3.0.8

The database is newly created. No migrations so far.

settings.py

INSTALLED_APPS = [
    'django.contrib.sites',  # DJANGO_APP. Necessary for the built in sitemap framework.
...
]

SITE_ID = 1 # For the sites framework.

urls.py

from feeds.feeds import RssFeed
urlpatterns += [
    path('rss/', RssFeed(), name="rss"),
...

feeds.py

from django.contrib.syndication.views import Feed
from general.utils import get_site_address

class RssFeed(Feed):
    title = "Pcask.ru: все о компьютерах, гаджетах и программировании."
    link = get_site_address()

utils.py

from django.contrib.sites.models import Site

def get_site():
    site = Site.objects.first().name
    return site


def get_protocol():
    if HTTPS:
        protocol = "https://"
    else:
        protocol = "http://"

    return protocol


def get_site_address():
    return "".format(get_protocol(), get_site())

Problem

First of all I have to migrate as I use sites framework (https://docs.djangoproject.com/en/3.0/ref/contrib/sites/#enabling-the-sites-framework).

$ python manage.py migrate
Traceback (most recent call last):
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 86, in _execute
    return self.cursor.execute(sql, params)
psycopg2.errors.UndefinedTable: relation "django_site" does not exist
LINE 1: ..."django_site"."domain", "django_site"."name" FROM "django_si...
                                                             ^


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "manage.py", line 21, in <module>
    main()
  File "manage.py", line 17, in main
    execute_from_command_line(sys.argv)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
    utility.execute()
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/core/management/__init__.py", line 395, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/core/management/base.py", line 328, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/core/management/base.py", line 366, in execute
    self.check()
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/core/management/base.py", line 392, in check
    all_issues = self._run_checks(
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/core/management/commands/migrate.py", line 64, in _run_checks
    issues.extend(super()._run_checks(**kwargs))
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/core/management/base.py", line 382, in _run_checks
    return checks.run_checks(**kwargs)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/core/checks/registry.py", line 72, in run_checks
    new_errors = check(app_configs=app_configs)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/core/checks/urls.py", line 13, in check_url_config
    return check_resolver(resolver)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/core/checks/urls.py", line 23, in check_resolver
    return check_method()
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/urls/resolvers.py", line 407, in check
    for pattern in self.url_patterns:
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/utils/functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/urls/resolvers.py", line 588, in url_patterns
    patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/utils/functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/urls/resolvers.py", line 581, in urlconf_module
    return import_module(self.urlconf_name)
  File "/usr/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 783, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/home/michael/PycharmProjects/pcask/pcask/pcask/urls.py", line 31, in <module>
    from feeds.feeds import RssFeed
  File "/home/michael/PycharmProjects/pcask/pcask/feeds/feeds.py", line 14, in <module>
    class RssFeed(Feed):
  File "/home/michael/PycharmProjects/pcask/pcask/feeds/feeds.py", line 16, in RssFeed
    link = get_site_address()
  File "/home/michael/PycharmProjects/pcask/pcask/general/utils.py", line 123, in get_site_address
    return "".format(get_protocol(), get_site())
  File "/home/michael/PycharmProjects/pcask/pcask/general/utils.py", line 109, in get_site
    site = Site.objects.first().name
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/db/models/query.py", line 664, in first
    for obj in (self if self.ordered else self.order_by('pk'))[:1]:
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/db/models/query.py", line 276, in __iter__
    self._fetch_all()
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/db/models/query.py", line 1261, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/db/models/query.py", line 57, in __iter__
    results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/cachalot/monkey_patch.py", line 36, in inner
    return original(compiler, *args, **kwargs)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/cachalot/monkey_patch.py", line 87, in inner
    return _get_result_or_execute_query(
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/cachalot/monkey_patch.py", line 59, in _get_result_or_execute_query
    result = execute_query_func()
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/cachalot/monkey_patch.py", line 75, in <lambda>
    execute_query_func = lambda: original(compiler, *args, **kwargs)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1152, in execute_sql
    cursor.execute(sql, params)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 100, in execute
    return super().execute(sql, params)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/cachalot/monkey_patch.py", line 128, in inner
    return original(cursor, sql, *args, **kwargs)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 68, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 86, in _execute
    return self.cursor.execute(sql, params)
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/db/utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/home/michael/PycharmProjects/pcask/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 86, in _execute
    return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: relation "django_site" does not exist
LINE 1: ..."django_site"."domain", "django_site"."name" FROM "django_si...

If I comment that urlpattern, the importing and using of Site, then migration is executed Ok.

Could you give me a hint how to cope with this problem?

Michael
  • 4,273
  • 3
  • 40
  • 69
  • Does the Feed class inherit from models? – Phteven Jul 27 '20 at 09:33
  • No. I edited the question to show how it is organized. It is a django feed framework. Loaded like this: from django.contrib.syndication.views import Feed – Michael Jul 27 '20 at 09:36
  • Could you try and make the this line link = get_site_address() a lambda something along the of this link = lambda: _: get_site_address() – Phteven Jul 27 '20 at 09:38
  • I did like this: link = lambda _: get_site_address() It doesn't help. – Michael Jul 27 '20 at 09:42
  • The issue you are experiencing is most likely due to the fact that your urls which get loaded at the start involve a query and the models at that point are not properly loaded yet. Your code would also fail on an empty db . you can try and hide the stuff in a method or make it a property on the Feed to delay execution. – Phteven Jul 27 '20 at 09:58
  • Can you update your traceback? The one above doesn't apply anymore if you applied the fixes from my answer. Locally, I can't reproduce this at all. Invoking `RssFeed()` just returns a view handler so doesn't invoke anything and the tb above clearly executes the method from RssFeed() declaration. –  Jul 27 '20 at 10:53
  • I did a lot of playing. Maybe it is not the right time for updating traceback as it may not reflect the situation again. By the way, I commented cachalot out. And it works. Hm. But cachalot is much lower in INSTALLED_APPS. Could you commen? – Michael Jul 27 '20 at 11:01
  • I can't, you should ask its authors. There's no reason to execute sites query if everything is shielded correctly as in my latest edit below, so whatever cachalot does, it conflicts with this. –  Jul 27 '20 at 11:07

1 Answers1

0

So, Final update:

What you're doing is invoking the function in the class definition:

class RssFeed(Feed):
    title = "Pcask.ru: все о компьютерах, гаджетах и программировании."
    link = get_site_address()  # <---- problem

Thing is that Feed.get_feed already has logic for the Sites framework. I agree, overriding the logic there is a bit cumbersome, but also look at:

    def _get_dynamic_attr(self, attname, obj, default=None):
        try:
            attr = getattr(self, attname)
        except AttributeError:
            return default
        if callable(attr):
            # Check co_argcount rather than try/excepting the function and
            # catching the TypeError, because something inside the function
            # may raise the TypeError. This technique is more accurate.
            try:
                code = attr.__code__
            except AttributeError:
                code = attr.__call__.__code__
            if code.co_argcount == 2:       # one argument is 'self'
                return attr(obj)
            else:
                return attr()
        return attr

This means you implement link as:

class RssFeed(Feed):
    title = "Pcask.ru: все о компьютерах, гаджетах и программировании."
    link = get_site_address  # No brackets

In addition to hiding the import inside get_site_address.

However, you should look more closely at Feed.get_feed() because you get an object and are expected to return a full link and not just a site address.

For Reference, this code works and is put in root url conf:

from django.contrib.syndication.views import Feed

HTTPS = False


def get_link(obj):
    from django.contrib.sites.models import Site

    main_site = Site.objects.order_by("id").first()
    assert main_site is not None, "Sites have been deleted!"

    try:
        path = getattr(obj, "get_absolute_url")()
    except AttributeError as e:
        raise AttributeError("Do not know how to generate url path") from e

    return f"{get_protocol()}://{main_site.domain}{path}"


def get_protocol():
    return "https" if HTTPS else "http"


class RssFeed(Feed):
    title = "Pcask.ru: все о компьютерах, гаджетах и программировании."
    link = get_link

# urls.py
urlpatterns = [
    path("rss/", RssFeed()),
]
  • I edited my question. It is a newly created database. And no migrations so far. – Michael Jul 27 '20 at 09:45
  • I tried. It doesn't help. And like this doesn't help: model_class = apps.get_model("sites.Site", require_ready=False) site = model_class.objects.first().name – Michael Jul 27 '20 at 10:05
  • The problem is localized not in get_site. It is in urls.py. When I comment lines out there, everything works. Like this: # from feeds.feeds import RssFeed urlpatterns += [ # path('rss/', RssFeed(), name="rss"), – Michael Jul 27 '20 at 10:11
  • Ugh, you're invoking the function at declaration time in RssFeed's class definition. This you should really avoid. –  Jul 27 '20 at 10:11
  • I can't catch your idea. I have rewritten like this: link = get_site_address() class RssFeed(Feed): link = link That is I just invoked the function outside the class. It didn't help. Then I wrote inside the class like this: link = "https://localhost:8000" It didn't help either. – Michael Jul 27 '20 at 10:18
  • Let me setup locally, it just might be that you can't do this in *root* urlconf, but it will work in app urlconfs as they are lazy loaded. I mean, the rest is in accordance with docs. –  Jul 27 '20 at 10:34