更新:我创建了一个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需要保存提交时,尚未保存该提交。
做到这一点的最佳方法是什么。希望我在这里很有道理。
谢谢你的帮助!
也许你可以这样尝试:
首先,更新你的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 filenameRun 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 instanceRun 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)