Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python

Mike Nedelko
Mike Nedelko
8,991 Points

Django - Forms - Quiz model iterable with lambda

Hi Treehouse Community

I have a question about the 'Quiz Model' episode in the django forms module.

The modifications we are making to the def course_detail(request,pk) function seem logical, but I would like to understand some of the finder details associated with that. As such I realized that this episode raised a few question around inheritance which I would love to get some advice on:

i.e. When we implement this steps = sorted(chain(course.text_set.all(), course.quiz_set.all()), key = lambda step:step.order)

I would like to know the following:

A) I understand that chain makes one big iterable by taking everything from course.text_set.all() and course.quiz_set.all(). But what form does this iterable take. Is this a list of tuples of [(text_set1, quiz_set1), (text_set2, quiz_set2),...] or are we looking at a dictionary of form {1:[text_set1,quiz_set1], 2:[text_set1,quiz_set1],....}

B) When we add the lambda key to the sorted method, we are refering to step:step.oder. That said, I did notice however that both text questions and quiz questions can have their order manually modified in the admin. In case, a Text and a Quiz have the same value for the 'order' field, what does Django default back to. The ID? If so this raises the third question.

C) ID and abstract models. When Django generates models these models automatically get their own IDs (very handy). But how is this handeled in sbract models. Does Django generate two IDs - ie one for the abstract model and one for the model that inherits based on the abstract model, or does it only generate IDs for the model that inherited form the abstract model.

D) If the latter is the case, how can we define lambda as step:step.oder? Isn't step an abstract model mmeaning that we can't query against it? Or is STEP, 'THE MOTHER OF ALL TEXT AND QUIZZ CLASSES', meaning that instanciation of text is also an instanciation of step. The implication here would be that Django generates IDs for steps only, and that Text and Quizz just get the next 'Step_Id' whenever a new Text of Quiz model is instanciated. However this raises another question:

E) If Text and Quiz share a stream of IDs (as they are both inheriting IDs from Step) how would we be managin foreighn Keys? Can one make reference to a foreighnKey Field of an inherited class or woudl that automatically defualt back to the ID of the abstract class it was inherited from?

I know these are quite a few questions, but any advice would be highly appreciated.

:) To the Treehouse team: Thanks for the great lession and to the Treehouse Community, thank you for the advice!

Mike

Mike Nedelko
Mike Nedelko
8,991 Points

Ok - UPDATE:

I noticed that abstract inheritance means that we actually don't have a Step table... this makes question C above even more important for me.

If Text and Quiz (which are both inherited from Step), get their own tables, wouldn't Django generate IDs for each instance of these models? If so, what would Django do if there was a conflict in terms of ordering our Steps on the course_details page?

i.e. value of order field is the same in both Text and Quizz --> Django defaults back to ID BUT ID is also the same in both Table and Quizz instances?

2 Answers

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,441 Points

Hi Mike, Let's work through your questions

A) I understand that chain makes one big iterable by taking everything from course.text_set.all() and course.quiz_set.all(). But what form does this iterable take?

chain does not necessarily make a uniform object from its arguments. It gets the iterator of the first item, exhausts it, then gets the iterator from the second item. The two iterators may be different. In this case, the argument is a QuerySet and the iterator is a generator that returns one object at a time. The first generator returns Text objects, the second produces Quiz objects. The behavior is similar to a list of the form [text_set[[0], text_set[1], text_set[2],... quiz_set[0], quiz_set[1], quiz_set[2],...], where each text_set object is a Text object and each quiz_set object is a Quiz object.

B) When we add the lambda key to the sorted method, we are referring to step:step.order. That said, I did notice however that both text questions and quiz questions can have their order manually modified in the admin. In case, a Text and a Quiz have the same value for the 'order' field, what does Django default back to. The ID? If so this raises the third question.

Python sorting is "guaranteed to be stable" which means that if two key values are the same then their order remains the same. This implies that if text_set is ahead of quiz_set in the chain, then if the two orders are the same, the Text object will appear before the Quiz object.

C) ID and abstract models. When Django generates models these models automatically get their own IDs (very handy). But how is this handled in abstract models. Does Django generate two IDs - ie one for the abstract model and one for the model that inherits based on the abstract model, or does it only generate IDs for the model that inherited form the abstract model.

It only generates tables and IDs for inheriting subclass Quiz and Text. Inspecting using python manage.py dbshell, you can see that the tables have been flattened to include the abstract class.

sqlite> .schema courses_quiz
CREATE TABLE "courses_quiz" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
     "title" varchar(255) NOT NULL, "description" text NOT NULL,
     "order" integer NOT NULL, "total_questions" integer NOT NULL,
     "course_id" integer NOT NULL REFERENCES "courses_course" ("id"));
CREATE INDEX "courses_quiz_ea134da7" ON "courses_quiz" ("course_id");
sqlite> .schema courses_text
CREATE TABLE "courses_text" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
     "title" varchar(255) NOT NULL, "description" text NOT NULL,
     "order" integer NOT NULL,
     "course_id" integer NOT NULL REFERENCES "courses_course" ("id"),
     "content" text NOT NULL);
CREATE INDEX "courses_step_ea134da7" ON "courses_text" ("course_id");

D) If the latter is the case, how can we define lambda as step:step.order? Isn't step an abstract model meaning that we can't query against it? Or is STEP, 'THE MOTHER OF ALL TEXT AND QUIZ CLASSES', meaning that instantiation of text is also an instantiation of step. The implication here would be that Django generates IDs for steps only, and that Text and Quiz just get the next 'Step_Id' whenever a new Text of Quiz model is instantiated.

Perhaps you're confusing the class Step with the variable name in the lambda function step. The step in the lambda function is simply a name for a local variable. It could also have been 'thing' as in:

steps = sorted(chain(course.text_set.all(), course.quiz_set.all()), 
               key = lambda thing; thing.order)

For each "thing" in the chain results, sorted will use the thing.step value as the sort key. This means it will be text_set[0].step, etc. for the Text objects and quiz_set[0].step, etc. for the Quiz objects.

E) If Text and Quiz share a stream of IDs (as they are both inheriting IDs from Step) how would we be managing foreign Keys? Can one make reference to a foreignKey Field of an inherited class or would that automatically default back to the ID of the abstract class it was inherited from?

The stream of IDs are separate and independent for both the Text and Quiz objects.

Bonus 1: If Text and Quiz (which are both inherited from Step), get their own tables, wouldn't Django generate IDs for each instance of these models?

Yes, each table gets it's own set of IDs

Bonus 2: If so, what would Django do if there was a conflict in terms of ordering our Steps on the course_details page?

The ordering is not in terms of Steps, but rather the value of the order attribute of each instance of either Quiz or Text

Bonus 3: i.e. value of order field is the same in both Text and Quizz --> Django defaults back to ID BUT ID is also the same in both Table and Quizz instances?

The IDs do not enter into the sort. It is solely based on the key argument. In cases of ties, its first-seen-first-listed so, as mentioned above, the sort stability will preserve whichever instance was seen first.

Did that cover it? Post back for more details if needed.

Mike Nedelko
Mike Nedelko
8,991 Points

Dear Chris. Thank you VERY much for this detailed reponse. Everything is much clearer now. I really appreciate the time and effort reflected in your response. This is great! Thank you!