How do I fix 'Message' instance needs to have a primary key value before this relationship can be used

When I try to add a Message from the admin pages I get the 'Message' instance needs to have a primary key value before this relationship can be used.

Here is my models.py Message class...

class Message(models.Model):
    """ Message as sent through a Submission. """
    
    default_id = time.time()
    #adding primary key to satisfy error
    id = models.BigAutoField(primary_key=True, auto_created=True)
    title = models.CharField(max_length=200, verbose_name=_('title'))
    slug = models.SlugField(verbose_name=_('slug'))

    newsletter = models.ForeignKey(
        Newsletter, verbose_name=_('newsletter'), on_delete=models.CASCADE, default=get_default_newsletter
    )

    date_create = models.DateTimeField(
        verbose_name=_('created'), auto_now_add=True, editable=False
    )
    date_modify = models.DateTimeField(
        verbose_name=_('modified'), auto_now=True, editable=False
    )

    class Meta:
        verbose_name = _('message')
        verbose_name_plural = _('messages')
        unique_together = ('slug', 'newsletter')
        #order_with_respect_to = 'newsletter'

    def __str__(self):
        try:
            return _("%(title)s in %(newsletter)s") % {
                'title': self.title,
                'newsletter': self.newsletter
            }
        except Newsletter.DoesNotExist:
            logger.warning('No newsletter has been set for this message yet.')
            return self.title

    def get_next_article_sortorder(self):
        """ Get next available sortorder for Article. """

        next_order = self.articles.aggregate(
            models.Max('sortorder')
        )['sortorder__max']

        if next_order:
            return next_order + 10
        else:
            return 10

    @cached_property
    def _templates(self):
        """Return a (subject_template, text_template, html_template) tuple."""
        return self.newsletter.get_templates('message')

    @property
    def subject_template(self):
        return self._templates[0]

    @property
    def text_template(self):
        return self._templates[1]

    @property
    def html_template(self):
        return self._templates[2]

    @classmethod
    def get_default(cls):
        try:
            return cls.objects.order_by('-date_create').all()[0]
        except IndexError:
            return None

and the admin.py module

class MessageAdmin(NewsletterAdminLinkMixin, ExtendibleModelAdminMixin,
                   admin.ModelAdmin):
    logger.critical('MessageAdmin')
    save_as = True
    list_display = (
        'admin_title', 'admin_newsletter', 'admin_preview', 'date_create',
        'date_modify'
    )
    list_filter = ('newsletter', )
    date_hierarchy = 'date_create'
    prepopulated_fields = {'slug': ('title',)}

    inlines = [ArticleInline, AttachmentInline, ]

    """ List extensions """
    def admin_title(self, obj):
        return format_html('<a href="{}/">{}</a>', obj.id, obj.title)
    admin_title.short_description = _('message')

    def admin_preview(self, obj):
        url = reverse('admin:' + self._view_name('preview'), args=(obj.id,),
                      current_app=self.admin_site.name)
        return format_html('<a href="{}">{}</a>', url, _("Preview"))
    admin_preview.short_description = ''

    """ Views """
    def preview(self, request, object_id):
        logger.critical('preview object_id = %s', object_id)
        return render(
            request,
            "admin/newsletter/message/preview.html",
            {'message': self._getobj(request, object_id),
             'attachments': Attachment.objects.filter(message_id=object_id)},
        )

    @xframe_options_sameorigin
    def preview_html(self, request, object_id):
        logger.critical('preview_html object_id = %s', object_id)
        message = self._getobj(request, object_id)

        if not message.html_template:
            raise Http404(_(
                'No HTML template associated with the newsletter this '
                'message belongs to.'
            ))

        c = {
            'message': message,
            'site': Site.objects.get_current(),
            'newsletter': message.newsletter,
            'date': now(),
            'STATIC_URL': settings.STATIC_URL,
            'MEDIA_URL': settings.MEDIA_URL
        }

        return HttpResponse(message.html_template.render(c))

    @xframe_options_sameorigin
    def preview_text(self, request, object_id):
        message = self._getobj(request, object_id)

        c = {
            'message': message,
            'site': Site.objects.get_current(),
            'newsletter': message.newsletter,
            'date': now(),
            'STATIC_URL': settings.STATIC_URL,
            'MEDIA_URL': settings.MEDIA_URL
        }

        return HttpResponse(
            message.text_template.render(c),
            content_type='text/plain'
        )

    def submit(self, request, object_id):
        submission = Submission.from_message(self._getobj(request, object_id))

        change_url = reverse(
            'admin:newsletter_submission_change', args=[submission.id])

        return HttpResponseRedirect(change_url)

    def subscribers_json(self, request, object_id):
        message = self._getobj(request, object_id)

        json = serializers.serialize(
            "json", message.newsletter.get_subscriptions(), fields=()
        )
        return HttpResponse(json, content_type='application/json')

    """ URLs """
    def get_urls(self):
        urls = super().get_urls()

        my_urls = [
            path('<object_id>/preview/',
                 self._wrap(self.preview),
                 name=self._view_name('preview')),
            path('<object_id>/preview/html/',
                 self._wrap(self.preview_html),
                 name=self._view_name('preview_html')),
            path('<object_id>/preview/text/',
                 self._wrap(self.preview_text),
                 name=self._view_name('preview_text')),
            path('<object_id>/submit/',
                 self._wrap(self.submit),
                 name=self._view_name('submit')),
            path('<object_id>/subscribers/json/',
                 self._wrap(self.subscribers_json),
                 name=self._view_name('subscribers_json')),
        ]

        return my_urls + urls



I have tried a number of the fixes recommended in posts on this error here in stackoverflow and on github. but none have solved the problem.

I created the id = models.BigAutoField(primary_key=True, auto_created=True) and varified in the sqlite db that the primary key and auto increment are in the structure.

I feel like creating a through or xref table between Message and Article would solve it, but I hesitate because the developers of Jazzband Newsletter (https://github.com/jazzband/django-newsletter) did it this way for a reason and that Django or Python updates have let this creep in.

Back to Top