mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Updated HTML docs.
This commit is contained in:
parent
59e50f3fa5
commit
06bc3c8bcd
663 changed files with 2 additions and 61705 deletions
|
|
@ -1,230 +0,0 @@
|
|||
# Web Character View Tutorial
|
||||
|
||||
|
||||
**Before doing this tutorial you will probably want to read the intro in [Basic Web tutorial](Web-
|
||||
Tutorial).**
|
||||
|
||||
In this tutorial we will create a web page that displays the stats of a game character. For this,
|
||||
and all other pages we want to make specific to our game, we'll need to create our own Django "app"
|
||||
|
||||
We'll call our app `character`, since it will be dealing with character information. From your game
|
||||
dir, run
|
||||
|
||||
evennia startapp character
|
||||
|
||||
This will create a directory named `character` in the root of your game dir. It contains all basic
|
||||
files that a Django app needs. To keep `mygame` well ordered, move it to your `mygame/web/`
|
||||
directory instead:
|
||||
|
||||
mv character web/
|
||||
|
||||
Note that we will not edit all files in this new directory, many of the generated files are outside
|
||||
the scope of this tutorial.
|
||||
|
||||
In order for Django to find our new web app, we'll need to add it to the `INSTALLED_APPS` setting.
|
||||
Evennia's default installed apps are already set, so in `server/conf/settings.py`, we'll just extend
|
||||
them:
|
||||
|
||||
```python
|
||||
INSTALLED_APPS += ('web.character',)
|
||||
```
|
||||
|
||||
> Note: That end comma is important. It makes sure that Python interprets the addition as a tuple
|
||||
instead of a string.
|
||||
|
||||
The first thing we need to do is to create a *view* and an *URL pattern* to point to it. A view is a
|
||||
function that generates the web page that a visitor wants to see, while the URL pattern lets Django
|
||||
know what URL should trigger the view. The pattern may also provide some information of its own as
|
||||
we shall see.
|
||||
|
||||
Here is our `character/urls.py` file (**Note**: you may have to create this file if a blank one
|
||||
wasn't generated for you):
|
||||
|
||||
```python
|
||||
# URL patterns for the character app
|
||||
|
||||
from django.urls import path
|
||||
from web.character.views import sheet
|
||||
|
||||
urlpatterns = [
|
||||
path("sheet/<int:object_id>", sheet, name="sheet")
|
||||
]
|
||||
```
|
||||
|
||||
This file contains all of the URL patterns for the application. The `url` function in the
|
||||
`urlpatterns` list are given three arguments. The first argument is a pattern-string used to
|
||||
identify which URLs are valid. Patterns are specified as *regular expressions*. Regular expressions
|
||||
are used to match strings and are written in a special, very compact, syntax. A detailed description
|
||||
of regular expressions is beyond this tutorial but you can learn more about them
|
||||
[here](https://docs.python.org/2/howto/regex.html). For now, just accept that this regular
|
||||
expression requires that the visitor's URL looks something like this:
|
||||
|
||||
````
|
||||
sheet/123/
|
||||
````
|
||||
|
||||
That is, `sheet/` followed by a number, rather than some other possible URL pattern. We will
|
||||
interpret this number as object ID. Thanks to how the regular expression is formulated, the pattern
|
||||
recognizer stores the number in a variable called `object_id`. This will be passed to the view (see
|
||||
below). We add the imported view function (`sheet`) in the second argument. We also add the `name`
|
||||
keyword to identify the URL pattern itself. You should always name your URL patterns, this makes
|
||||
them easy to refer to in html templates using the `{% url %}` tag (but we won't get more into that
|
||||
in this tutorial).
|
||||
|
||||
> Security Note: Normally, users do not have the ability to see object IDs within the game (it's
|
||||
restricted to superusers only). Exposing the game's object IDs to the public like this enables
|
||||
griefers to perform what is known as an [account enumeration
|
||||
attack](http://www.sans.edu/research/security-laboratory/article/attacks-browsing) in the efforts of
|
||||
hijacking your superuser account. Consider this: in every Evennia installation, there are two
|
||||
objects that we can *always* expect to exist and have the same object IDs-- Limbo (#2) and the
|
||||
superuser you create in the beginning (#1). Thus, the griefer can get 50% of the information they
|
||||
need to hijack the admin account (the admin's username) just by navigating to `sheet/1`!
|
||||
|
||||
Next we create `views.py`, the view file that `urls.py` refers to.
|
||||
|
||||
```python
|
||||
# Views for our character app
|
||||
|
||||
from django.http import Http404
|
||||
from django.shortcuts import render
|
||||
from django.conf import settings
|
||||
|
||||
from evennia.utils.search import object_search
|
||||
from evennia.utils.utils import inherits_from
|
||||
|
||||
def sheet(request, object_id):
|
||||
object_id = '#' + object_id
|
||||
try:
|
||||
character = object_search(object_id)[0]
|
||||
except IndexError:
|
||||
raise Http404("I couldn't find a character with that ID.")
|
||||
if not inherits_from(character, settings.BASE_CHARACTER_TYPECLASS):
|
||||
raise Http404("I couldn't find a character with that ID. "
|
||||
"Found something else instead.")
|
||||
return render(request, 'character/sheet.html', {'character': character})
|
||||
```
|
||||
|
||||
As explained earlier, the URL pattern parser in `urls.py` parses the URL and passes `object_id` to
|
||||
our view function `sheet`. We do a database search for the object using this number. We also make
|
||||
sure such an object exists and that it is actually a Character. The view function is also handed a
|
||||
`request` object. This gives us information about the request, such as if a logged-in user viewed it
|
||||
- we won't use that information here but it is good to keep in mind.
|
||||
|
||||
On the last line, we call the `render` function. Apart from the `request` object, the `render`
|
||||
function takes a path to an html template and a dictionary with extra data you want to pass into
|
||||
said template. As extra data we pass the Character object we just found. In the template it will be
|
||||
available as the variable "character".
|
||||
|
||||
The html template is created as `templates/character/sheet.html` under your `character` app folder.
|
||||
You may have to manually create both `template` and its subfolder `character`. Here's the template
|
||||
to create:
|
||||
|
||||
````html
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<h1>{{ character.name }}</h1>
|
||||
|
||||
<p>{{ character.db.desc }}</p>
|
||||
|
||||
<h2>Stats</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Stat</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Strength</td>
|
||||
<td>{{ character.db.str }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Intelligence</td>
|
||||
<td>{{ character.db.int }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Speed</td>
|
||||
<td>{{ character.db.spd }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>Skills</h2>
|
||||
<ul>
|
||||
{% for skill in character.db.skills %}
|
||||
<li>{{ skill }}</li>
|
||||
{% empty %}
|
||||
<li>This character has no skills yet.</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% if character.db.approved %}
|
||||
<p class="success">This character has been approved!</p>
|
||||
{% else %}
|
||||
<p class="warning">This character has not yet been approved!</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
````
|
||||
|
||||
In Django templates, `{% ... %}` denotes special in-template "functions" that Django understands.
|
||||
The `{{ ... }}` blocks work as "slots". They are replaced with whatever value the code inside the
|
||||
block returns.
|
||||
|
||||
The first line, `{% extends "base.html" %}`, tells Django that this template extends the base
|
||||
template that Evennia is using. The base template is provided by the theme. Evennia comes with the
|
||||
open-source third-party theme `prosimii`. You can find it and its `base.html` in
|
||||
`evennia/web/templates/prosimii`. Like other templates, these can be overwritten.
|
||||
|
||||
The next line is `{% block content %}`. The `base.html` file has `block`s, which are placeholders
|
||||
that templates can extend. The main block, and the one we use, is named `content`.
|
||||
|
||||
We can access the `character` variable anywhere in the template because we passed it in the `render`
|
||||
call at the end of `view.py`. That means we also have access to the Character's `db` attributes,
|
||||
much like you would in normal Python code. You don't have the ability to call functions with
|
||||
arguments in the template-- in fact, if you need to do any complicated logic, you should do it in
|
||||
`view.py` and pass the results as more variables to the template. But you still have a great deal of
|
||||
flexibility in how you display the data.
|
||||
|
||||
We can do a little bit of logic here as well. We use the `{% for %} ... {% endfor %}` and `{% if %}
|
||||
... {% else %} ... {% endif %}` structures to change how the template renders depending on how many
|
||||
skills the user has, or if the user is approved (assuming your game has an approval system).
|
||||
|
||||
The last file we need to edit is the master URLs file. This is needed in order to smoothly integrate
|
||||
the URLs from your new `character` app with the URLs from Evennia's existing pages. Find the file
|
||||
`web/website/urls.py` and update its `patterns` list as follows:
|
||||
|
||||
```python
|
||||
# web/website/urls.py
|
||||
|
||||
urlpatterns = [
|
||||
# ...
|
||||
path("character/", include('web.character.urls'))
|
||||
]
|
||||
```
|
||||
|
||||
Now reload the server with `evennia reload` and visit the page in your browser. If you haven't
|
||||
changed your defaults, you should be able to find the sheet for character `#1` at
|
||||
`http://localhost:4001/character/sheet/1/`
|
||||
|
||||
Try updating the stats in-game and refresh the page in your browser. The results should show
|
||||
immediately.
|
||||
|
||||
As an optional final step, you can also change your character typeclass to have a method called
|
||||
'get_absolute_url'.
|
||||
```python
|
||||
# typeclasses/characters.py
|
||||
|
||||
# inside Character
|
||||
def get_absolute_url(self):
|
||||
from django.urls import reverse
|
||||
return reverse('character:sheet', kwargs={'object_id':self.id})
|
||||
```
|
||||
Doing so will give you a 'view on site' button in the top right of the Django Admin Objects
|
||||
changepage that links to your new character sheet, and allow you to get the link to a character's
|
||||
page by using `{{ object.get_absolute_url }}` in any template where you have a given object.
|
||||
|
||||
*Now that you've made a basic page and app with Django, you may want to read the full Django
|
||||
tutorial to get a better idea of what it can do. [You can find Django's tutorial
|
||||
here](https://docs.djangoproject.com/en/1.8/intro/tutorial01/).*
|
||||
Loading…
Add table
Add a link
Reference in a new issue