Opened 16 years ago

Closed 16 years ago

Last modified 16 years ago

#6118 closed (duplicate)

Add Ordered MayToMany

Reported by: toomim@… Owned by: nobody
Component: Uncategorized Version: dev
Severity: Keywords: ordered list many-to-many
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I'm writing an extremely simple django app to store a database of publications for academics. Each publication has a title and an ordered list of authors. I want the academics in my group to enter their pubs and author lists using the django admin.

Here's the basic model:

class Author(models.Model):
    name = models.CharField(maxlength=30)

class Pub(models.Model):
    title = models.CharField(maxlength=200)
    authors = models.ManyToManyField(Author)

However, this list of authors is unordered, and academics care a lot about author order.

Even though ordered lists are common in practice, they turn out to be very tricky to represent in django.You can introduce an intermediary table (http://www.djangoproject.com/documentation/models/m2m_intermediary/) but doing so is a bit too complicated and unintuitive, and I was personally unable to make it work properly with the admin site. (See below & attachment.)

This ticket proposes a new relation akin to "OrderedManyToManyField" that works just like ManyToMany, except that the order of elements can be specified and preserved. The code for the above would look something like:

class Author(models.Model):
    name = models.CharField(maxlength=30)

class Pub(models.Model):
    title = models.CharField(maxlength=200)
    authors = models.OrderedManyToManyField(Author)

Note that the order must be maintained per publication; you can't just order by an attribute on the author model. Each author can be in multiple differently-ordered lists.

Just for the record, here's my current attempt at implementing an ordered list of items using an intermediary table:

from django.db import models

class Author(models.Model):
    name = models.CharField(maxlength=30)
    def __str__(self):
        return self.name
    class Admin:
        pass

class Pub(models.Model):
    title = models.CharField(maxlength=200)
    def __str__(self):
        return self.title
    class Admin:
        pass

class PubAuthor(models.Model):
    author = models.OneToOneField(Author, core=True)
    author_number = models.IntegerField(core=True)
    pub = models.ForeignKey(Pub, edit_inline=models.TABULAR, num_in_admin=5, num_extra_on_change=5)
    class Admin:
        pass
    def __str__(self):
        return self.author.__str__() + ' ' + str(self.author_number)

Besides being more complicated to write, the admin interface for this code does not work right. I'm attaching a screenshot of viewing a pub after it has been created and saved. Note that (1) the admin user has to manually specify the index of each pub rather than have it implicit in the order of the list, and (2) for some reason the authors cannot be changed after the pub has been saved and committed to the database.

(Including links in a separate post to dodge spam filter.)

Attachments (1)

badorderedmanytomany.png (20.3 KB ) - added by toomim@… 16 years ago.
Screenshot of failed ordered list attempt

Download all attachments as: .zip

Change History (8)

by toomim@…, 16 years ago

Attachment: badorderedmanytomany.png added

Screenshot of failed ordered list attempt

comment:2 by anonymous, 16 years ago

Links:

My failed approach uses an intermediary table: http://www.djangoproject.com/documentation/models/m2m_intermediary/

Rails has something called "acts_as_list": http://api.rubyonrails.org/classes/ActiveRecord/Acts/List/ClassMethods.html#M000667

There is existing code that might be reusable here:
http://www.djangosnippets.org/snippets/259/
...which I believe was derived from here:
http://www.djangosnippets.org/snippets/245/

However this code does not include an Admin interface.

comment:3 by Brian Rosner, 16 years ago

Resolution: duplicate
Status: newclosed

Marking duplicate of #6095, which fixes the real problem.

comment:4 by toomim@…, 16 years ago

Resolution: duplicate
Status: closedreopened

Although 6095 improves the workaround of using intermediate tables, they still do not provide the functionality of ordered lists.

Intermediate tables can be hard to wrap one's head around (see the mailing list posts).

The ideal admin interface has a list of items that can be dragged and dropped to reorder:

Item 1 [x delete]
Item 2 [x delete]
[+ add item]

Not a two-column table of fixed length with integers in one column:

Item 1  |  2
Item 2  |  1
______  |  _
______  |  _
______  |  _
______  |  _

In the latter, the admin user has to manually track the integers, add rows, etc.

in reply to:  4 comment:5 by anonymous, 16 years ago

Replying to toomim@cs.washington.edu:

In the latter, the admin user has to manually track the integers, add rows, etc.

I should clarify: the real problem with the intermediate table UI is that the admin user has to know what in the world is going on in the first place. It makes much more sense to *present* an ordered list as an ordered list than as a two-column table. An admin view for an ordered list, even if the underlying code used intermediate tables, would be great.

comment:6 by Brian Rosner, 16 years ago

Resolution: duplicate
Status: reopenedclosed

This can already be done with the newforms-admin and will be merged in once completed. Marking a duplicate of #13 which will be visited when admin UI work starts after newforms-admin is merged in to trunk.

comment:7 by toomim@…, 16 years ago

Great, thanks for clarifying.

Note: See TracTickets for help on using tickets.
Back to Top