内容简介:In the previousUnderstand Django article, we looked at the fundamentals of using views in Django. This article will focus on templates. Templates are your primary tool in a Django project for generating a user interface. Let’s see how templates hook into v
In the previousUnderstand Django article, we looked at the fundamentals of using views in Django. This article will focus on templates. Templates are your primary tool in a Django project for generating a user interface. Let’s see how templates hook into views and what features Django provides with its template system.
Set Up Templates
We need a place for templates to live. Templates are static files that Django will fill in with data. In order to use those files, we must instruct Django on where to find them.
Like most parts of Django,
this configuration is
in your project’s settings file.
After you use startproject
,
you can find a section
in your settings file
that will be called TEMPLATES
.
The section should look something like:
# project/settings.py TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
Django’s template system can use multiple template backends. The backends dictate how your templates will work. I would recommend sticking with the default Django template language. This language has the tightest integration with the framework and the strongest support.
The next thing to notice is APP_DIRS
with its value of True
.
For the Django template language,
setting this value to True
will cause Django
to look for template files
within a templates
directory
in each Django application
in your project.
Note that this also includes any third party applications
so you should probably leave this to True
.
So, where should your templates go? There are different schools of thought in the Django community. Some developers believe in having all templates within applications. Others ascribe to having all your project’s templates in a single directory. I’m in this second category of developers. I find it valuable to keep all of the templates for my entire project within a single directory.
From my perspective,
keeping templates in a single directory
makes it very clear
where all the layout and UI
in your system will live.
To use that pattern,
we must set the DIRS
variable
with the directory
that we want Django to include.
I recommend keeping a templates
directory
at the root of your project.
If you do that,
your DIRS
value will change
to something like:
# project/settings.py TEMPLATES = [ ... "DIRS": [os.path.join(BASE_DIR, "templates")], ... ]
Finally,
there is OPTIONS
.
Each backend can accept a variety
of options. startproject
set a number of context processors.
We’ll come back to context processors later
in this article.
With your templates set up, you’re ready to go!
Using Templates With Render
Django builds your user interface by rendering a template. The idea behind rendering is that dynamic data is combined with a static template file to produce a final output.
To produce an HttpResponse
that contains rendered output,
we use the render
function.
Let’s see an example.
# application/views.py from django.shortcuts import render def a_template_view(request): context = {'name': 'Johnny'} return render(request, 'hello.txt', context)
In this example,
the view would use a template located
in templates/hello.txt
which could contain:
Hello {{ name }}
When this view responds to a request, a user would see “Hello Johnny” in their browser. There are some interesting things to note about this example.
some_template.html {{ name }}
This idea of mixing context and static layout is the core concept of working with templates. The rest of this article builds on this root concept and shows what else is possible in the Django template language.
From the last article,
you may recall seeing the TemplateView
.
In those examples,
we provided a template name,
and I declared that Django would take care
of the rest.
Now you can start to understand
that Django takes the template name
and calls code similar to render
to provide an HttpResponse
.
Those examples were missing context data
to combine with the template.
A fuller example to replicate what is above would look like:
# application/views.py from django.views.generic.base import TemplateView class HelloView(TemplateView): template_name = 'hello.txt' def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) context['name'] = 'Johnny' return context
This example uses get_context_data
so that we can insert our “dynamic” data
into the rendering system
to give us the response we want.
In a real application, a lot of the code that we need to write focuses on building up a truly dynamic context. I’m using static data in these examples to keep the mechanics of the template system clear. When you see me use context, try to imagine more complex data building to create a user interface.
Those are the fundamentals of rendering. We’ll now turn our attention to what the Django template language is capable of.
Templates In Action
When using templates, we take context data and insert it into the placeholders within the template.
This most basic form
of filling placeholders
with context
are template variables.
The previous section showed an example
by using the name
variable.
The context dictionary contained a name
key
and double curly braces
like {{ name }}
are
where the name
value is used.
We can also use a dot access when the context data is more complex. Let’s say your template gets context like:
context = { 'address': { 'street': '123 Main St.', 'city': 'Beverly Hills', 'state': 'CA', 'zip_code': '90210', } }
Your Django template won’t
work
if you try to access this context data
like a regular dictionary
(e.g., {{ address['street'] }}
).
Instead,
you would use dot notation
to get to the data
in the dictionary.
The address is: {{ address.street }} {{ address.city }}, {{ address.state }} {{ address.zip_code}}
This would render as:
The address is: 123 Main St. Beverly Hills, CA 90210
Django templates also try
to be flexible
with the types of context data.
You could also pass in a Python class instance
like an Address
class
with attributes
that are the same as the keys
in our previous dictionary.
The template would work the same.
The core template language also includes some standard programming logic keywords
by using tags
.
Template tags look like {% some_tag %}
whereas template variables look like {{ some_variable }}
.
Variables are meant to be placeholders
to fill in,
but tags offer more power.
We can start
with two core tags, if
and for
.
The if
tag is for handling conditional logic
that your template might need.
{% if user.is_authenticated %} <h1>Welcome, {{ user.username }}</h1> {% endif %}
This example will only include this welcome message HTML header tag
when the user is logged in
to the application.
We started the example
with an if
tag.
Observe that the if
tag requires a closing endif
tag.
Templates must respect whitespace
since your layout might depend
on that whitespace.
The template language can’t use whitespace
to indicate scope
like it can with Python
so it uses closing tags instead.
As you might guess,
there are also else
and elif
tags
that are accepted inside
of an if
/ endif
pair.
{% if user.is_authenticated %} <h1>Welcome, {{ user.username }}</h1> {% else %} <h1>Welcome, guest</h1> {% endif %}
In this case, only one of the header tags will render depending on whether the user is authenticated or not.
The other core tag
to consider
is the for
loop tag.
A for
loop
in Django templates
behaves as you might expect.
<p>Prices:</p> <ul> {% for item in items %} <li>{{ item.name }} costs {{ item.price }}.</li> {% endfor %} </ul>
Django will loop over iterables
like lists
and let users output template responses
for each entry in an interable.
If the example above had a list
of items
in the context like:
items = [ {'name': 'Pizza', 'price': '$12.99'}, {'name': 'Soda', 'price': '$3.99'}, ]
Then the output would look roughly like:
<p>Prices:</p> <ul> <li>Pizza costs $12.99.</li> <li>Soda costs $3.99.</li> </ul>
Occasionally,
you may want to take some specific action
on a particular element
in the for loop.
Python’s built in enumerate
function isn’t available directly
in templates,
but a special variable called forloop
is available
inside of a for
tag.
This forloop
variable has some attributes
like first
and last
that you can use to make templates behave differently
on certain loop iterations.
Counting: {% for number in first_three_numbers %} {{ number }}{% if forloop.last %} is last!{% endif %} {% endfor %}
This example would produce:
Counting: 1 2 3 is last!
Equipped with variables, if
tags,
and for
tags,
you should now have the ability to make some fairly powerful templates,
but there’s more!
More Context On Context
In the setup of the templates settings, we glossed over context processors. Context processors are a valuable way to extend the context that is available to your templates when they are rendered.
Here’s the set of context processors
that Django’s startproject
command brings in
by default.
'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ],
Context processors are functions
(technically, callables, but let’s focus on functions)
that receive an HttpRequest
and must return a dictionary.
The returned dictionary merges
with any other context
that will be passed to your template.
We can look
at the actual definition of the request
context processor included
in that default list.
# django/template/context_processors.py def request(request): return {'request': request}
That’s it!
Because of this context processor,
the request
object will be available
as a variable
to any template
in your project.
That’s super powerful.
Sidebar
Don't be afraid to look at the source code of the projects that you depend on. Remember that regular people wrote your favorite frameworks! You can learn valuable lessons from what they did. The code might be a little intimidating at first, but there is no magic going on!
The “dark side” of context processors is that they run for all requests. If you write a context processor that is slow and does a lot of computation, every request will suffer that performance impact. So use context processors carefully.
Reusable Chunks Of Templates
Now let’s talk about one of the powerhouse features of the template system: reusable pieces.
Think about a website. Most pages have a similar look and feel. They do this by repeating a lot of the same HTML, which is Hypertext Markup Language that defines the structure of a page. These pages also use the same CSS, Cascading Style Sheets, which define the styles that shape the look of the page elements.
Imagine you’re asked to manage a site and you need to create two separate pages. The home page looks like:
<!DOCTYPE html> <html> <head> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <h1>Hello from the Home page</h1> </body> </html>
And here is a page to learn about the company behind the website.
<!DOCTYPE html> <html> <head> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <h1>Learn about our company</h1> </body> </html>
These examples are tiny amounts of HTML,
but what if you’re asked to change the stylesheet
from styles.css
to a new stylesheet made
by a designer called better_styles.css
?
You would have to update both places.
Now think if there were 2,000 pages
instead of 2 pages.
Making big changes quickly across a site would be virtually impossible!
Django helps you avoid this scenario entirely
with a few tags.
Let’s make a new template called base.html
.
<!DOCTYPE html> <html> <head> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> {% block main %}{% endblock %} </body> </html>
We’ve created a reusable template with the block
tag!
We can fix up our home page
to use this new template.
{% extends "base.html" %} {% block main %} <h1>Hello from the Home page</h1> {% endblock %}
This new version of the home page extends
the base template.
All the template had to do was define its own version
of the main
block
to fill in the content.
We could do the exact same thing with the about page.
If we revisit the task of replacing styles.css
with better_styles.css
,
we can make the update in base.html
and have that change apply
to any templates
that extend it.
Even if there were 2,000 pages
that all extended from base.html
,
changing the stylesheet would still be one line
of code
to change
for an entire site.
That’s the power of Django’s template extension system.
Another powerful tool for reuse is the include
tag.
The include
tag is useful
when you want to extract some chunk
of template
that you want to use
in multiple locations.
You may want to use include
to:
- Keep templates tidy. You can break a large template up into small pieces that are more manageable.
- Use a template fragment in different parts of your site. Maybe you have a piece of template that should only appear on a few pages.
Coming back to our website example,
imagine that base.html
grew to be 20,000 lines long.
Navigating to the right part
of the template
to make changes
is now harder.
We can decompose the template
into smaller pieces.
<!DOCTYPE html> <html> {% include "head.html" %} <body> {% include "navigation.html" %} {% block main %}{% endblock %} </body> {% include "footer.html" %} </html>
The include
tag can move those extra pieces around.
By providing good name to your templates,
if you needed to change the structure of some section
like navigation,
you could go to the template
with the appropriate name.
That template file would focus
on only the element that you need to change.
block
, extends
, and include
are core tags
for keeping your user interface code
from sprawling all over the place
with lots of duplication.
Next, let’s talk about more of Django’s built-in template tags that can supercharge your UI.
The Templates Toolbox
The Django documentation includes a large set of built-in tags that you can use in your projects. We aren’t going to cover all of them, but I’ll focus on a few tags to give you a flavor of what is available.
One of the most used built-in tags
aside from what we’ve already covered
is the url
tag.
Recall from the article
on URLs
that you can get the URL
to a named view
by using the reverse
function.
What if you wanted to use the URL
in your template?
You could do this:
# application/views.py from django.shortcuts import render from django.urls import reverse def the_view(request): context = {'the_url': reverse('a_named_view')} return render(request, 'a_template.html', context)
While this works,
it’s tedious to have to route all URLs
through the context.
Instead,
our template can directly create the proper URL.
Here’s what a_template.html
might look like instead:
<a href="{% url "a_named_view" %}">Go to a named view</a>
The url
tag is the template equivalent
of the reverse
function.
Like its reverse
counterpart, url
can accept args or kwargs
for routes
that expect other variables. url
is an incredibly useful tool
and one that you will probably reach for many times
as you build your user interface.
Another useful tag is the now
tag. now
is a convenient method
to display information
about the current time.
Using what Django calls format specifiers
,
you can tell your template how to display the current time.
Want to add a current copyright year to your website?
No problem!
© {% now "Y" %} Your Company LLC.
One final built-in tag to consider is the spaceless
tag.
HTML is partially
sensitive to whitespace.
There are some frustrating circumstances
where this whitspace sensitivity can ruin your day
when building a user interface.
Can you make a pixel perfect navigation menu
for your site with an unordered list?
Maybe. Consider this:
<ul> <li><a href="/home/">Home</a></li> <li><a href="/about/">About</a></li> </ul>
The indented whitespace on those list items
(or the new line characters that follow them)
might cause you trouble
when working with CSS.
Knowing that the whitespace can affect layout,
we can use spaceless
like so:
{% spaceless %} <ul> <li><a href="/home/">Home</a></li> <li><a href="/about/">About</a></li> </ul> {% endspaceless %}
This neat little template tag will remove all the spaces between HTML tags so your output looks like:
<ul><li><a href="/home/">Home</a></li>...</ul>
By removing the extra space, you may get a more consistent experience with your CSS styling and save yourself some frustration. (I had to trim the output to fit better on the screen.)
There is another kind of built-in that we have not looked at yet. These alternative built-in functions are called filters . Filters change the output of variables in your templates. The filter syntax is a bit interesting. It looks like:
Here's a filter example: {{ a_variable|some_filter:"filter arguments" }}
The important element is the pipe character directly
after a variable.
This character signals to the template system
that we want to modify the variable
with some kind of transformation.
Also observe that filters are used
between double curly braces
instead of the {%
syntax
that we’ve seen with tags.
A very common filter is the date
filter.
When you pass a Python datetime
instance
in the context,
you can use the date
filter
to control the format
of the datetime.
The date
documentation
shows
what options you can use
to modify the format.
{{ a_datetime|date:"Y-m-d" }}
If a_datetime
was an instance of April Fools’ Day,
then it could return a string like 2020-04-01
.
The date
filter has many specifiers
that will enable you to produce most date formatting outputs
that you could think of.
default
is a useful filter
for when your template value evaluates to False
.
This is perfect when you’ve got a variable
with an empty string.
The example below outputs “Nothing to see here”
if the variable was Falsy.
{{ a_variable|default:"Nothing to see here." }}
length
is a simple filter
for lists. {{ a_list_variable|length }}
will produce a number.
It is the Django template equivalent to the len
function.
I like the linebreaks
filter a lot.
If you create a form
(which we’ll explore in the next article)
and accept a text area field where the user is allowed
to provide newlines,
then the linebreaks
filter is great
if you want to display those newlines later
when rendering the user’s data.
By default,
HTML will not show new line characters as intended.
The linebreaks
filter will convert \n
to a <br>
HTML tag.
Handy!
Before moving on, let’s consider two more.
pluralize
is a convenient tag
for the times when your text considers counts
of things. Consider a count of items.
{{ count_items }} item{{ count_items|pluralize }}
The pluralize
tag will do the right thing
if there are zero, one, or more items
in the list.
0 items 1 item 2 items 3 items (and so on)
The final tag in our tour is the yesno
tag. yesno
is good for converting True|False|None
into a meaningful text message.
Imagine we’re making an application
for tracking events
and a person’s attendance is one
of those three values.
Our template might look like:
{{ user.name }} has {{ user_accepted|yesno:"accepted,declined,not RSVPed" }}.
Depending on the value of user_accepted
,
the template will display something meaningful
to a reader.
There are so many built-ins that’s it’s really hard to narrow down my favorites. Check out the full list to see what might be useful for you.
What if the built-ins don’t cover what you need? Have no fear, Django let’s you make custom tags and filters for your own purposes. We’ll see how next.
Build Your Own Lightsaber In Templates
When you need to build your own template tags or filters, Django gives you the tools to make what you need.
There are three major elements to working with custom tags:
- Defining your tags in a place that Django expects.
- Registering your tags with the template engine.
- Loading your tags in a template so they can be used.
The first step is to put the tags
in the correct location.
To do that,
we need a templatetags
Python package
inside of a Django application.
We also need a module
in that directory.
Choose the module name carefully
because it is what we will load
in the template later on.
application ├── templatetags │ ├── __init__.py │ └── custom_tags.py ├── __init__.py ├── ... ├── models.py └── views.py
Next, we need to make our tag or filter and register it. Let’s start with a filter example.
# application/templatetags/custom_tags.py import random from django import template register = template.Library() @register.filter def add_pizzazz(value): pieces_of_flair = [' Amazing!', ' Wowza!', ' Unbelievable!'] return value + random.choice(pieces_of_flair)
Now,
if we have a message
variable,
we can give it some pizzazz.
To use the custom filter,
we must load our tags module
into the template
with the load
tag.
{% load custom_tags %} {{ message|add_pizzazz }}
If our message was “You got a perfect score!”, then our template should show the message and one of the three random choices like “You got a perfect score! Wowza!”
Writing basic custom tags is very similar to custom filters. Code will speak better than words here.
# application/templatetags/custom_tags.py import random from django import template register = template.Library() @register.simple_tag def champion_welcome(name, level): if level > 42: welcome = f"Hello great champion {name}!" elif level > 20: welcome = f"Greetings noble warrior {name}!" elif level > 5: welcome = f"Hello {name}." else: welcome = "Oh, it's you." return welcome
We can load the custom tags and use our tag like any other built-in tag.
{% load custom_tags %} {% champion_welcome "He-Man" 50 %}
This silly welcome tag will respond to multiple input variables and vary depending on the provided level. The example usage should display “Hello great champion He-Man!”
We’re only looking at the most common kinds of custom tags in our examples. There are some more advanced custom tagging features which you can explore in the Django custom template tags documentation .
Summary
Now we’ve seen templates in action! We’ve looked at:
- How to set up templates for your site
- Ways to call templates from views
- How to use data
- How to handle logic
- Built-in tags and filters available to templates
- Customizing templates with your own code extensions
In the next article, we are going to examine how users can send data to a Django application with HTML forms. Django has tools to make form building quick and effective. We’re going to see:
Form
If you’d like to follow along with the series, please feel free to sign up for my newsletter where I announce all of my new content. If you have other questions, you can reach me online on Twitter where I am @mblayman .
以上所述就是小编给大家介绍的《Templates For User Interfaces》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
React Native开发指南
[美]艾森曼 / 黄为伟 / 人民邮电出版社 / 2016-6-1 / CNY 59.00
本书通过丰富的示例和详细的讲解,介绍了React Native这款JavaScript框架。在React Native中利用现有的JavaScript和React知识,就可以开发和部署功能完备的、真正原生的移动应用,并同时支持iOS与Android平台。除了框架本身的概念讲解之外,本书还讨论了如何使用第三方库,以及如何编写自己的Java或Objective-C的React Native扩展。一起来看看 《React Native开发指南》 这本书的介绍吧!