>
> In trying to update my templates after I successfully finished part 3 of
> the tutorial, I found that I could write something like
> <p>You're looking at the results of question {{ question.id }}: "{{
> question.question_text }}"</p>
> and get: You're looking at the results of question 1: "What's up?"
>

This worked by accident in your particular situation. The 'id' of the
object is a reference to the data row in the database, and is not intended
for human consumption in most cases (ie direct display in the template to
the end-user). If you created more questions, the ID would increase. You
should not rely on it to 'number' your questions, rather number the
questions yourself (either manually or via something like
django-ordered-model). Using the ID, there's no way to a) renumber
questions in a different order or b) group questions together via other
attributes such as a 'question group', where you would want the numbering
for your questions to start over (presumably).


>
> However, if I write
> <p>You're looking at the results of question {{ question.question_id }}:
> "{{ question.question_text }}"</p>
> I get: You're looking at the results of question : "What's up?"
>

> I think the answer is that "The template system uses dot-lookup syntax to
> access variable attributes. In the example of {{ question.question_text }},
> first Django does a dictionary lookup on the object question."  And "id"
> is an attribute of the question object.  But if that's the case, then why
> is "question_id" used everywhere else (views.py, urls.py)?  Is it because
> we *define* the question_id parameter by the pattern of the incoming
> request in views.py?  In other words, if we changed ?P<question_id> to
> ?P<my_favorite_number>, then we would be writing our views like this:
> def detail(request, my_favorite_number):
>     question = get_object_or_404(Question, pk=my_favorite_number)
> but still referencing the id as {{ question.id }} in our templates?
>
>
"question_id" and question.id are referring to very different things. The
reason that {{ question.question_id }} didn't work is because there is no
attribute/method/property on "question" called "question_id". The template
system will return an empty string in those cases where it can't resolve a
value. There is a magic shortcut that might be causing some confusion
(explained below).

Within the views, "question_id" is referring to the kwarg that was captured
by the URL regex (through the regex capture group of the same name), and is
literally just a number (captured as a string). It is used as part of the
.filter() or get_object_or_404() call to pull the object with the database
ID of whatever the value of "question_id" is (which is coerced in to an
integer if it hasn't been already internally).

You are correct in your assertion about changing the name of the capture
group and the view argument and the reflected changes in the
get_object_or_404() call. However, "my_favorite_number" is exactly that,
just a number. Remember, "question_id" is simply a variable name that lives
within the context of your view, that's it.

Now moving on to "question". Once the get_object_or_404() call is made,
"question" becomes a fully populated Question object, rather than just a
number. You can modify it and run .save() to keep the changes in the
database, which you can't do with just "question_id". The "question" in
your view is then passed along via the template context as "question". It
is possible to change the name of the variable that holds your Question
object in the template vs. the view. In fact, this is exactly what the
class-based views are doing behind the scenes, and every reference to the
primary object of interest (in this case, a Question object) in a template
populated by a CBV is called {{ object }} within the template.

Template naming tricks aside, all of the calls within your template to {{
question }} are for an actual Question object. Question objects (per the
tutorial models) have no attribute/field called "question_id", hence the
reason your template didn't display anything.


To confuse things more, Django does offer some optimization shortcuts for
related fields. For example, if you were working with a Choice object in a
variable called "choice", you can access the database ID of the related
question in two ways (in either a view or a template):

choice.question.id
choice.question_id

Both of these calls will result in the same value, the database ID of the
Question model that the Choice belongs to. However, there is a big
difference in how they get there.

The first is the "standard" way to access information about related
objects. The ORM tries to be lazy, so it doesn't try to fetch anything
about the related Question unless needed (ie accessing anything
choice.question.*). The first time it is called, a database hit is incurred
to populate the Question object that is related to the Choice object. Once
the Question object is populated, the ID of that object is returned.

The second is less-known, but is used by programmers who are looking to
lessen the stress on their database. It takes advantage of a little magic
provided by Django that makes the raw ID of a related object available for
use without hitting the database a second time (since the FK relationship
has the raw ID stored, and it is used to pull the right related object). It
uses the format of "foo_id" where "foo" is the name of the relationship.

It is mentioned here in this section of the docs:

https://docs.djangoproject.com/en/1.9/ref/models/querysets/#values

HTH,

-James

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/CA%2Be%2BciU6X4e4qzG1YAngCEofZ_bWw0TRVOMJ7aGDN7st8sweiA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to