Update:
For anyone curious, I figured out what and why and how to fix it.
In my view I had:
fields = ['html', 'tags', 'title', 'text', 'taken_date', 'image']
And am using {{ form.as_p }} in my template. Apparently once that gets posted from the form it really, really doesn't want anything else touching the form fields that wasn't already in the form.
So I took out the 'tags' field from my view and it works.
Thanks to everyone that responded.
Original Question:
Using Django 2.0.1 and PostgreSQL 9.2.18
I'm writing a simple photogallery application. In it I have a photo object and PhotoTag object. The photo can have many tags and the tags can be associated with many photos, thus it needing to be a ManyToManyField.
Upon save of the submitted photo, a post_save receiver calls functions to make thumbnails (which work fine) and a function to update tags.
The photo gets saved fine, update_tags gets called fine, tags get read from the photo fine, tags get saved into PhotoTag fine. But the manytomany table tying the two together does not get the new rows inserted. Unless the code exits abnormally during either the update_tags function or the post_save receiver function, thumbs after update_tags is called.
I've even tried using a connection.cursor to write directly into the m2m table and it has the same behavior.
If I try to call save() on the Photo object again, I just get into an infinite loop due to the post_save signal.
I'm baffled as to what is going on. Any clues?
# models.py
def update_tags(instance):
tags = get_tags(instance.image)
# Set initial values
pt = []
tagid = ''
photoid = instance.id
# Loop through tag list and insert into PhotoTag and m2m relation
for x in range(0, len(tags)):
# Make sure this tag doesn't already exist
if PhotoTag.objects.filter(tag_text=tags[x]).count() == 0:
pt = PhotoTag.objects.create(tag_text=tags[x])
tagid = PhotoTag.objects.latest('id').id
instance.tags.add(pt)
else:
# Only working with new tags right now
pass
return
class Photo(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
title = models.CharField(max_length=200, null=True, blank=True)
text = models.TextField(null=True, blank=True)
html = models.BooleanField(default=False)
filename = models.CharField(default='', max_length=100, blank=True,
null=True)
image = models.ImageField(upload_to=upload_path)
location = models.CharField(max_length=100, blank=True, null=True)
entry_date = models.DateTimeField(default=timezone.now)
taken_date = models.DateTimeField(blank=True, null=True)
tags = models.ManyToManyField(PhotoTag, blank=True)
@receiver(post_save, sender=Photo)
def thumbs(sender, instance, **kwargs):
"""
Upon photo save, create thumbnails and then
update PhotoTag and m2m with any Exif/XMP tags
in the photo.
"""
mk_thumb(instance.image, 'mid')
mk_thumb(instance.image, 'th')
mk_thumb(instance.image, 'sm')
update_tags(instance)
return
-------------
From views.py
-------------
class PhotoCreate(LoginRequiredMixin, CreateView):
model = Photo
template_name = 'photogallery/photo_edit.html'
fields = ['html', 'tags', 'title', 'text', 'taken_date', 'image']
def get_initial(self):
self.initial = {'entry_date': timezone.now()}
return self.initial
def form_valid(self, form):
form.instance.author = self.request.user
return super(PhotoCreate, self).form_valid(form)
Update:
def save(self, mkthumb='', *args, **kwargs):
super(Photo, self).save(*args, **kwargs)
if mkthumb != "thumbs":
self.mk_thumb(self.image, 'mid')
self.mk_thumb(self.image, 'th')
self.mk_thumb(self.image, 'sm')
self.update_tags()
mkthumb = "thumbs"
return