Django: using custom upload_to function, can I request multi-product fields before saving?

I was not sure what to call this question.

I am creating a magazine site using Django 1.10. Using the admin interface, you can add publications. Publications come with several authors who are sorted through through . In addition, you upload PDF files to the publication. I am trying to ensure that PDF files have consistent and reasonable names using the custom upload_to function for FileField as described in the docs . In particular, I want the names to be (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" For example, for the first author of Smith, who publishes the document in 2016, the file name will be Smith_2016a.pdf . The second should be Smith_2016b.pdf , etc. I got this to work when you edit an existing post.

However, if you create a new publication and try to add a PDF, the list index out of range error appears. This is because calling Person.objects.filter(author_of = instance) results in an empty request, because the current object has not yet been saved to the database.

My question is: is it possible to get the last name of the first author of a new publication in some other way? Without this, it is impossible to determine which letter to add per year.

Due to how manytomanyfield works with through , you cannot use instance.authors[0] to get the first author:

 (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. 

The workaround is to save the publication first without a PDF, then edit it and add the PDF. I tested this and it works.

Perhaps you can force two-stage saving of new publications in the same way that some fields of the new User not edited at the first stage. This seems possible according to a 6 year question .

Some relevant code from 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) 
+1
python django
source share

No one has answered this question yet.

See similar questions:

7
In Django, how do I imitate the two-step method of adding users via admin for my own models?

or similar:

5
django - inlineformset_factory with several foreign keys
4
Access to Django foreign key in save () function
4
Radio buttons in django admin
3
What is wrong with my machines .py?
3
How to set some specific model_b fields based on model_a field?
2
How to set dynamic initial values ​​in django modelform field
one
Create a new model that has all the fields of the existing model
one
Show subclass information in django_display list
0
json filter data from Django model
0
How to check if Django Signal is working?

All Articles