django-vote icon indicating copy to clipboard operation
django-vote copied to clipboard

Issue with template code that worked before updating Django 3->4 (possibly postgresql 13->14)

Open y2kbadbug opened this issue 3 years ago • 13 comments

This is the entire traceback provided by Django:

Environment:


Request Method: GET
Request URL: http://192.168.2.155:8000/quotes/

Django Version: 4.0.8
Python Version: 3.10.8
Installed Applications:
['django.contrib.admin',
 'django.contrib.admindocs',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.flatpages',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.sites',
 'django.contrib.sitemaps',
 'django.contrib.humanize',
 'django.contrib.postgres',
 'django.forms',
 'crispy_forms',
 'bootstrapform',
 'pinax.messages',
 'pinax.notifications',
 'notifications',
 'haystack',
 'ircdriven',
 'django_filters',
 'martor',
 'formtools',
 'debug_toolbar',
 'django_gravatar',
 'django_extensions',
 'django_countries',
 'allauth',
 'allauth.account',
 'allauth.socialaccount',
 'allauth.socialaccount.providers.github',
 'allauth.socialaccount.providers.google',
 'rest_framework',
 'rest_framework.authtoken',
 'drf_spectacular',
 'friendship',
 'captcha',
 'mptt',
 'widget_tweaks',
 'machina',
 'machina.apps.forum',
 'machina.apps.forum_conversation',
 'machina.apps.forum_conversation.forum_attachments',
 'machina.apps.forum_conversation.forum_polls',
 'machina.apps.forum_feeds',
 'machina.apps.forum_moderation',
 'machina.apps.forum_search',
 'machina.apps.forum_tracking',
 'machina.apps.forum_member',
 'machina.apps.forum_permission',
 'django_nyt.apps.DjangoNytConfig',
 'sekizai',
 'sorl.thumbnail',
 'wiki.apps.WikiConfig',
 'wiki.plugins.attachments.apps.AttachmentsConfig',
 'wiki.plugins.editsection.apps.EditSectionConfig',
 'wiki.plugins.globalhistory.apps.GlobalHistoryConfig',
 'wiki.plugins.help.apps.HelpConfig',
 'wiki.plugins.images.apps.ImagesConfig',
 'wiki.plugins.links.apps.LinksConfig',
 'wiki.plugins.macros.apps.MacrosConfig',
 'wiki.plugins.notifications.apps.NotificationsConfig',
 'vote']
Installed Middleware:
['debug_toolbar.middleware.DebugToolbarMiddleware',
 'django.middleware.cache.UpdateCacheMiddleware',
 'django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'django.contrib.sites.middleware.CurrentSiteMiddleware',
 'machina.apps.forum_permission.middleware.ForumPermissionMiddleware',
 'django.middleware.cache.FetchFromCacheMiddleware',
 'ircdriven.middleware.TimezoneMiddleware']


Template error:
In template /home/daniel/Repos/website/templates/ircdriven/quotes/main.html, error at line 50
   operator does not exist: character varying = numeric
LINE 1: ...content_type_id" = 93 AND "vote_vote"."object_id" = 15663665...
                                                             ^
HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.

   40 :                     <div class="card">
   41 :                         <div class="card-body elegant-color p-0">
   42 :                             <pre style="white-space: pre-wrap;" class="p-2 mb-0 white-text">
   43 : {{ quote.quote }}</pre>
   44 :                         </div>
   45 :                         <div class="card-footer m-0 p-1 px-2">
   46 :                             <div class="small text-muted d-inline">Submitted by <a class="black-text" href="{% url 'user_profile' quote.submitter.username %}">{{ quote.submitter.username }}</a></div>
   47 :                             <div class="float-right d-inline">
   48 :                                 <div class="badge badge-pill badge-dark d-inline">{{ quote.vote_score }}</div>
   49 :                                 {% if request.user.is_authenticated %}
   50 :                                  {% vote_exists quote request.user 0 as vote_up %} 
   51 :                                 {% vote_exists quote request.user 1 as vote_down %}
   52 :                                 <div class="form-inline d-inline">
   53 :                                     <form class="d-inline" action="{% url 'quotes_home' %}" method="post">
   54 :                                         {% csrf_token %}
   55 :                                         <input type="hidden" name="id" value="{{ quote.id }}" />
   56 :                                         <input type="hidden" name="vote" value="up" />
   57 :                                         <button class="btn btn-link p-0 m-0" {% if vote_up %}disabled="disabled"{% endif %} type="submit"><i class="fa-sharp fa-solid fa-arrow-alt-up fa-lg green-text"></i></button>
   58 :                                     </form>
   59 :                                     <form class="d-inline" action="{% url 'quotes_home' %}" method="post">
   60 :                                         {% csrf_token %}


Traceback (most recent call last):
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/db/backends/utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)

The above exception (operator does not exist: character varying = numeric
LINE 1: ...content_type_id" = 93 AND "vote_vote"."object_id" = 15663665...
                                                             ^
HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
) was the direct cause of the following exception:
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/daniel/Repos/website/ircdriven/views/quote.py", line 51, in quotes_page
    return render(request, 'ircdriven/quotes/main.html', context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/shortcuts.py", line 24, in render
    content = loader.render_to_string(template_name, context, request, using=using)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/loader.py", line 62, in render_to_string
    return template.render(context, request)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/backends/django.py", line 62, in render
    return self.template.render(context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 175, in render
    return self._render(context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/test/utils.py", line 111, in instrumented_test_render
    return self.nodelist.render(context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 1000, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 1000, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 958, in render_annotated
    return self.render(context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/loader_tags.py", line 157, in render
    return compiled_parent._render(context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/test/utils.py", line 111, in instrumented_test_render
    return self.nodelist.render(context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 1000, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 1000, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 958, in render_annotated
    return self.render(context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/classytags/core.py", line 151, in render
    return str(self.render_tag(context, **kwargs))
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/sekizai/templatetags/sekizai_tags.py", line 87, in render_tag
    rendered_contents = nodelist.render(context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 1000, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 1000, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 958, in render_annotated
    return self.render(context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/defaulttags.py", line 322, in render
    return nodelist.render(context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 1000, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 1000, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 958, in render_annotated
    return self.render(context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/loader_tags.py", line 63, in render
    result = block.nodelist.render(context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 1000, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 1000, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 958, in render_annotated
    return self.render(context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/defaulttags.py", line 238, in render
    nodelist.append(node.render_annotated(context))
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 958, in render_annotated
    return self.render(context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/defaulttags.py", line 322, in render
    return nodelist.render(context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 1000, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 1000, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/base.py", line 958, in render_annotated
    return self.render(context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/template/library.py", line 239, in render
    output = self.func(*resolved_args, **resolved_kwargs)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/vote/templatetags/vote.py", line 15, in vote_exists
    return model.votes.exists(user.pk, action=action)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/vote/utils.py", line 12, in inner
    return func(self, *args, **kwargs)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/vote/managers.py", line 145, in exists
    ).exists()
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/db/models/query.py", line 892, in exists
    return self.query.has_results(using=self.db)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/db/models/sql/query.py", line 589, in has_results
    return compiler.has_results()
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/db/models/sql/compiler.py", line 1329, in has_results
    return bool(self.execute_sql(SINGLE))
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/db/models/sql/compiler.py", line 1361, in execute_sql
    cursor.execute(sql, params)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/db/backends/utils.py", line 103, in execute
    return super().execute(sql, params)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/db/backends/utils.py", line 67, in execute
    return self._execute_with_wrappers(
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/db/backends/utils.py", line 84, in _execute
    with self.db.wrap_database_errors:
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/db/utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/home/daniel/.pyenv/versions/website/lib/python3.10/site-packages/django/db/backends/utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)

Exception Type: ProgrammingError at /quotes/
Exception Value: operator does not exist: character varying = numeric
LINE 1: ...content_type_id" = 93 AND "vote_vote"."object_id" = 15663665...
                                                             ^
HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.

The main piece throwing this is:

   50 :                                  {% vote_exists quote request.user 0 as vote_up %} 
   51 :                                 {% vote_exists quote request.user 1 as vote_down %}

y2kbadbug avatar Nov 03 '22 01:11 y2kbadbug

It seems the vote_vote.object filed in the database becomes a varchar type which should be an integer. Did you do any database migration recently? could you double-check the table schema in your database (something like \d vote_vote in the PostgreSQL command line)

shellfly avatar Nov 03 '22 02:11 shellfly

I did do some migrations recently

                                         Table "public.vote_vote"
     Column      |           Type           | Collation | Nullable |                Default                
-----------------+--------------------------+-----------+----------+---------------------------------------
 id              | bigint                   |           | not null | nextval('vote_vote_id_seq'::regclass)
 user_id         | character varying(36)    |           |          | 
 object_id       | character varying(36)    |           |          | 
 create_at       | timestamp with time zone |           | not null | 
 content_type_id | integer                  |           | not null | 
 action          | smallint                 |           | not null | 
Indexes:
    "vote_vote_pkey" PRIMARY KEY, btree (id)
    "vote_vote_content_type_id_3e7f4036" btree (content_type_id)
    "vote_vote_content_type_id_object_id_d4b2a059_idx" btree (content_type_id, object_id)
    "vote_vote_user_id_content_type_id__2491cf2e_uniq" UNIQUE CONSTRAINT, btree (user_id, content_type_id, object_id, action)
Check constraints:
    "vote_vote_action_check" CHECK (action >= 0)
Foreign-key constraints:
    "vote_vote_content_type_id_3e7f4036_fk_django_content_type_id" FOREIGN KEY (content_type_id) REFERENCES django_content_type(id) DEFERRABLE INITIALLY DEFERRED

y2kbadbug avatar Nov 08 '22 03:11 y2kbadbug

The object_id is a varchar because my database uses uuid for ids. This works before, it only broke on my dev server while trying to migrate to Django 4, and upgraded to Postgresql 14 from 13.

y2kbadbug avatar Nov 08 '22 03:11 y2kbadbug

@y2kbadbug If you use uuid for object_id, then where does this numeric ID come from ? "vote_vote"."object_id" = 15663665.. what does your quote table schema looks like now?

shellfly avatar Nov 09 '22 01:11 shellfly

It looks like

ircdriven=# \d ircdriven_quote;
                      Table "public.ircdriven_quote"
    Column     |           Type           | Collation | Nullable | Default 
---------------+--------------------------+-----------+----------+---------
 id            | uuid                     |           | not null | 
 quote         | text                     |           | not null | 
 timestamp     | timestamp with time zone |           | not null | 
 channel_id    | uuid                     |           |          | 
 submitter_id  | bigint                   |           | not null | 
 approved      | boolean                  |           | not null | 
 num_vote_down | integer                  |           | not null | 
 num_vote_up   | integer                  |           | not null | 
 vote_score    | integer                  |           | not null | 
Indexes:
    "ircdriven_quotes_pkey" PRIMARY KEY, btree (id)
    "ircdriven_q_id_bab217_idx" btree (id, "timestamp")
    "ircdriven_q_quote_4c9c71_idx" btree (quote)
    "ircdriven_quote_num_vote_down_b1d0397a" btree (num_vote_down)
    "ircdriven_quote_num_vote_up_b43b6601" btree (num_vote_up)
    "ircdriven_quote_timestamp_ea265334" btree ("timestamp")
    "ircdriven_quote_vote_score_e652383f" btree (vote_score)
    "ircdriven_quotes_channel_id_39530223" btree (channel_id)
    "ircdriven_quotes_submitter_id_d4507f71" btree (submitter_id)
Check constraints:
    "ircdriven_quote_num_vote_down_check" CHECK (num_vote_down >= 0)
    "ircdriven_quote_num_vote_up_check" CHECK (num_vote_up >= 0)
Foreign-key constraints:
    "ircdriven_quotes_channel_id_39530223_fk_ircdriven_channel_id" FOREIGN KEY (channel_id) REFERENCES ircdriven_channel(id) DEFERRABLE INITIALLY DEFERRED
    "ircdriven_quotes_submitter_id_d4507f71_fk_ircdriven_user_id" FOREIGN KEY (submitter_id) REFERENCES ircdriven_user(id) DEFERRABLE INITIALLY DEFERRED

EDIT:

I have no idea where it's getting that number from. I am reimporting my database since this appears to only be happening on my dev server.

y2kbadbug avatar Nov 10 '22 04:11 y2kbadbug

So it only seems to be appearing on my dev server so I will close this right now. Prod server cannot reproduce.

y2kbadbug avatar Nov 14 '22 03:11 y2kbadbug

So it appears to be an issue with Django 4.x. I finally updated my prod server from Django 3.2.x to 4.0.8, and now I am getting the same error.

y2kbadbug avatar Nov 23 '22 20:11 y2kbadbug

@shellfly I will continue to investigate and submit a PR if I can figure it out. If there is anything I can do for you, let me know :)

dshafer-godaddy avatar Dec 05 '22 20:12 dshafer-godaddy

@shellfly I will continue to investigate and submit a PR if I can figure it out. If there is anything I can do for you, let me know :)

This was me by the way. I didn't realize I was on my work account. I have not found a solution to this though. Not sure if you want me to close this?

y2kbadbug avatar Apr 02 '23 06:04 y2kbadbug

This is a quick fix that I did. This was required due to Postgresql:

# Generated by Django 4.1.7 on 2023-04-02 07:11

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('vote', '0005_alter_vote_id'),
    ]

    operations = [
        migrations.AlterField(
            model_name='vote',
            name='object_id',
            field=models.CharField(max_length=50),
        ),
        migrations.AlterField(
            model_name='vote',
            name='user_id',
            field=models.CharField(max_length=50),
        ),
    ]

I fixed it out by seeing this: https://github.com/django/django-contrib-comments/commit/7bcc661982930fb98c5a56ec71bd05a6ba86885a

y2kbadbug avatar Apr 02 '23 07:04 y2kbadbug

@y2kbadbug it seems a valid solution to change the field type to be compatible with the content object, I just checked the Django document which suggests the same solution. do you want to make a MR to for this?

https://docs.djangoproject.com/en/4.1/ref/contrib/contenttypes/

The “object_id” field doesn’t have to be the same type as the primary key fields on the related models, but their primary key values must be coercible to the same type as the “object_id” field by its get_db_prep_value() method.

For example, if you want to allow generic relations to models with either IntegerField or CharField primary key fields, you can use CharField for the “object_id” field on your model since integers can be coerced to strings by get_db_prep_value().

shellfly avatar Apr 03 '23 01:04 shellfly

I will submit one tomorrow!  So far everything works fine from what I tested Get Outlook for Android

y2kbadbug avatar Apr 03 '23 01:04 y2kbadbug

I created a PR #87 to fix this. Better late than never, right?

y2kbadbug avatar Jun 20 '24 16:06 y2kbadbug