我不确定如何标题这个问题。
我正在使用Django 1.10构建期刊网站。使用管理界面,可以添加发布。出版物附带多个使用through
订购的作者。还可以将PDF文件上传到出版物。我正在尝试使用upload_to
的自定义FileField
函数作为described in the docs,确保PDF文件具有一致且合理的名称。具体来说,我希望名称为(lastname of the first author) + "_" + (year of publication) + (a letter that depends on the number of previous publications of the same first author that year) + ".pdf"
。例如,对于2016年发表论文的第一作者史密斯,文件名为Smith_2016a.pdf
。第二个应该是Smith_2016b.pdf
,依此类推。当编辑现有出版物时,我就可以使用它。
但是,如果创建新发布并尝试添加PDF,则会出现list index out of range
错误。这是因为对Person.objects.filter(author_of = instance)
的调用会导致查询为空,因为当前对象尚未保存在数据库中。
我的问题是:是否有可能以其他方式获取新出版物的第一作者的姓氏?如果没有这个,就无法确定要添加到年份的字母。
由于manytomanyfield
through
的工作方式有效,我们不能只使用instance.authors[0]
来获取第一作者:
(Pdb) instance.authors
*** ValueError: "<Publication: Test paper (OQSPS)>" needs to have a value for field "publication" before this many-to-many relationship can be used.
解决方法是首先在没有PDF的情况下保存出版物,然后对其进行编辑并添加PDF。我测试了这个并且它有效。
也许可以强制两步保存新出版物的方式与新User
的某些字段在第一步中无法编辑的方式相同。根据{{3}},这似乎是可能的。
来自models.py
的一些相关代码:
def custom_filename(instance, filename):
#determine lastname of first author
authors = Person.objects.filter(author_of = instance)
pdb.set_trace()
#how many papers by this author this year?
papers = Publication.objects.filter(authors = authors[0])
#filter to those where he is first author
papers_firstauthor = []
for paper in papers:
#is it the current paper?
if paper == instance:
#then dont count it
continue
#is it published after the current paper?
if paper.publication_date > instance.publication_date:
#then don't count it
continue
#get the authors of that paper
paper_authors = Person.objects.filter(author_of = paper)
if paper_authors[0] == authors[0]:
papers_firstauthor.append(paper)
#choose a letter fitting to the number of previous papers by that author
letter = string.ascii_lowercase[len(papers_firstauthor)]
# file will be renamed to
return '{0}_{1}{2}.pdf'.format(authors[0].lastname, instance.publication_date.year, letter)
#Publications
class Publication(models.Model):
#mandatory
journal = models.ForeignKey(Journal, blank=False)
authors = models.ManyToManyField(Person, blank=False, related_name = "author_of", through='AuthorOrder')
title = models.CharField(max_length=500, blank=False)
publication_date = models.DateField(default=now, blank=False)
submission_date = models.DateField(default=now, blank=False)
#optional
abstract = models.TextField(max_length=1000, blank=True)
keywords = models.CharField(max_length=1000, blank=True)
pdf = models.FileField(blank=True, upload_to=custom_filename) #the current PDF file
sup_mat_link = models.CharField(max_length=200, blank=True) #link to supplementary materials
peerreview_thread_link = models.CharField(max_length=200, blank=True) #link to peer review thread on the forum
reviewers = models.ManyToManyField(Person, blank=True, related_name = "reviewer_of")
old_url = models.CharField(max_length=150, blank=True) #URL on the old wordpress site
DOI = models.CharField(max_length=200, blank=True)
#self
def __str__(self):
return "{0} ({1})".format(self.title, self.journal.abbreviation)
#review length
def review_time(self):
return self.publication_date - self.submission_date
#AuthorOrder
class AuthorOrder(models.Model):
publication = models.ForeignKey(Publication)
author = models.ForeignKey(Person)