evennia/docs/6.x/Concepts/Models.html
2026-02-15 19:06:04 +01:00

373 lines
No EOL
39 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en" data-content_root="../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title>New Models &#8212; Evennia latest documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=d75fae25" />
<link rel="stylesheet" type="text/css" href="../_static/nature.css?v=279e0f84" />
<link rel="stylesheet" type="text/css" href="../_static/custom.css?v=e4a91a55" />
<script src="../_static/documentation_options.js?v=c6e86fd7"></script>
<script src="../_static/doctools.js?v=9bcbadda"></script>
<script src="../_static/sphinx_highlight.js?v=dc90522c"></script>
<link rel="icon" href="../_static/favicon.ico"/>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="Zones" href="Zones.html" />
<link rel="prev" title="Protocols" href="Protocols.html" />
</head><body>
<div class="related" role="navigation" aria-label="Related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Zones.html" title="Zones"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Protocols.html" title="Protocols"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Concepts-Overview.html" accesskey="U">Core Concepts</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">New Models</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="new-models">
<h1>New Models<a class="headerlink" href="#new-models" title="Link to this heading"></a></h1>
<p><em>Note: This is considered an advanced topic.</em></p>
<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 <a class="reference internal" href="../Components/Tags.html"><span class="std std-doc">Tags</span></a> or <a class="reference internal" href="../Components/Scripts.html"><span class="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>
<section id="overview-of-database-tables">
<h2>Overview of database tables<a class="headerlink" href="#overview-of-database-tables" title="Link to this heading"></a></h2>
<p>SQL-type databases (which is what Evennia supports) are basically highly optimized systems for
retrieving text stored in tables. A table may look like this</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="nb">id</span> <span class="o">|</span> <span class="n">db_key</span> <span class="o">|</span> <span class="n">db_typeclass_path</span> <span class="o">|</span> <span class="n">db_permissions</span> <span class="o">...</span>
<span class="o">------------------------------------------------------------------</span>
<span class="mi">1</span> <span class="o">|</span> <span class="n">Griatch</span> <span class="o">|</span> <span class="n">evennia</span><span class="o">.</span><span class="n">DefaultCharacter</span> <span class="o">|</span> <span class="n">Developers</span> <span class="o">...</span>
<span class="mi">2</span> <span class="o">|</span> <span class="n">Rock</span> <span class="o">|</span> <span class="n">evennia</span><span class="o">.</span><span class="n">DefaultObject</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">...</span>
</pre></div>
</div>
<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>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> evennia dbshell
</pre></div>
</div>
<p>You will drop into the database shell. While there, try:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> sqlite&gt; .help # view help
sqlite&gt; .tables # view all tables
# show the table field names for objects_objectdb
sqlite&gt; .schema objects_objectdb
# show the first row from the objects_objectdb table
sqlite&gt; select * from objects_objectdb limit 1;
sqlite&gt; .exit
</pre></div>
</div>
<p>Evennia uses <a class="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>
</section>
<section id="adding-a-new-database-table">
<h2>Adding a new database table<a class="headerlink" href="#adding-a-new-database-table" title="Link to this heading"></a></h2>
<p>Here is how you add your own database table/models:</p>
<ol class="arabic">
<li><p>In Django lingo, we will create a new “application” - a subsystem under the main Evennia program. For this example well 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>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> evennia startapp myapp
mv myapp world (linux)
move myapp world (windows)
</pre></div>
</div>
</li>
<li><p>A new folder <code class="docutils literal notranslate"><span class="pre">myapp</span></code> is created. “myapp” will also be the name (the “app label”) from now on. We move it into the <code class="docutils literal notranslate"><span class="pre">world/</span></code> subfolder here, but you could keep it in the root of your <code class="docutils literal notranslate"><span class="pre">mygame</span></code> if that makes more sense. 1. The <code class="docutils literal notranslate"><span class="pre">myapp</span></code> folder contains a few empty default files. What we are interested in for now is <code class="docutils literal notranslate"><span class="pre">models.py</span></code>. In <code class="docutils literal notranslate"><span class="pre">models.py</span></code> you define your model(s). Each model will be a table in the database. See the next section and dont 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 <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code>file (make sure to use the path where you put <code class="docutils literal notranslate"><span class="pre">myapp</span></code> and dont forget the comma at the end of the tuple):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">INSTALLED_APPS</span> <span class="o">=</span> <span class="n">INSTALLED_APPS</span> <span class="o">+</span> <span class="p">(</span><span class="s2">&quot;world.myapp&quot;</span><span class="p">,</span> <span class="p">)</span>
</pre></div>
</div>
</li>
<li><p>From <code class="docutils literal notranslate"><span class="pre">mygame/</span></code>, run</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> evennia makemigrations myapp
evennia migrate myapp
</pre></div>
</div>
</li>
</ol>
<p>This will add your new database table to the database. If you have put your game under version control (if not, <a class="reference internal" href="../Coding/Version-Control.html"><span class="std std-doc">you should</span></a>), dont forget to <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">add</span> <span class="pre">myapp/*</span></code> to add all items
to version control.</p>
</section>
<section id="defining-your-models">
<h2>Defining your models<a class="headerlink" href="#defining-your-models" title="Link to this heading"></a></h2>
<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 wont describe all aspects of Django models here, for that we refer to the vast <a class="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 class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">django.db</span><span class="w"> </span><span class="kn">import</span> <span class="n">models</span>
<span class="k">class</span><span class="w"> </span><span class="nc">MyDataStore</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="s2">&quot;A simple model for storing some data&quot;</span>
<span class="n">db_key</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">80</span><span class="p">,</span> <span class="n">db_index</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">db_category</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">80</span><span class="p">,</span> <span class="n">null</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">blank</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">db_text</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">TextField</span><span class="p">(</span><span class="n">null</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">blank</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="c1"># we need this one if we want to be</span>
<span class="c1"># able to store this in an Evennia Attribute!</span>
<span class="n">db_date_created</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateTimeField</span><span class="p">(</span><span class="s1">&#39;date created&#39;</span><span class="p">,</span> <span class="n">editable</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">auto_now_add</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">db_index</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
<p>We create four fields: two character fields of limited length and one text field which has no
maximum length. Finally we create a field containing the current time of us creating this object.</p>
<blockquote>
<div><p>The <code class="docutils literal notranslate"><span class="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 <a class="reference internal" href="../Components/Attributes.html"><span class="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. <code class="docutils literal notranslate"><span class="pre">obj.db.myinstance</span> <span class="pre">=</span> <span class="pre">mydatastore</span></code>. If you know youll never store your model instances in Attributes the <code class="docutils literal notranslate"><span class="pre">db_date_created</span></code> field is optional.</p>
</div></blockquote>
<p>You dont <em>have</em> to start field names with <code class="docutils literal notranslate"><span class="pre">db_</span></code>, this is an Evennia convention. Its nevertheless recommended that you do use <code class="docutils literal notranslate"><span class="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 Evennias
<code class="docutils literal notranslate"><span class="pre">SharedMemoryModel</span></code> parent down the line.</p>
<p>The field keyword <code class="docutils literal notranslate"><span class="pre">db_index</span></code> creates a <em>database index</em> for this field, which allows quicker lookups, so its recommended to put it on fields you know youll often use in queries. The <code class="docutils literal notranslate"><span class="pre">null=True</span></code> and <code class="docutils literal notranslate"><span class="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 <a class="reference external" href="https://docs.djangoproject.com/en/4.1/howto/legacy-databases/">django-admin</a> you are able to do <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="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
point for your models.</p>
</section>
<section id="referencing-existing-models-and-typeclasses">
<h2>Referencing existing models and typeclasses<a class="headerlink" href="#referencing-existing-models-and-typeclasses" title="Link to this heading"></a></h2>
<p>You may want to use <code class="docutils literal notranslate"><span class="pre">ForeignKey</span></code> or <code class="docutils literal notranslate"><span class="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 youll run into problems with models not having been initialized yet).</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">&quot;objects.ObjectDB&quot;</span></code> for all <a class="reference internal" href="../Components/Objects.html"><span class="std std-doc">Objects</span></a> (like exits, rooms, characters etc)</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">&quot;accounts.AccountDB&quot;</span></code> for <a class="reference internal" href="../Components/Accounts.html"><span class="std std-doc">Accounts</span></a>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">&quot;scripts.ScriptDB&quot;</span></code> for <a class="reference internal" href="../Components/Scripts.html"><span class="std std-doc">Scripts</span></a>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">&quot;comms.ChannelDB&quot;</span></code> for <a class="reference internal" href="../Components/Channels.html"><span class="std std-doc">Channels</span></a>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">&quot;comms.Msg&quot;</span></code> for <a class="reference internal" href="../Components/Msg.html"><span class="std std-doc">Msg</span></a> objects.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">&quot;help.HelpEntry&quot;</span></code> for <a class="reference internal" href="../Components/Help-System.html"><span class="std std-doc">Help Entries</span></a>.</p></li>
</ul>
<p>Heres an example:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">django.db</span><span class="w"> </span><span class="kn">import</span> <span class="n">models</span>
<span class="k">class</span><span class="w"> </span><span class="nc">MySpecial</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="n">db_character</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="s2">&quot;objects.ObjectDB&quot;</span><span class="p">)</span>
<span class="n">db_items</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ManyToManyField</span><span class="p">(</span><span class="s2">&quot;objects.ObjectDB&quot;</span><span class="p">)</span>
<span class="n">db_account</span> <span class="o">=</span> <span class="n">modeles</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="s2">&quot;accounts.AccountDB&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>It may seem counter-intuitive, but this will work correctly:</p>
<div class="highlight-none notranslate"><div class="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 <code class="docutils literal notranslate"><span class="pre">.db_character</span></code> field is loaded into Python, the entity itself knows that its supposed to be a <code class="docutils literal notranslate"><span class="pre">Character</span></code> and loads itself to that form.</p>
<p>The drawback of this is that the database wont <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 <code class="docutils literal notranslate"><span class="pre">db_character</span></code> field fail if you try to store an <code class="docutils literal notranslate"><span class="pre">Account</span></code>, it will gladly accept any instance of a typeclass that inherits from <code class="docutils literal notranslate"><span class="pre">ObjectDB</span></code>, such as rooms, exits or other non-character Objects. Its up to you to validate that what you store is what you expect it to be.</p>
</section>
<section id="creating-a-new-model-instance">
<h2>Creating a new model instance<a class="headerlink" href="#creating-a-new-model-instance" title="Link to this heading"></a></h2>
<p>To create a new row in your table, you instantiate the model and then call its <code class="docutils literal notranslate"><span class="pre">save()</span></code> method:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span><span class="w"> </span><span class="nn">evennia.myapp</span><span class="w"> </span><span class="kn">import</span> <span class="n">MyDataStore</span>
<span class="n">new_datastore</span> <span class="o">=</span> <span class="n">MyDataStore</span><span class="p">(</span><span class="n">db_key</span><span class="o">=</span><span class="s2">&quot;LargeSword&quot;</span><span class="p">,</span>
<span class="n">db_category</span><span class="o">=</span><span class="s2">&quot;weapons&quot;</span><span class="p">,</span>
<span class="n">db_text</span><span class="o">=</span><span class="s2">&quot;This is a huge weapon!&quot;</span><span class="p">)</span>
<span class="c1"># this is required to actually create the row in the database!</span>
<span class="n">new_datastore</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
</pre></div>
</div>
<p>Note that the <code class="docutils literal notranslate"><span class="pre">db_date_created</span></code> field of the model is not specified. Its flag <code class="docutils literal notranslate"><span class="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>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">my_datastore</span><span class="o">.</span><span class="n">db_key</span> <span class="o">=</span> <span class="s2">&quot;Larger Sword&quot;</span>
<span class="n">my_datastore</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
</pre></div>
</div>
<p>Evennias normal models dont need to explicitly save, since they are based on <code class="docutils literal notranslate"><span class="pre">SharedMemoryModel</span></code> rather than the raw django model. This is covered in the next section.</p>
</section>
<section id="using-the-sharedmemorymodel-parent">
<h2>Using the <code class="docutils literal notranslate"><span class="pre">SharedMemoryModel</span></code> parent<a class="headerlink" href="#using-the-sharedmemorymodel-parent" title="Link to this heading"></a></h2>
<p>Evennia doesnt base most of its models on the raw <code class="docutils literal notranslate"><span class="pre">django.db.models.Model</span></code> but on the Evennia base model <code class="docutils literal notranslate"><span class="pre">evennia.utils.idmapper.models.SharedMemoryModel</span></code>. There are two main reasons for this:</p>
<ol class="arabic simple">
<li><p>Ease of updating fields without having to explicitly call <code class="docutils literal notranslate"><span class="pre">save()</span></code></p></li>
<li><p>On-object memory persistence and database caching</p></li>
</ol>
<p>The first (and least important) point means that as long as you named your fields <code class="docutils literal notranslate"><span class="pre">db_*</span></code>, Evennia will automatically create field wrappers for them. This happens in the models <a class="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 <code class="docutils literal notranslate"><span class="pre">db_</span></code> prefix. So the <code class="docutils literal notranslate"><span class="pre">db_key</span></code> field will have a wrapper property named <code class="docutils literal notranslate"><span class="pre">key</span></code>. You can then do:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">my_datastore</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;Larger Sword&quot;</span>
</pre></div>
</div>
<p>and dont have to explicitly call <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="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>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">shield</span> <span class="o">=</span> <span class="n">MyDataStore</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">db_key</span><span class="o">=</span><span class="s2">&quot;SmallShield&quot;</span><span class="p">)</span>
<span class="n">shield</span><span class="o">.</span><span class="n">cracked</span> <span class="o">=</span> <span class="kc">True</span> <span class="c1"># where cracked is not a database field</span>
</pre></div>
</div>
<p>And then in another function you do</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">shield</span> <span class="o">=</span> <span class="n">MyDataStore</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">db_key</span><span class="o">=</span><span class="s2">&quot;SmallShield&quot;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">shield</span><span class="o">.</span><span class="n">cracked</span><span class="p">)</span> <span class="c1"># error!</span>
</pre></div>
</div>
<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 <code class="docutils literal notranslate"><span class="pre">AttributeError</span></code> for not finding the <code class="docutils literal notranslate"><span class="pre">cracked</span></code> property. The reason is that <code class="docutils literal notranslate"><span class="pre">cracked</span></code> doesnt represent an actual field in the database. It was just added at run-time and thus Django dont 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 <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">cracked</span></code> property at any time - until you rebooted when all non-persistent data goes.</p>
<p>Using the idmapper is both more intuitive and more efficient <em>per object</em>; it leads to a lot less
reading from disk. The drawback is that this system tends to be more memory hungry <em>overall</em>. So if you know that youll <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 <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">evennia.utils.idmapper.models.SharedMemoryModel</span></code> instead of from the default <code class="docutils literal notranslate"><span class="pre">django.db.models.Model</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">evennia.utils.idmapper.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">SharedMemoryModel</span>
<span class="k">class</span><span class="w"> </span><span class="nc">MyDataStore</span><span class="p">(</span><span class="n">SharedMemoryModel</span><span class="p">):</span>
<span class="c1"># the rest is the same as before, but db_* is important; these will</span>
<span class="c1"># later be settable as .key, .category, .text ...</span>
<span class="n">db_key</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">80</span><span class="p">,</span> <span class="n">db_index</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">db_category</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">80</span><span class="p">,</span> <span class="n">null</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">blank</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">db_text</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">TextField</span><span class="p">(</span><span class="n">null</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">blank</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">db_date_created</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateTimeField</span><span class="p">(</span><span class="s1">&#39;date created&#39;</span><span class="p">,</span> <span class="n">editable</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">auto_now_add</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">db_index</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
</section>
<section id="searching-for-your-models">
<h2>Searching for your models<a class="headerlink" href="#searching-for-your-models" title="Link to this heading"></a></h2>
<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 <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">db_key</span></code> and not just <code class="docutils literal notranslate"><span class="pre">key</span></code>).</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span><span class="w"> </span><span class="nn">world.myapp</span><span class="w"> </span><span class="kn">import</span> <span class="n">MyDataStore</span>
<span class="c1"># get all datastore objects exactly matching a given key</span>
<span class="n">matches</span> <span class="o">=</span> <span class="n">MyDataStore</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">db_key</span><span class="o">=</span><span class="s2">&quot;Larger Sword&quot;</span><span class="p">)</span>
<span class="c1"># get all datastore objects with a key containing &quot;sword&quot;</span>
<span class="c1"># and having the category &quot;weapons&quot; (both ignoring upper/lower case)</span>
<span class="n">matches2</span> <span class="o">=</span> <span class="n">MyDataStore</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">db_key__icontains</span><span class="o">=</span><span class="s2">&quot;sword&quot;</span><span class="p">,</span>
<span class="n">db_category__iequals</span><span class="o">=</span><span class="s2">&quot;weapons&quot;</span><span class="p">)</span>
<span class="c1"># show the matching data (e.g. inside a command)</span>
<span class="k">for</span> <span class="n">match</span> <span class="ow">in</span> <span class="n">matches2</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">match</span><span class="o">.</span><span class="n">db_text</span><span class="p">)</span>
</pre></div>
</div>
<p>See the <a class="reference internal" href="../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Django-queries.html"><span class="std std-doc">Beginner Tutorial lesson on Django querying</span></a> for a lot more information about querying the database.</p>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="Main">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo of Evennia"/>
</a></p>
<search id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</search>
<script>document.getElementById('searchbox').style.display = "block"</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">New Models</a><ul>
<li><a class="reference internal" href="#overview-of-database-tables">Overview of database tables</a></li>
<li><a class="reference internal" href="#adding-a-new-database-table">Adding a new database table</a></li>
<li><a class="reference internal" href="#defining-your-models">Defining your models</a></li>
<li><a class="reference internal" href="#referencing-existing-models-and-typeclasses">Referencing existing models and typeclasses</a></li>
<li><a class="reference internal" href="#creating-a-new-model-instance">Creating a new model instance</a></li>
<li><a class="reference internal" href="#using-the-sharedmemorymodel-parent">Using the <code class="docutils literal notranslate"><span class="pre">SharedMemoryModel</span></code> parent</a></li>
<li><a class="reference internal" href="#searching-for-your-models">Searching for your models</a></li>
</ul>
</li>
</ul>
<div>
<h4>Previous topic</h4>
<p class="topless"><a href="Protocols.html"
title="previous chapter">Protocols</a></p>
</div>
<div>
<h4>Next topic</h4>
<p class="topless"><a href="Zones.html"
title="next chapter">Zones</a></p>
</div>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Concepts/Models.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com/docs/latest/index.html">Documentation Top</a> </li>
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
<li><a href="https://github.com/evennia/evennia">Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Doc Versions</h3>
<ul>
<li>
<a href="https://www.evennia.com/docs/latest/index.html">latest (main branch)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/5.x/index.html">v5.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/4.x/index.html">v4.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/3.x/index.html">v3.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/2.x/index.html">v2.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/1.x/index.html">v1.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/0.x/index.html">v0.9.5 branch (outdated)</a>
</li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="Related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Zones.html" title="Zones"
>next</a> |</li>
<li class="right" >
<a href="Protocols.html" title="Protocols"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Concepts-Overview.html" >Core Concepts</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">New Models</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2024, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.2.3.
</div>
</body>
</html>