Python / Django通过Through节省m2m

hmc*_*iii 5 python django

更新:我创建了一个github回购,其中包含该问题的完整站点演示。也许我在下面的描述没有完全传达我正在尝试做的事情。

github仓库是:https : //github.com/theCodeJerk/m2m-through

非常感谢您提供的任何帮助。

下面的代码已精简以说明问题。尽管有些事情您可能想说“为什么您仍然要这样做”,但在较大的上下文中可能有一个原因:)

这是我的看法:

class SubmissionCreate(CreateView):
    model = Submission
    fields = '__all__'
    template_name_suffix = '_create_form'
    success_url = '/'
Run Code Online (Sandbox Code Playgroud)

这是相关的models.py代码:

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
        )
Run Code Online (Sandbox Code Playgroud)

问题出在custom_filename中,因为我需要实例中的第一个发布者来生成文件名。当SubmissionPublisher需要保存提交时,尚未保存该提交。

做到这一点的最佳方法是什么。希望我在这里很有道理。

谢谢你的帮助!

rud*_*dra 2

也许你可以这样尝试:

首先,更新你的custom_filename方法:

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
Run Code Online (Sandbox Code Playgroud)

在这里我修复了一些问题,例如在您的代码中将instances.publishers[0]无法工作,因为您需要使用查询集方法(如all()filter()等)来访问Publisher实例。

然后,使upload字段可为null。因为如果不创建Submission实例就无法创建 M2M 关系,并且无法创建不Submission为 null 的实例upload,因为它需要图像。

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
    )
Run Code Online (Sandbox Code Playgroud)

然后,创建一个Form并重写该save方法:

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
Run Code Online (Sandbox Code Playgroud)

在这里,我首先提取实例的值upload并保存实例。然后稍后再放图片。此代码将起作用,因为upload字段在您的模型中可为空Submission

最后,在您的视图中使用该表单类SubmissionCreate

class SubmissionCreate(CreateView):
    model = Submission
    form_class = SubmissionForm
    template_name_suffix = '_create_form'
    success_url = '/'
Run Code Online (Sandbox Code Playgroud)