0

I am trying to build a publication database for researchers. So my database has model classes Paper, Author and Journal. Journal is a foreign key to Paper while Author is a ManytoMany key to Paper. The model definition is thus:

from django.db import models
from django import forms
from django.forms import ModelForm, Textarea

# Create your models here.

class Journal(models.Model):
    name = models.CharField(max_length = 100)
    organization = models.CharField(max_length = 100, blank = True)

    def __unicode__(self):
        return self.name


class Author(models.Model):
    first_name = models.CharField(max_length = 20, blank = True)
    last_name = models.CharField(max_length = 20, blank = True)
    middle_name = models.CharField(max_length = 20, blank = True)
    full_name = models.CharField(max_length = 50)
    email = models.EmailField(blank = True)

    def __unicode__(self):
        return self.full_name


class Paper(models.Model):
    paper_title = models.CharField(max_length=200)
    paper_year = models.IntegerField(blank = True, null = True)
    paper_volume = models.CharField(max_length = 100, blank = True, null = True)
    paper_number = models.CharField(max_length = 100, blank = True, null = True)
    paper_pages = models.CharField(max_length = 100, blank = True, null = True)
    paper_month = models.CharField(max_length = 15, blank = True, null = True)
    paper_doi = models.CharField(max_length = 50, blank = True, null = True)
    paper_abstract = models.TextField(blank = True, null = True)
    paper_keywords = models.TextField(blank = True, null = True)
    paper_journal = models.ForeignKey(Journal)
    paper_authors = models.ManyToManyField(Author)

    def __unicode__(self):
        return self.paper_title

I created a database and now I am trying to use forms to let the user edit a paper. I am using ModelForm for creating the form. To edit the Author information for a paper, I am using a drop down list to let the user know a particular author in the paper may be a duplicate. The user can then check out the other author and if indeed it is a duplicate author entry, can insert the data of the other author into this paper. The block of code for this purpose is:

other_author = Author.objects.get(id = other_author_srno)
print(other_author)
replaced_author = Author.objects.get(id = author_srno)
print(replaced_author)
replaced_author_papers = replaced_author.paper_set.all()
print(replaced_author_papers)
for paper_item in replaced_author_papers:
    print("initial")
    print("authors")
    paper_item_authors = paper_item.paper_authors.all()
    print(paper_item_authors)
    copy_of_paper_item_authors = []
    for author in paper_item_authors:
        copy_of_paper_item_authors.append(author)
    print("copyofauthors")
    print(copy_of_paper_item_authors)
    for author in paper_item_authors:
        paper_item.paper_authors.remove(author)
    print("afterremove")
    print(paper_item.paper_authors.all())
    print(copy_of_paper_item_authors)
    for author in copy_of_paper_item_authors:
        if not author == replaced_author:
            paper_item.paper_authors.add(author)
        else:
            paper_item.paper_authors.add(other_author)
        paper_item.save()
        print(paper_item.paper_authors.all())
    print(paper_item.paper_authors.all())

So basically the replaced_author object gets replaced by the other_author object. Since, these are authors in a paper, the order of authors is important. So I made a copy of the authors (paper_authors), removed all the items for paper_authors and then add author objects from the copy except for the object that needs to be replaced. But the order of authors gets messed up. For example, say there is a paper with authors A. AAA, B. BBB, C. CCC and there is another paper with these identical authors. I want to replace them one by one since they are identical entries. But this is the output if I try to replace author B. BBB.

B. BBB
B. BBB
[<Paper: XYZ>]
initial
authors
[<Author: A. AAA>, <Author: B. BBB>, <Author: C. CCC>]
copyofauthors
[<Author: A. AAA>, <Author: B. BBB>, <Author: C. CCC>]
afterremove
[]
[<Author: A. AAA>, <Author: B. BBB>, <Author: C. CCC>]
[<Author: A. AAA>]
[<Author: A. AAA>, <Author: B. BBB>]
[<Author: A. AAA>, <Author: C. CCC>, <Author: B. BBB>]
[<Author: A. AAA>, <Author: C. CCC>, <Author: B. BBB>]

It inserts the author C. CCC in the second place. Is there some ordering aspect in ManyToMany fields that I am overlooking? I would like the ordering to be maintained.

Thanks in advance.

Shiv Kumar
  • 361
  • 5
  • 16
  • 1
    Possible duplicate of [Ordering many-to-many relations in Django models](http://stackoverflow.com/questions/19901818/ordering-many-to-many-relations-in-django-models) – Todor Mar 12 '17 at 00:55
  • Thanks for that link @Todor. As a follow-up question - if I add ManyToMany objects to another object in a sequence, the QuerySet could produce another arbitrary sequence? When I first generated the database by adding ManyToMany objects in a sequence, the sequence was always right. Surprising that the sequence got disrupted only when I tried to replace ManyToMany objects. – Shiv Kumar Mar 12 '17 at 02:39
  • You can't count on this ordering (sequence), since you don't define order, the database is allowed to return the results in any order. – Todor Mar 12 '17 at 07:38
  • Thanks again. That solves my problem. – Shiv Kumar Mar 12 '17 at 12:32

0 Answers0