<p>Evennia offers many convenient ways to store object data, such as via Attributes or Scripts. This is sufficient for most use cases. But if you aim to build a large stand-alone system, trying to squeeze your storage requirements into those may be more complex than you bargain for. Examples may be to store guild data for guild members to be able to change, tracking the flow of money across a game-wide economic system or implement other custom game systems that requires the storage of custom data in a quickly accessible way.</p>
<p>Whereas <aclass="reference internal"href="../Components/Tags.html"><spanclass="doc std std-doc">Tags</span></a> or <aclass="reference internal"href="../Components/Scripts.html"><spanclass="doc std std-doc">Scripts</span></a> can handle many situations, sometimes things may be easier to handle by adding your own <em>database model</em>.</p>
<p>Each line is considerably longer in your database. Each column is referred to as a “field” and every row is a separate object. You can check this out for yourself. If you use the default sqlite3 database, go to your game folder and run</p>
<p>Evennia uses <aclass="reference external"href="https://docs.djangoproject.com">Django</a>, which abstracts away the database SQL manipulation and allows you to search and manipulate your database entirely in Python. Each database table is in Django represented by a class commonly called a <em>model</em> since it describes the look of the table. In Evennia, Objects, Scripts, Channels etc are examples of Django models that we then extend and build on.</p>
<li><p>In Django lingo, we will create a new “application” - a subsystem under the main Evennia program. For this example we’ll call it “myapp”. Run the following (you need to have a working Evennia running before you do this, so make sure you have run the steps in [Setup Quickstart](Getting- Started) first):</p>
<li><p>A new folder <codeclass="docutils literal notranslate"><spanclass="pre">myapp</span></code> is created. “myapp” will also be the name (the “app label”) from now on. We move it into the <codeclass="docutils literal notranslate"><spanclass="pre">world/</span></code> subfolder here, but you could keep it in the root of your <codeclass="docutils literal notranslate"><spanclass="pre">mygame</span></code> if that makes more sense. 1. The <codeclass="docutils literal notranslate"><spanclass="pre">myapp</span></code> folder contains a few empty default files. What we are interested in for now is <codeclass="docutils literal notranslate"><spanclass="pre">models.py</span></code>. In <codeclass="docutils literal notranslate"><spanclass="pre">models.py</span></code> you define your model(s). Each model will be a table in the database. See the next section and don’t continue until you have added the models you want.</p></li>
<li><p>You now need to tell Evennia that the models of your app should be a part of your database scheme. Add this line to your <codeclass="docutils literal notranslate"><spanclass="pre">mygame/server/conf/settings.py</span></code>file (make sure to use the path where you put <codeclass="docutils literal notranslate"><spanclass="pre">myapp</span></code> and don’t forget the comma at the end of the tuple):</p>
<p>This will add your new database table to the database. If you have put your game under version control (if not, <aclass="reference internal"href="../Coding/Version-Control.html"><spanclass="doc std std-doc">you should</span></a>), don’t forget to <codeclass="docutils literal notranslate"><spanclass="pre">git</span><spanclass="pre">add</span><spanclass="pre">myapp/*</span></code> to add all items
<p>A Django <em>model</em> is the Python representation of a database table. It can be handled like any other Python class. It defines <em>fields</em> on itself, objects of a special type. These become the “columns” of the database table. Finally, you create new instances of the model to add new rows to the database.</p>
<p>We won’t describe all aspects of Django models here, for that we refer to the vast <aclass="reference external"href="https://docs.djangoproject.com/en/4.1/topics/db/models/">Django documentation</a> on the subject. Here is a (very) brief example:</p>
<div><p>The <codeclass="docutils literal notranslate"><spanclass="pre">db_date_created</span></code> field, with exactly this name, is <em>required</em> if you want to be able to store instances of your custom model in an Evennia <aclass="reference internal"href="../Components/Attributes.html"><spanclass="doc std std-doc">Attribute</span></a>. It will automatically be set upon creation and can after that not be changed. Having this field will allow you to do e.g. <codeclass="docutils literal notranslate"><spanclass="pre">obj.db.myinstance</span><spanclass="pre">=</span><spanclass="pre">mydatastore</span></code>. If you know you’ll never store your model instances in Attributes the <codeclass="docutils literal notranslate"><spanclass="pre">db_date_created</span></code> field is optional.</p>
<p>You don’t <em>have</em> to start field names with <codeclass="docutils literal notranslate"><spanclass="pre">db_</span></code>, this is an Evennia convention. It’s nevertheless recommended that you do use <codeclass="docutils literal notranslate"><spanclass="pre">db_</span></code>, partly for clarity and consistency with Evennia (if you ever want to share your code) and partly for the case of you later deciding to use Evennia’s
<p>The field keyword <codeclass="docutils literal notranslate"><spanclass="pre">db_index</span></code> creates a <em>database index</em> for this field, which allows quicker lookups, so it’s recommended to put it on fields you know you’ll often use in queries. The <codeclass="docutils literal notranslate"><spanclass="pre">null=True</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">blank=True</span></code> keywords means that these fields may be left empty or set to the empty string without the database complaining. There are many other field types and keywords to define them, see django docs for more info.</p>
<p>Similar to using <aclass="reference external"href="https://docs.djangoproject.com/en/4.1/howto/legacy-databases/">django-admin</a> you are able to do <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">inspectdb</span></code> to get an automated listing of model information for an existing database. As is the case with any model generating tool you should only use this as a starting
<h2>Referencing existing models and typeclasses<aclass="headerlink"href="#referencing-existing-models-and-typeclasses"title="Permalink to this headline">¶</a></h2>
<p>You may want to use <codeclass="docutils literal notranslate"><spanclass="pre">ForeignKey</span></code> or <codeclass="docutils literal notranslate"><spanclass="pre">ManyToManyField</span></code> to relate your new model to existing ones.</p>
<p>To do this we need to specify the app-path for the root object type we want to store as a string (we must use a string rather than the class directly or you’ll run into problems with models not having been initialized yet).</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">"objects.ObjectDB"</span></code> for all <aclass="reference internal"href="../Components/Objects.html"><spanclass="doc std std-doc">Objects</span></a> (like exits, rooms, characters etc)</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">"accounts.AccountDB"</span></code> for <aclass="reference internal"href="../Components/Accounts.html"><spanclass="doc std std-doc">Accounts</span></a>.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">"scripts.ScriptDB"</span></code> for <aclass="reference internal"href="../Components/Scripts.html"><spanclass="doc std std-doc">Scripts</span></a>.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">"comms.ChannelDB"</span></code> for <aclass="reference internal"href="../Components/Channels.html"><spanclass="doc std std-doc">Channels</span></a>.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">"comms.Msg"</span></code> for <aclass="reference internal"href="../Components/Msg.html"><spanclass="doc std std-doc">Msg</span></a> objects.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">"help.HelpEntry"</span></code> for <aclass="reference internal"href="../Components/Help-System.html"><spanclass="doc std std-doc">Help Entries</span></a>.</p></li>
<p>It may seem counter-intuitive, but this will work correctly:</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>myspecial.db_character = my_character # a Character instance
my_character = myspecial.db_character # still a Character
</pre></div>
</div>
<p>This works because when the <codeclass="docutils literal notranslate"><spanclass="pre">.db_character</span></code> field is loaded into Python, the entity itself knows that it’s supposed to be a <codeclass="docutils literal notranslate"><spanclass="pre">Character</span></code> and loads itself to that form.</p>
<p>The drawback of this is that the database won’t <em>enforce</em> the type of object you store in the relation. This is the price we pay for many of the other advantages of the Typeclass system.</p>
<p>While the <codeclass="docutils literal notranslate"><spanclass="pre">db_character</span></code> field fail if you try to store an <codeclass="docutils literal notranslate"><spanclass="pre">Account</span></code>, it will gladly accept any instance of a typeclass that inherits from <codeclass="docutils literal notranslate"><spanclass="pre">ObjectDB</span></code>, such as rooms, exits or other non-character Objects. It’s up to you to validate that what you store is what you expect it to be.</p>
<h2>Creating a new model instance<aclass="headerlink"href="#creating-a-new-model-instance"title="Permalink to this headline">¶</a></h2>
<p>To create a new row in your table, you instantiate the model and then call its <codeclass="docutils literal notranslate"><spanclass="pre">save()</span></code> method:</p>
<p>Note that the <codeclass="docutils literal notranslate"><spanclass="pre">db_date_created</span></code> field of the model is not specified. Its flag <codeclass="docutils literal notranslate"><spanclass="pre">at_now_add=True</span></code> makes sure to set it to the current date when the object is created (it can also not be changed further after creation).</p>
<p>When you update an existing object with some new field value, remember that you have to save the object afterwards, otherwise the database will not update:</p>
<p>Evennia’s normal models don’t need to explicitly save, since they are based on <codeclass="docutils literal notranslate"><spanclass="pre">SharedMemoryModel</span></code> rather than the raw django model. This is covered in the next section.</p>
<h2>Using the <codeclass="docutils literal notranslate"><spanclass="pre">SharedMemoryModel</span></code> parent<aclass="headerlink"href="#using-the-sharedmemorymodel-parent"title="Permalink to this headline">¶</a></h2>
<p>Evennia doesn’t base most of its models on the raw <codeclass="docutils literal notranslate"><spanclass="pre">django.db.models.Model</span></code> but on the Evennia base model <codeclass="docutils literal notranslate"><spanclass="pre">evennia.utils.idmapper.models.SharedMemoryModel</span></code>. There are two main reasons for this:</p>
<li><p>Ease of updating fields without having to explicitly call <codeclass="docutils literal notranslate"><spanclass="pre">save()</span></code></p></li>
<li><p>On-object memory persistence and database caching</p></li>
<p>The first (and least important) point means that as long as you named your fields <codeclass="docutils literal notranslate"><spanclass="pre">db_*</span></code>, Evennia will automatically create field wrappers for them. This happens in the model’s <aclass="reference external"href="http://en.wikibooks.org/wiki/Python_Programming/Metaclasses">Metaclass</a> so there is no speed penalty for this. The name of the wrapper will be the same name as the field, minus the <codeclass="docutils literal notranslate"><spanclass="pre">db_</span></code> prefix. So the <codeclass="docutils literal notranslate"><spanclass="pre">db_key</span></code> field will have a wrapper property named <codeclass="docutils literal notranslate"><spanclass="pre">key</span></code>. You can then do:</p>
<p>and don’t have to explicitly call <codeclass="docutils literal notranslate"><spanclass="pre">save()</span></code> afterwards. The saving also happens in a more efficient way under the hood, updating only the field rather than the entire model using django optimizations. Note that if you were to manually add the property or method <codeclass="docutils literal notranslate"><spanclass="pre">key</span></code> to your model, this will be used instead of the automatic wrapper and allows you to fully customize access as needed.</p>
<p>To explain the second and more important point, consider the following example using the default Django model parent:</p>
<spanclass="n">shield</span><spanclass="o">.</span><spanclass="n">cracked</span><spanclass="o">=</span><spanclass="kc">True</span><spanclass="c1"># where cracked is not a database field</span>
<p>The outcome of that last print statement is <em>undefined</em>! It could <em>maybe</em> randomly work but most likely you will get an <codeclass="docutils literal notranslate"><spanclass="pre">AttributeError</span></code> for not finding the <codeclass="docutils literal notranslate"><spanclass="pre">cracked</span></code> property. The reason is that <codeclass="docutils literal notranslate"><spanclass="pre">cracked</span></code> doesn’t represent an actual field in the database. It was just added at run-time and thus Django don’t care about it. When you retrieve your shield-match later there is <em>no</em> guarantee you will get back the <em>same Python instance</em> of the model where you defined <codeclass="docutils literal notranslate"><spanclass="pre">cracked</span></code>, even if you search for the same database object.</p>
<p>Evennia relies heavily on on-model handlers and other dynamically created properties. So rather than using the vanilla Django models, Evennia uses <codeclass="docutils literal notranslate"><spanclass="pre">SharedMemoryModel</span></code>, which levies something called <em>idmapper</em>. The idmapper caches model instances so that we will always get the <em>same</em> instance back after the first lookup of a given object. Using idmapper, the above example would work fine and you could retrieve your <codeclass="docutils literal notranslate"><spanclass="pre">cracked</span></code> property at any time - until you rebooted when all non-persistent data goes.</p>
reading from disk. The drawback is that this system tends to be more memory hungry <em>overall</em>. So if you know that you’ll <em>never</em> need to add new properties to running instances or know that you will create new objects all the time yet rarely access them again (like for a log system), you are probably better off making “plain” Django models rather than using <codeclass="docutils literal notranslate"><spanclass="pre">SharedMemoryModel</span></code> and its idmapper.</p>
<p>To use the idmapper and the field-wrapper functionality you just have to have your model classes inherit from <codeclass="docutils literal notranslate"><spanclass="pre">evennia.utils.idmapper.models.SharedMemoryModel</span></code> instead of from the default <codeclass="docutils literal notranslate"><spanclass="pre">django.db.models.Model</span></code>:</p>
<p>To search your new custom database table you need to use its database <em>manager</em> to build a <em>query</em>. Note that even if you use <codeclass="docutils literal notranslate"><spanclass="pre">SharedMemoryModel</span></code> as described in the previous section, you have to use the actual <em>field names</em> in the query, not the wrapper name (so <codeclass="docutils literal notranslate"><spanclass="pre">db_key</span></code> and not just <codeclass="docutils literal notranslate"><spanclass="pre">key</span></code>).</p>
<p>See the <aclass="reference internal"href="../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Django-queries.html"><spanclass="doc std std-doc">Beginner Tutorial lesson on Django querying</span></a> for a lot more information about querying the database.</p>