Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python/Django Saving m2m with Through

Tags:

python

django

UPDATE: I created a github repo with a full site demonstration of the problem. Maybe my description below isn't quite communicating what I'm trying to do.

The github repo is: https://github.com/theCodeJerk/m2m-through

I really appreciate any help you may offer.

The code below is stripped down to illustrate the issue. While there are things that you may want to say "why would you do this anyway", there is probably a reason in the larger context :)

Here is my view:

class SubmissionCreate(CreateView):
    model = Submission
    fields = '__all__'
    template_name_suffix = '_create_form'
    success_url = '/'

Here is the relevant models.py code:

def custom_filename(instance, filename):
    author = instance.publishers[0]
    return 'papers/{0}.pdf'.format(author.pseudonum)


class Submission(models.Model):
    name = models.CharField(
        max_length=200, 
        blank=False
        )
    upload = models.FileField(
        blank=True, 
        upload_to=custom_filename
        )
    publishers = models.ManyToManyField(
        'Publisher', 
        blank=False, 
        related_name='publisher_of', 
        through='SubmissionPublisher'
        )


class Publisher(models.Model):
    user = models.ForeignKey(
        User, blank=False, 
        on_delete=models.CASCADE
        )
    pseudonym = models.CharField(
        max_length=200,
        blank=False
        )


class SubmissionPublisher(models.Model):
    publisher = models.ForeignKey(
        'Publisher', 
        blank=False, 
        on_delete=models.CASCADE
        )
    submission = models.ForeignKey(
        'Submission', 
        blank=False, 
        on_delete=models.CASCADE
        )

The problem is in the custom_filename, because I need the first publisher from the instance to generate the filename. The Submission is not yet saved when the SubmissionPublisher needs it to be saved.

What would the best way to do this be. Hopefully I have made sense here.

Thanks for any help!

like image 398
hmcclungiii Avatar asked Oct 28 '22 10:10

hmcclungiii


1 Answers

Probably you can try like this:

First, update your custom_filename method:

def custom_filename(instance, filename):
    if instance:
        authors = instance.publishers.all()
        if authors.exists():
           author = authors[0]
           return 'papers/{0}.pdf'.format(author.pseudonum)
    return filename

Here I have fixed few issues, for example in your code instances.publishers[0] won't work, because you need to use a queryset method(like all(), or filter() etc) to access Publisher instances.

Then, make upload field nullable. Because you can't create M2M relations without creating Submission instance, and you can't create Submission instance with upload not null, because it requires an image.

class Submission(models.Model):
    name = models.CharField(
        max_length=200, 
        blank=False
    )
    upload = models.FileField(
        null=True, default=None,
        blank=True, 
        upload_to=custom_filename
    )

Then, create a Form and override the save method:

from django import forms
    from .models import Submission

    class SubmissionForm(forms.ModelForm):
        class Meta:
            model = Submission
            fields = '__all__'

        def save(self, commit=True):
            uploaded_file = self.cleaned_data.pop('upload')
            instance = super().save(commit=True)
            instance.upload = uploaded_file
            instance.save()
            return instance

Here I am pulling out the value for upload and saving the instance first. Then putting the image later. This code will work because upload field is nullable in your Submission model.

Finally, use that form class in your SubmissionCreate view:

class SubmissionCreate(CreateView):
    model = Submission
    form_class = SubmissionForm
    template_name_suffix = '_create_form'
    success_url = '/'
like image 135
ruddra Avatar answered Oct 31 '22 19:10

ruddra