Django:使用自定义upload_to函数,可以在保存之前查询manytomanyfields吗?

时间:2016-08-18 01:29:53

标签: python django

我不确定如何标题这个问题。

我正在使用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)

0 个答案:

没有答案