Django templates has a few special features that separate them from normal HTML
documents - they contain a special templating language marked with `{% ... %}` and
`{{ ... }}`.
Some important things to know:
-`{% extends "base.html" %}` - This is equivalent to a Python
`from othermodule import *` statement, but for templates. It allows a given template
to use everything from the imported (extended) template, but also to override anything
it wants to change. This makes it easy to keep all pages looking the same and avoids
a lot of boiler plate.
-`{% block blockname %}...{% endblock %}` - Blocks are inheritable, named pieces of code
that are modified in one place and then used elsewhere. This works a bit in reverse to
normal inheritance, because it's commonly in such a way that `base.html` defines an empty
block, let's say `contents`: `{% block contents %}{% endblock %}` but makes sure to put
that _in the right place_, say in the main body, next to the sidebar etc. Then each page
does `{% extends "base.html %"}` and makes their own `{% block contents} <actual content> {% endblock %}`.
Their `contents` block will now override the empty one in `base.html` and appear in the right
place in the document, without the extending template having to specifying everything else
around it!
-`{{ ... }}` are 'slots' usually embedded inside HTML tags or content. They reference a
_context_ (basically a dict) that the Python _view_ makes available to it.
Keys on the context are accessed with dot-notation, so if you provide a
context `{"stats": {"hp": 10, "mp": 5}}` to your template, you could access
that as `{{ stats.hp }}` to display `10` at that location to display `10` at
that location.
This allows for template inheritance (making it easier to make all
pages look the same without rewriting the same thing over and over)
There's a lot more information to be found in the [Django template language documentation](https://docs.djangoproject.com/en/3.2/ref/templates/language/).
The frontpage view is a class `EvenniaIndexView`. This is a [Django class-based view](https://docs.djangoproject.com/en/3.2/topics/class-based-views/).
It's a little less visible what happens in a class-based view than in a function (since
the class implements a lot of functionality as methods), but it's powerful and
much easier to extend/modify.
The class property `template_name` sets the location of the template used under
the `templates/` folder. So `website/index.html` points to
`web/templates/website/index.html` (as we already explored above.
The `get_context_data` is a convenient method for providing the context for the
template. In the index-page's case we want the game stats (number of recent
players etc). These are then made available to use in `{{ ... }}` slots in the
For the `Flat pages` module to work you must first set up a _Site_ (or
domain) to use. You only need to this once.
- Go to the Web admin and select `Sites`. If your
game is at `mygreatgame.com`, that's the domain you need to add. For local
experimentation, add the domain `localhost:4001`. Note the `id` of the domain
(look at the url when you click on the new domain, if it's for example
`http://localhost:4001/admin/sites/site/2/change/`, then the id is `2`).
- Now add the line `SITE_ID = <id>` to your settings file.
Next you create new pages easily.
- Go the `Flat Pages` web admin and choose to add a new flat page.
- Set the url. If you want the page to appear as e.g. `localhost:4001/test/`, then
add `/test/` here. You need to add both leading and trailing slashes.
- Set `Title` to the name of the page.
- The `Content` is the HTML content of the body of the page. Go wild!
- Finally pick the `Site` you made before, and save.
- (in the advanced section you can make it so that you have to login to see the page etc).
You can now go to `localhost:4001/test/` and see your new page!
### Add Custom new page
The `Flat Pages` page doesn't allow for (much) dynamic content and customization. For
this you need to add the needed components yourself.
Let's see how to make a `/test/` page from scratch.
- Add a new `test.html` file under `mygame/web/templates/website/`. Easiest is to base
this off an existing file. Make sure to `{% extend base.html %}` if you want to
get the same styling as the rest of your site.
- Add a new view `testview.py` under `mygame/web/website/views/` (don't name it `test.py` or
Django/Evennia will think it contains unit tests). Add a view there to process
your page. This is a minimal view to start from (read much more [in the Django docs](https://docs.djangoproject.com/en/3.2/topics/class-based-views/)):
```python
# mygame/web/website/views/testview.py
from django.views.generic import TemplateView
class MyTestView(TemplateView):
template_name = "website/test.html"
```
- Finally, point to your view from the `mygame/web/website/urls.py`:
```python
# in mygame/web/website/urls.py
# ...
from web.website.views import testview
urlpatterns = [
# ...
# we can skip the initial / here
path("test/", testview.MyTestView.as_view())
]
```
- Reload the server and your new page is available. You can now continue to add
all sorts of advanced dynamic content through your view and template!
## User forms
All the pages created so far deal with _presenting_ information to the user.
It's also possible for the user to _input_ data on the page through _forms_. An
example would be a page of fields and sliders you fill in to create a
character, with a big 'Submit' button at the bottom.
Firstly, this must be represented in HTML. The `<form> ... </form>` is a
standard HTML element you need to add to your template. It also has some other
requirements, such as `<input>` and often Javascript components as well (but
usually Django will help with this). If you are unfamiliar with how HTML forms
work, [read about them here](https://docs.djangoproject.com/en/3.2/topics/forms/#html-forms).
The basic gist of it is that when you click to 'submit' the form, a POST HTML
request will be sent to the server containing the data the user entered. It's
now up to the server to make sure the data makes sense (validation) and then
process the input somehow (like creating a new character).
On the backend side, we need to specify the logic for validating and processing
the form data. This is done by the `Form` [Django class](https://docs.djangoproject.com/en/3.2/topics/forms/#forms-in-django).
This specifies _fields_ on itself that define how to validate that piece of data.
The form is then linked into the view-class by adding `form_class = MyFormClass` to
the view (next to `template_name`).
There are several example forms in `evennia/web/website/forms.py`. It's also a good
idea to read [Building a form in Django](https://docs.djangoproject.com/en/3.2/topics/forms/#building-a-form-in-django)