views:

52

answers:

2

I'm having some trouble figuring out the best/Djangoic way to do this. I'm creating something like an interactive textbook. It has modules, which are more or less like chapters. Each module page needs to list the topics in that module, grouped into sections.

My question is how I can ensure that they list in the correct order in the template? Specifically:

1) How to ensure the sections appear in the correct order?
2) How to ensure the topics appear in the correct order in the section?

I imagine I could add a field to each model purely for the sake of ordering, but the problem with that is that a topic might appear in different modules, and in whatever section they are in there they would again have to be ordered somehow.

I would probably give up and do it all manually were it not for the fact that I need to have the Topic as object in the template (or view) so I can mark it up according to how the user has labeled it.

So I suppose my question is really to do with whether I should create the contents pages manually, or whether there is a way of ordering the query results in a way I haven't thought of. Thanks for your help!

edit: The simplest thing I can think of would be if I could have an ordered list (of topics) in the module or section model, but afaik that's not possible. Is it? Perhaps with a custom field?

+1  A: 

I would use a table in your database specifically for ordering topics in modules eg:

Topic | Module | Order
A     | mod1   | 2
B     | mod1   | 1
C     | mod1   | 3
C     | mod2   | 2
A     | mod2   | 3
B     | mod2   | 1

It may not be the best method but it's how I've solved the issue in my own app.

To order the data you simply use .order_by("field_name") on the end of your model.objects.filter() statement.

danspants
I like this solution, but can I really just use order_by like that? Wouldn't I need to refer to the new table I'm using for this ordering somewhere in the query?
Chris
You would need to have the order table linked to the module and topic tables through foreign keys. You then do something like : Mod=module.objects.get(module="mod1") order.objects.filter(module=mod).order_by("order"). You then can access the Topics through the foreign key in each order object.
danspants
This is imho also the best solution, for more information of how to do this properly in django, see http://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships
KillianDS
This is what I've gone with, with an extra Section column in this table to allow me to regroup by that in the template. Thanks!
Chris
+4  A: 

So your structure is basically module/section/topic, and topics can appear in more than one section.

Basically, you want this (content fields omitted):

class Module(models.Model):
    title = CharField(max_length=100)

class Section(models.Model):
    topics = ManyToManyField(Topic, related_name="sections", 
        through='TopicEntry')
    module = models.ForeignKey(Module, related_name="sections")

class Topic(models.Model):
    text = models.TextField()

class TopicEntry(models.Model):
    section = models.ForeignKey(Section)
    topic = models.ForeignKey(Topic)
    order = models.IntegerField()

See Extra Fields on Many-to-Many Relationships for more information on ManyToManyField.through. The docs aren't perfectly clear, though. If I read them right, to get your table of contents, use something like:

topicList = Topic.objects.filter(section=section).order_by("TopicEntry__order")
# Might be "topicEntry__order" or "topicentry__order" instead; the docs aren't 
# clear how it transforms the name of the intermediate model.
# This also works:
topicList = section.topics.all().order_by("TopicEntry__order")
Mike DeSimone