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.