mirror of
https://github.com/evennia/evennia.git
synced 2026-03-18 22:06:30 +01:00
528 lines
53 KiB
HTML
528 lines
53 KiB
HTML
|
|
|
|||
|
|
<!DOCTYPE html>
|
|||
|
|
|
|||
|
|
<html>
|
|||
|
|
<head>
|
|||
|
|
<meta charset="utf-8" />
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
|||
|
|
|
|||
|
|
<title>Tutorial Searching For Objects — Evennia 0.9.5 documentation</title>
|
|||
|
|
<link rel="stylesheet" href="_static/nature.css" type="text/css" />
|
|||
|
|
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
|||
|
|
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
|||
|
|
<script src="_static/jquery.js"></script>
|
|||
|
|
<script src="_static/underscore.js"></script>
|
|||
|
|
<script src="_static/doctools.js"></script>
|
|||
|
|
<script src="_static/language_data.js"></script>
|
|||
|
|
<script async="async" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
|||
|
|
<script type="text/x-mathjax-config">MathJax.Hub.Config({"tex2jax": {"processClass": "tex2jax_process|mathjax_process|math|output_area"}})</script>
|
|||
|
|
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
|||
|
|
<link rel="index" title="Index" href="genindex.html" />
|
|||
|
|
<link rel="search" title="Search" href="search.html" />
|
|||
|
|
</head><body>
|
|||
|
|
<div class="related" role="navigation" aria-label="related navigation">
|
|||
|
|
<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="nav-item nav-item-0"><a href="index.html">Evennia 0.9.5</a> »</li>
|
|||
|
|
<li class="nav-item nav-item-this"><a href="">Tutorial Searching For Objects</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="tutorial-searching-for-objects">
|
|||
|
|
<h1>Tutorial Searching For Objects<a class="headerlink" href="#tutorial-searching-for-objects" title="Permalink to this headline">¶</a></h1>
|
|||
|
|
<p>You will often want to operate on a specific object in the database. For example when a player
|
|||
|
|
attacks a named target you’ll need to find that target so it can be attacked. Or when a rain storm
|
|||
|
|
draws in you need to find all outdoor-rooms so you can show it raining in them. This tutorial
|
|||
|
|
explains Evennia’s tools for searching.</p>
|
|||
|
|
<section id="things-to-search-for">
|
|||
|
|
<h2>Things to search for<a class="headerlink" href="#things-to-search-for" title="Permalink to this headline">¶</a></h2>
|
|||
|
|
<p>The first thing to consider is the base type of the thing you are searching for. Evennia organizes
|
|||
|
|
its database into a few main tables: <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>, <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>, <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a>,
|
|||
|
|
<a class="reference internal" href="Communications.html#channels"><span class="std std-doc">Channels</span></a>, <a class="reference internal" href="Communications.html#msg"><span class="std std-doc">Messages</span></a> and <a class="reference internal" href="Help-System.html"><span class="doc std std-doc">Help Entries</span></a>.
|
|||
|
|
Most of the time you’ll likely spend your time searching for Objects and the occasional Accounts.</p>
|
|||
|
|
<p>So to find an entity, what can be searched for?</p>
|
|||
|
|
<ul class="simple">
|
|||
|
|
<li><p>The <code class="docutils literal notranslate"><span class="pre">key</span></code> is the name of the entity. While you can get this from <code class="docutils literal notranslate"><span class="pre">obj.key</span></code> the <em>database field</em>
|
|||
|
|
is actually named <code class="docutils literal notranslate"><span class="pre">obj.db_key</span></code> - this is useful to know only when you do <a class="reference internal" href="#queries-in-django"><span class="std std-doc">direct database
|
|||
|
|
queries</span></a>. The one exception is <code class="docutils literal notranslate"><span class="pre">Accounts</span></code>, where
|
|||
|
|
the database field for <code class="docutils literal notranslate"><span class="pre">.key</span></code> is instead named <code class="docutils literal notranslate"><span class="pre">username</span></code> (this is a Django requirement). When you
|
|||
|
|
don’t specify search-type, you’ll usually search based on key. <em>Aliases</em> are extra names given to
|
|||
|
|
Objects using something like <code class="docutils literal notranslate"><span class="pre">@alias</span></code> or <code class="docutils literal notranslate"><span class="pre">obj.aliases.add('name')</span></code>. The main search functions (see
|
|||
|
|
below) will automatically search for aliases whenever you search by-key.</p></li>
|
|||
|
|
<li><p><a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> are the main way to group and identify objects in Evennia. Tags can most often be
|
|||
|
|
used (sometimes together with keys) to uniquely identify an object. For example, even though you
|
|||
|
|
have two locations with the same name, you can separate them by their tagging (this is how Evennia
|
|||
|
|
implements ‘zones’ seen in other systems). Tags can also have categories, to further organize your
|
|||
|
|
data for quick lookups.</p></li>
|
|||
|
|
<li><p>An object’s <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a> can also used to find an object. This can be very useful but
|
|||
|
|
since Attributes can store almost any data they are far less optimized to search for than Tags or
|
|||
|
|
keys.</p></li>
|
|||
|
|
<li><p>The object’s <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclass</span></a> indicate the sub-type of entity. A Character, Flower or
|
|||
|
|
Sword are all types of Objects. A Bot is a kind of Account. The database field is called
|
|||
|
|
<code class="docutils literal notranslate"><span class="pre">typeclass_path</span></code> and holds the full Python-path to the class. You can usually specify the
|
|||
|
|
<code class="docutils literal notranslate"><span class="pre">typeclass</span></code> as an argument to Evennia’s search functions as well as use the class directly to limit
|
|||
|
|
queries.</p></li>
|
|||
|
|
<li><p>The <code class="docutils literal notranslate"><span class="pre">location</span></code> is only relevant for <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a> but is a very common way to weed down the
|
|||
|
|
number of candidates before starting to search. The reason is that most in-game commands tend to
|
|||
|
|
operate on things nearby (in the same room) so the choices can be limited from the start.</p></li>
|
|||
|
|
<li><p>The database id or the ‘#dbref’ is unique (and never re-used) within each database table. So while
|
|||
|
|
there is one and only one Object with dbref <code class="docutils literal notranslate"><span class="pre">#42</span></code> there could also be an Account or Script with the
|
|||
|
|
dbref <code class="docutils literal notranslate"><span class="pre">#42</span></code> at the same time. In almost all search methods you can replace the “key” search
|
|||
|
|
criterion with <code class="docutils literal notranslate"><span class="pre">"#dbref"</span></code> to search for that id. This can occasionally be practical and may be what
|
|||
|
|
you are used to from other code bases. But it is considered <em>bad practice</em> in Evennia to rely on
|
|||
|
|
hard-coded #dbrefs to do your searches. It makes your code tied to the exact layout of the database.
|
|||
|
|
It’s also not very maintainable to have to remember abstract numbers. Passing the actual objects
|
|||
|
|
around and searching by Tags and/or keys will usually get you what you need.</p></li>
|
|||
|
|
</ul>
|
|||
|
|
</section>
|
|||
|
|
<section id="getting-objects-inside-another">
|
|||
|
|
<h2>Getting objects inside another<a class="headerlink" href="#getting-objects-inside-another" title="Permalink to this headline">¶</a></h2>
|
|||
|
|
<p>All in-game <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a> have a <code class="docutils literal notranslate"><span class="pre">.contents</span></code> property that returns all objects ‘inside’ them
|
|||
|
|
(that is, all objects which has its <code class="docutils literal notranslate"><span class="pre">.location</span></code> property set to that object. This is a simple way to
|
|||
|
|
get everything in a room and is also faster since this lookup is cached and won’t hit the database.</p>
|
|||
|
|
<ul class="simple">
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">roomobj.contents</span></code> returns a list of all objects inside <code class="docutils literal notranslate"><span class="pre">roomobj</span></code>.</p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">obj.contents</span></code> same as for a room, except this usually represents the object’s inventory</p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">obj.location.contents</span></code> gets everything in <code class="docutils literal notranslate"><span class="pre">obj</span></code>’s location (including <code class="docutils literal notranslate"><span class="pre">obj</span></code> itself).</p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">roomobj.exits</span></code> returns all exits starting from <code class="docutils literal notranslate"><span class="pre">roomobj</span></code> (Exits are here defined as Objects with
|
|||
|
|
their <code class="docutils literal notranslate"><span class="pre">destination</span></code> field set).</p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">obj.location.contents_get(exclude=obj)</span></code> - this helper method returns all objects in <code class="docutils literal notranslate"><span class="pre">obj</span></code>’s
|
|||
|
|
location except <code class="docutils literal notranslate"><span class="pre">obj</span></code>.</p></li>
|
|||
|
|
</ul>
|
|||
|
|
</section>
|
|||
|
|
<section id="searching-using-object-search">
|
|||
|
|
<h2>Searching using <code class="docutils literal notranslate"><span class="pre">Object.search</span></code><a class="headerlink" href="#searching-using-object-search" title="Permalink to this headline">¶</a></h2>
|
|||
|
|
<p>Say you have a <a class="reference internal" href="Commands.html"><span class="doc std std-doc">command</span></a>, and you want it to do something to a target. You might be
|
|||
|
|
wondering how you retrieve that target in code, and that’s where Evennia’s search utilities come in.
|
|||
|
|
In the most common case, you’ll often use the <code class="docutils literal notranslate"><span class="pre">search</span></code> method of the <code class="docutils literal notranslate"><span class="pre">Object</span></code> or <code class="docutils literal notranslate"><span class="pre">Account</span></code>
|
|||
|
|
typeclasses. In a command, the <code class="docutils literal notranslate"><span class="pre">.caller</span></code> property will refer back to the object using the command
|
|||
|
|
(usually a <code class="docutils literal notranslate"><span class="pre">Character</span></code>, which is a type of <code class="docutils literal notranslate"><span class="pre">Object</span></code>) while <code class="docutils literal notranslate"><span class="pre">.args</span></code> will contain Command’s arguments:</p>
|
|||
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># e.g. in file mygame/commands/command.py</span>
|
|||
|
|
|
|||
|
|
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">default_cmds</span>
|
|||
|
|
|
|||
|
|
<span class="k">class</span> <span class="nc">CmdPoke</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
|||
|
|
<span class="sd">"""</span>
|
|||
|
|
<span class="sd"> Pokes someone.</span>
|
|||
|
|
|
|||
|
|
<span class="sd"> Usage: poke <target></span>
|
|||
|
|
<span class="sd"> """</span>
|
|||
|
|
<span class="n">key</span> <span class="o">=</span> <span class="s2">"poke"</span>
|
|||
|
|
|
|||
|
|
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
|
<span class="sd">"""Executes poke command"""</span>
|
|||
|
|
<span class="n">target</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">lstrip</span><span class="p">())</span>
|
|||
|
|
<span class="k">if</span> <span class="ow">not</span> <span class="n">target</span><span class="p">:</span>
|
|||
|
|
<span class="c1"># we didn't find anyone, but search has already let the</span>
|
|||
|
|
<span class="c1"># caller know. We'll just return, since we're done</span>
|
|||
|
|
<span class="k">return</span>
|
|||
|
|
<span class="c1"># we found a target! we'll do stuff to them.</span>
|
|||
|
|
<span class="n">target</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="si">}</span><span class="s2"> pokes you."</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="sa">f</span><span class="s2">"You poke </span><span class="si">{</span><span class="n">target</span><span class="si">}</span><span class="s2">."</span><span class="p">)</span>
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
<p>By default, the search method of a Character will attempt to find a unique object match for the
|
|||
|
|
string sent to it (<code class="docutils literal notranslate"><span class="pre">self.args</span></code>, in this case, which is the arguments passed to the command by the
|
|||
|
|
player) in the surroundings of the Character - the room or their inventory. If there is no match
|
|||
|
|
found, the return value (which is assigned to <code class="docutils literal notranslate"><span class="pre">target</span></code>) will be <code class="docutils literal notranslate"><span class="pre">None</span></code>, and an appropriate failure
|
|||
|
|
message will be sent to the Character. If there’s not a unique match, <code class="docutils literal notranslate"><span class="pre">None</span></code> will again be returned,
|
|||
|
|
and a different error message will be sent asking them to disambiguate the multi-match. By default,
|
|||
|
|
the user can then pick out a specific match using with a number and dash preceding the name of the
|
|||
|
|
object: <code class="docutils literal notranslate"><span class="pre">character.search("2-pink</span> <span class="pre">unicorn")</span></code> will try to find the second pink unicorn in the room.</p>
|
|||
|
|
<p>The search method has many <a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia.objects.objects#defaultcharactersearch">arguments</a> that
|
|||
|
|
allow you to refine the search, such as by designating the location to search in or only matching
|
|||
|
|
specific typeclasses.</p>
|
|||
|
|
</section>
|
|||
|
|
<section id="searching-using-utils-search">
|
|||
|
|
<h2>Searching using <code class="docutils literal notranslate"><span class="pre">utils.search</span></code><a class="headerlink" href="#searching-using-utils-search" title="Permalink to this headline">¶</a></h2>
|
|||
|
|
<p>Sometimes you will want to find something that isn’t tied to the search methods of a character or
|
|||
|
|
account. In these cases, Evennia provides a <a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia.utils.search">utility module with a number of search
|
|||
|
|
functions</a>. For example, suppose you want a command that will find and
|
|||
|
|
display all the rooms that are tagged as a ‘hangout’, for people to gather by. Here’s a simple
|
|||
|
|
Command to do this:</p>
|
|||
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># e.g. in file mygame/commands/command.py</span>
|
|||
|
|
|
|||
|
|
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">default_cmds</span>
|
|||
|
|
<span class="kn">from</span> <span class="nn">evennia.utils.search</span> <span class="kn">import</span> <span class="n">search_tag</span>
|
|||
|
|
|
|||
|
|
<span class="k">class</span> <span class="nc">CmdListHangouts</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">MuxCommand</span><span class="p">):</span>
|
|||
|
|
<span class="sd">"""Lists hangouts"""</span>
|
|||
|
|
<span class="n">key</span> <span class="o">=</span> <span class="s2">"hangouts"</span>
|
|||
|
|
|
|||
|
|
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
|
<span class="sd">"""Executes 'hangouts' command"""</span>
|
|||
|
|
<span class="n">hangouts</span> <span class="o">=</span> <span class="n">search_tag</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s2">"hangout"</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">"location tags"</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="sa">f</span><span class="s2">"Hangouts available: </span><span class="si">{</span><span class="s1">', '</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">ob</span><span class="p">)</span> <span class="k">for</span> <span class="n">ob</span> <span class="ow">in</span> <span class="n">hangouts</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
<p>This uses the <code class="docutils literal notranslate"><span class="pre">search_tag</span></code> function to find all objects previously tagged with <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a>
|
|||
|
|
“hangout” and with category “location tags”.</p>
|
|||
|
|
<p>Other important search methods in <code class="docutils literal notranslate"><span class="pre">utils.search</span></code> are</p>
|
|||
|
|
<ul class="simple">
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">search_object</span></code></p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">search_account</span></code></p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">search_scripts</span></code></p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">search_channel</span></code></p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">search_message</span></code></p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">search_help</span></code></p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">search_tag</span></code> - find Objects with a given Tag. <a class="reference internal" href="Tags.html#searching-for-objects-with-a-given-tag"><span class="std std-doc">See also here for how to search by
|
|||
|
|
tag</span></a>.</p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">search_account_tag</span></code> - find Accounts with a given Tag.</p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">search_script_tag</span></code> - find Scripts with a given Tag.</p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">search_channel_tag</span></code> - find Channels with a given Tag.</p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">search_object_attribute</span></code> - find Objects with a given Attribute.</p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">search_account_attribute</span></code> - find Accounts with a given Attribute.</p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">search_attribute_object</span></code> - this returns the actual Attribute, not the object it sits on.</p></li>
|
|||
|
|
</ul>
|
|||
|
|
<blockquote>
|
|||
|
|
<div><p>Note: All search functions return a Django <code class="docutils literal notranslate"><span class="pre">queryset</span></code> which is technically a list-like
|
|||
|
|
representation of the database-query it’s about to do. Only when you convert it to a real list, loop
|
|||
|
|
over it or try to slice or access any of its contents will the datbase-lookup happen. This means you
|
|||
|
|
could yourself customize the query further if you know what you are doing (see the next section).</p>
|
|||
|
|
</div></blockquote>
|
|||
|
|
</section>
|
|||
|
|
<section id="queries-in-django">
|
|||
|
|
<h2>Queries in Django<a class="headerlink" href="#queries-in-django" title="Permalink to this headline">¶</a></h2>
|
|||
|
|
<p><em>This is an advanced topic.</em></p>
|
|||
|
|
<p>Evennia’s search methods should be sufficient for the vast majority of situations. But eventually
|
|||
|
|
you might find yourself trying to figure out how to get searches for unusual circumstances: Maybe
|
|||
|
|
you want to find all characters who are <em>not</em> in rooms tagged as hangouts <em>and</em> have the lycanthrope
|
|||
|
|
tag <em>and</em> whose names start with a vowel, but <em>not</em> with ‘Ab’, and <em>only if</em> they have 3 or more
|
|||
|
|
objects in their inventory … You could in principle use one of the earlier search methods to find
|
|||
|
|
all candidates and then loop over them with a lot of if statements in raw Python. But you can do
|
|||
|
|
this much more efficiently by querying the database directly.</p>
|
|||
|
|
<p>Enter <a class="reference external" href="https://docs.djangoproject.com/en/1.11/ref/models/querysets/">django’s querysets</a>. A QuerySet
|
|||
|
|
is the representation of a database query and can be modified as desired. Only once one tries to
|
|||
|
|
retrieve the data of that query is it <em>evaluated</em> and does an actual database request. This is
|
|||
|
|
useful because it means you can modify a query as much as you want (even pass it around) and only
|
|||
|
|
hit the database once you are happy with it.
|
|||
|
|
Evennia’s search functions are themselves an even higher level wrapper around Django’s queries, and
|
|||
|
|
many search methods return querysets. That means that you could get the result from a search
|
|||
|
|
function and modify the resulting query to your own ends to further tweak what you search for.</p>
|
|||
|
|
<p>Evaluated querysets can either contain objects such as Character objects, or lists of values derived
|
|||
|
|
from the objects. Queries usually use the ‘manager’ object of a class, which by convention is the
|
|||
|
|
<code class="docutils literal notranslate"><span class="pre">.objects</span></code> attribute of a class. For example, a query of Accounts that contain the letter ‘a’ could
|
|||
|
|
be:</p>
|
|||
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">typeclasses.accounts</span> <span class="kn">import</span> <span class="n">Account</span>
|
|||
|
|
|
|||
|
|
<span class="n">queryset</span> <span class="o">=</span> <span class="n">Account</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">username__contains</span><span class="o">=</span><span class="s1">'a'</span><span class="p">)</span>
|
|||
|
|
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
<p>The <code class="docutils literal notranslate"><span class="pre">filter</span></code> method of a manager takes arguments that allow you to define the query, and you can
|
|||
|
|
continue to refine the query by calling additional methods until you evaluate the queryset, causing
|
|||
|
|
the query to be executed and return a result. For example, if you have the result above, you could,
|
|||
|
|
without causing the queryset to be evaluated yet, get rid of matches that contain the letter ‘e by
|
|||
|
|
doing this:</p>
|
|||
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">queryset</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">exclude</span><span class="p">(</span><span class="n">username__contains</span><span class="o">=</span><span class="s1">'e'</span><span class="p">)</span>
|
|||
|
|
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
<blockquote>
|
|||
|
|
<div><p>You could also have chained <code class="docutils literal notranslate"><span class="pre">.exclude</span></code> directly to the end of the previous line.</p>
|
|||
|
|
</div></blockquote>
|
|||
|
|
<p>Once you try to access the result, the queryset will be evaluated automatically under the hood:</p>
|
|||
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">accounts</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">queryset</span><span class="p">)</span> <span class="c1"># this fills list with matches</span>
|
|||
|
|
|
|||
|
|
<span class="k">for</span> <span class="n">account</span> <span class="ow">in</span> <span class="n">queryset</span><span class="p">:</span>
|
|||
|
|
<span class="c1"># do something with account</span>
|
|||
|
|
|
|||
|
|
<span class="n">accounts</span> <span class="o">=</span> <span class="n">queryset</span><span class="p">[:</span><span class="mi">4</span><span class="p">]</span> <span class="c1"># get first four matches</span>
|
|||
|
|
<span class="n">account</span> <span class="o">=</span> <span class="n">queryset</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># get first match</span>
|
|||
|
|
<span class="c1"># etc</span>
|
|||
|
|
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
<section id="limiting-by-typeclass">
|
|||
|
|
<h3>Limiting by typeclass<a class="headerlink" href="#limiting-by-typeclass" title="Permalink to this headline">¶</a></h3>
|
|||
|
|
<p>Although <code class="docutils literal notranslate"><span class="pre">Character</span></code>s, <code class="docutils literal notranslate"><span class="pre">Exit</span></code>s, <code class="docutils literal notranslate"><span class="pre">Room</span></code>s, and other children of <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> all shares the same
|
|||
|
|
underlying database table, Evennia provides a shortcut to do more specific queries only for those
|
|||
|
|
typeclasses. For example, to find only <code class="docutils literal notranslate"><span class="pre">Character</span></code>s whose names start with ‘A’, you might do:</p>
|
|||
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">Character</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__startswith</span><span class="o">=</span><span class="s2">"A"</span><span class="p">)</span>
|
|||
|
|
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
<p>If Character has a subclass <code class="docutils literal notranslate"><span class="pre">Npc</span></code> and you wanted to find only Npc’s you’d instead do</p>
|
|||
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">Npc</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__startswith</span><span class="o">=</span><span class="s2">"A"</span><span class="p">)</span>
|
|||
|
|
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
<p>If you wanted to search both Characters and all its subclasses (like Npc) you use the <code class="docutils literal notranslate"><span class="pre">*_family</span></code>
|
|||
|
|
method which is added by Evennia:</p>
|
|||
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">Character</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter_family</span><span class="p">(</span><span class="n">db_key__startswith</span><span class="o">=</span><span class="s2">"A"</span><span class="p">)</span>
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
<p>The higher up in the inheritance hierarchy you go the more objects will be included in these
|
|||
|
|
searches. There is one special case, if you really want to include <em>everything</em> from a given
|
|||
|
|
database table. You do that by searching on the database model itself. These are named <code class="docutils literal notranslate"><span class="pre">ObjectDB</span></code>,
|
|||
|
|
<code class="docutils literal notranslate"><span class="pre">AccountDB</span></code>, <code class="docutils literal notranslate"><span class="pre">ScriptDB</span></code> etc.</p>
|
|||
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">AccountDB</span>
|
|||
|
|
|
|||
|
|
<span class="c1"># all Accounts in the database, regardless of typeclass</span>
|
|||
|
|
<span class="nb">all</span> <span class="o">=</span> <span class="n">AccountDB</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
|
|||
|
|
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
<p>Here are the most commonly used methods to use with the <code class="docutils literal notranslate"><span class="pre">objects</span></code> managers:</p>
|
|||
|
|
<ul class="simple">
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">filter</span></code> - query for a listing of objects based on search criteria. Gives empty queryset if none
|
|||
|
|
were found.</p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">get</span></code> - query for a single match - raises exception if none were found, or more than one was
|
|||
|
|
found.</p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">all</span></code> - get all instances of the particular type.</p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">filter_family</span></code> - like <code class="docutils literal notranslate"><span class="pre">filter</span></code>, but search all sub classes as well.</p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">get_family</span></code> - like <code class="docutils literal notranslate"><span class="pre">get</span></code>, but search all sub classes as well.</p></li>
|
|||
|
|
<li><p><code class="docutils literal notranslate"><span class="pre">all_family</span></code> - like <code class="docutils literal notranslate"><span class="pre">all</span></code>, but return entities of all subclasses as well.</p></li>
|
|||
|
|
</ul>
|
|||
|
|
</section>
|
|||
|
|
</section>
|
|||
|
|
<section id="multiple-conditions">
|
|||
|
|
<h2>Multiple conditions<a class="headerlink" href="#multiple-conditions" title="Permalink to this headline">¶</a></h2>
|
|||
|
|
<p>If you pass more than one keyword argument to a query method, the query becomes an <code class="docutils literal notranslate"><span class="pre">AND</span></code>
|
|||
|
|
relationship. For example, if we want to find characters whose names start with “A” <em>and</em> are also
|
|||
|
|
werewolves (have the <code class="docutils literal notranslate"><span class="pre">lycanthrope</span></code> tag), we might do:</p>
|
|||
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">queryset</span> <span class="o">=</span> <span class="n">Character</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__startswith</span><span class="o">=</span><span class="s2">"A"</span><span class="p">,</span> <span class="n">db_tags__db_key</span><span class="o">=</span><span class="s2">"lycanthrope"</span><span class="p">)</span>
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
<p>To exclude lycanthropes currently in rooms tagged as hangouts, we might tack on an <code class="docutils literal notranslate"><span class="pre">.exclude</span></code> as
|
|||
|
|
before:</p>
|
|||
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">queryset</span> <span class="o">=</span> <span class="n">quersyet</span><span class="o">.</span><span class="n">exclude</span><span class="p">(</span><span class="n">db_location__db_tags__db_key</span><span class="o">=</span><span class="s2">"hangout"</span><span class="p">)</span>
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
<p>Note the syntax of the keywords in building the queryset. For example, <code class="docutils literal notranslate"><span class="pre">db_location</span></code> is the name of
|
|||
|
|
the database field sitting on (in this case) the <code class="docutils literal notranslate"><span class="pre">Character</span></code> (Object). Double underscore <code class="docutils literal notranslate"><span class="pre">__</span></code> works
|
|||
|
|
like dot-notation in normal Python (it’s used since dots are not allowed in keyword names). So the
|
|||
|
|
instruction <code class="docutils literal notranslate"><span class="pre">db_location__db_tags__db_key="hangout"</span></code> should be read as such:</p>
|
|||
|
|
<ol class="simple">
|
|||
|
|
<li><p>“On the <code class="docutils literal notranslate"><span class="pre">Character</span></code> object … (this comes from us building this queryset using the
|
|||
|
|
<code class="docutils literal notranslate"><span class="pre">Character.objects</span></code> manager)</p></li>
|
|||
|
|
<li><p>… get the value of the <code class="docutils literal notranslate"><span class="pre">db_location</span></code> field … (this references a Room object, normally)</p></li>
|
|||
|
|
<li><p>… on that location, get the value of the <code class="docutils literal notranslate"><span class="pre">db_tags</span></code> field … (this is a many-to-many field that
|
|||
|
|
can be treated like an object for this purpose. It references all tags on the location)</p></li>
|
|||
|
|
<li><p>… through the <code class="docutils literal notranslate"><span class="pre">db_tag</span></code> manager, find all Tags having a field <code class="docutils literal notranslate"><span class="pre">db_key</span></code> set to the value
|
|||
|
|
“hangout”.”</p></li>
|
|||
|
|
</ol>
|
|||
|
|
<p>This may seem a little complex at first, but this syntax will work the same for all queries. Just
|
|||
|
|
remember that all <em>database-fields</em> in Evennia are prefaced with <code class="docutils literal notranslate"><span class="pre">db_</span></code>. So even though Evennia is
|
|||
|
|
nice enough to alias the <code class="docutils literal notranslate"><span class="pre">db_key</span></code> field so you can normally just do <code class="docutils literal notranslate"><span class="pre">char.key</span></code> to get a character’s
|
|||
|
|
name, the database field is actually called <code class="docutils literal notranslate"><span class="pre">db_key</span></code> and the real name must be used for the purpose
|
|||
|
|
of building a query.</p>
|
|||
|
|
<blockquote>
|
|||
|
|
<div><p>Don’t confuse database fields with <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a> you set via <code class="docutils literal notranslate"><span class="pre">obj.db.attr</span> <span class="pre">=</span> <span class="pre">'foo'</span></code> or
|
|||
|
|
<code class="docutils literal notranslate"><span class="pre">obj.attributes.add()</span></code>. Attributes are custom database entities <em>linked</em> to an object. They are not
|
|||
|
|
separate fields <em>on</em> that object like <code class="docutils literal notranslate"><span class="pre">db_key</span></code> or <code class="docutils literal notranslate"><span class="pre">db_location</span></code> are. You can get attached Attributes
|
|||
|
|
manually through the <code class="docutils literal notranslate"><span class="pre">db_attributes</span></code> many-to-many field in the same way as <code class="docutils literal notranslate"><span class="pre">db_tags</span></code> above.</p>
|
|||
|
|
</div></blockquote>
|
|||
|
|
<section id="complex-queries">
|
|||
|
|
<h3>Complex queries<a class="headerlink" href="#complex-queries" title="Permalink to this headline">¶</a></h3>
|
|||
|
|
<p>What if you want to have a query with with <code class="docutils literal notranslate"><span class="pre">OR</span></code> conditions or negated requirements (<code class="docutils literal notranslate"><span class="pre">NOT</span></code>)? Enter
|
|||
|
|
Django’s Complex Query object,
|
|||
|
|
<a class="reference external" href="https://docs.djangoproject.com/en/1.11/topics/db/queries/#complex-lookups-with-q-objects">Q</a>. <code class="docutils literal notranslate"><span class="pre">Q()</span></code>
|
|||
|
|
objects take a normal django keyword query as its arguments. The special thing is that these Q
|
|||
|
|
objects can then be chained together with set operations: <code class="docutils literal notranslate"><span class="pre">|</span></code> for OR, <code class="docutils literal notranslate"><span class="pre">&</span></code> for AND, and preceded with
|
|||
|
|
<code class="docutils literal notranslate"><span class="pre">~</span></code> for NOT to build a combined, complex query.</p>
|
|||
|
|
<p>In our original Lycanthrope example we wanted our werewolves to have names that could start with any
|
|||
|
|
vowel except for the specific beginning “ab”.</p>
|
|||
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">Q</span>
|
|||
|
|
<span class="kn">from</span> <span class="nn">typeclasses.characters</span> <span class="kn">import</span> <span class="n">Character</span>
|
|||
|
|
|
|||
|
|
<span class="n">query</span> <span class="o">=</span> <span class="n">Q</span><span class="p">()</span>
|
|||
|
|
<span class="k">for</span> <span class="n">letter</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">"aeiouy"</span><span class="p">):</span>
|
|||
|
|
<span class="n">query</span> <span class="o">|=</span> <span class="n">Q</span><span class="p">(</span><span class="n">db_key__istartswith</span><span class="o">=</span><span class="n">letter</span><span class="p">)</span>
|
|||
|
|
<span class="n">query</span> <span class="o">&=</span> <span class="o">~</span><span class="n">Q</span><span class="p">(</span><span class="n">db_key__istartswith</span><span class="o">=</span><span class="s2">"ab"</span><span class="p">)</span>
|
|||
|
|
<span class="n">query</span> <span class="o">=</span> <span class="n">Character</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">query</span><span class="p">)</span>
|
|||
|
|
|
|||
|
|
<span class="n">list_of_lycanthropes</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
<p>In the above example, we construct our query our of several Q objects that each represent one part
|
|||
|
|
of the query. We iterate over the list of vowels, and add an <code class="docutils literal notranslate"><span class="pre">OR</span></code> condition to the query using <code class="docutils literal notranslate"><span class="pre">|=</span></code>
|
|||
|
|
(this is the same idea as using <code class="docutils literal notranslate"><span class="pre">+=</span></code> which may be more familiar). Each <code class="docutils literal notranslate"><span class="pre">OR</span></code> condition checks that
|
|||
|
|
the name starts with one of the valid vowels. Afterwards, we add (using <code class="docutils literal notranslate"><span class="pre">&=</span></code>) an <code class="docutils literal notranslate"><span class="pre">AND</span></code> condition
|
|||
|
|
that is negated with the <code class="docutils literal notranslate"><span class="pre">~</span></code> symbol. In other words we require that any match should <em>not</em> start
|
|||
|
|
with the string “ab”. Note that we don’t actually hit the database until we convert the query to a
|
|||
|
|
list at the end (we didn’t need to do that either, but could just have kept the query until we
|
|||
|
|
needed to do something with the matches).</p>
|
|||
|
|
</section>
|
|||
|
|
<section id="annotations-and-f-objects">
|
|||
|
|
<h3>Annotations and <code class="docutils literal notranslate"><span class="pre">F</span></code> objects<a class="headerlink" href="#annotations-and-f-objects" title="Permalink to this headline">¶</a></h3>
|
|||
|
|
<p>What if we wanted to filter on some condition that isn’t represented easily by a field on the
|
|||
|
|
object? Maybe we want to find rooms only containing five or more objects?</p>
|
|||
|
|
<p>We <em>could</em> retrieve all interesting candidates and run them through a for-loop to get and count
|
|||
|
|
their <code class="docutils literal notranslate"><span class="pre">.content</span></code> properties. We’d then just return a list of only those objects with enough
|
|||
|
|
contents. It would look something like this (note: don’t actually do this!):</p>
|
|||
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># probably not a good idea to do it this way</span>
|
|||
|
|
|
|||
|
|
<span class="kn">from</span> <span class="nn">typeclasses.rooms</span> <span class="kn">import</span> <span class="n">Room</span>
|
|||
|
|
|
|||
|
|
<span class="n">queryset</span> <span class="o">=</span> <span class="n">Room</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span> <span class="c1"># get all Rooms</span>
|
|||
|
|
<span class="n">rooms</span> <span class="o">=</span> <span class="p">[</span><span class="n">room</span> <span class="k">for</span> <span class="n">room</span> <span class="ow">in</span> <span class="n">queryset</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">room</span><span class="o">.</span><span class="n">contents</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">5</span><span class="p">]</span>
|
|||
|
|
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
<p>Once the number of rooms in your game increases, this could become quite expensive. Additionally, in
|
|||
|
|
some particular contexts, like when using the web features of Evennia, you must have the result as a
|
|||
|
|
queryset in order to use it in operations, such as in Django’s admin interface when creating list
|
|||
|
|
filters.</p>
|
|||
|
|
<p>Enter <a class="reference external" href="https://docs.djangoproject.com/en/1.11/ref/models/expressions/#f-expressions">F objects</a> and
|
|||
|
|
<em>annotations</em>. So-called F expressions allow you to do a query that looks at a value of each object
|
|||
|
|
in the database, while annotations allow you to calculate and attach a value to a query. So, let’s
|
|||
|
|
do the same example as before directly in the database:</p>
|
|||
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typeclasses.rooms</span> <span class="kn">import</span> <span class="n">Room</span>
|
|||
|
|
<span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">Count</span>
|
|||
|
|
|
|||
|
|
<span class="n">room_count</span> <span class="o">=</span> <span class="n">Room</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="n">num_objects</span><span class="o">=</span><span class="n">Count</span><span class="p">(</span><span class="s1">'locations_set'</span><span class="p">))</span>
|
|||
|
|
<span class="n">queryset</span> <span class="o">=</span> <span class="n">room_count</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">num_objects__gte</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
|
|||
|
|
|
|||
|
|
<span class="n">rooms</span> <span class="o">=</span> <span class="p">(</span><span class="n">Room</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="n">num_objects</span><span class="o">=</span><span class="n">Count</span><span class="p">(</span><span class="s1">'locations_set'</span><span class="p">))</span>
|
|||
|
|
<span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">num_objects__gte</span><span class="o">=</span><span class="mi">5</span><span class="p">))</span>
|
|||
|
|
|
|||
|
|
<span class="n">rooms</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">rooms</span><span class="p">)</span>
|
|||
|
|
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
<p>Here we first create an annotation <code class="docutils literal notranslate"><span class="pre">num_objects</span></code> of type <code class="docutils literal notranslate"><span class="pre">Count</span></code>, which is a Django class. Note that
|
|||
|
|
use of <code class="docutils literal notranslate"><span class="pre">location_set</span></code> in that <code class="docutils literal notranslate"><span class="pre">Count</span></code>. The <code class="docutils literal notranslate"><span class="pre">*_set</span></code> is a back-reference automatically created by
|
|||
|
|
Django. In this case it allows you to find all objects that <em>has the current object as location</em>.
|
|||
|
|
Once we have those, they are counted.
|
|||
|
|
Next we filter on this annotation, using the name <code class="docutils literal notranslate"><span class="pre">num_objects</span></code> as something we can filter for. We
|
|||
|
|
use <code class="docutils literal notranslate"><span class="pre">num_objects__gte=5</span></code> which means that <code class="docutils literal notranslate"><span class="pre">num_objects</span></code> should be greater than 5. This is a little
|
|||
|
|
harder to get one’s head around but much more efficient than lopping over all objects in Python.</p>
|
|||
|
|
<p>What if we wanted to compare two parameters against one another in a query? For example, what if
|
|||
|
|
instead of having 5 or more objects, we only wanted objects that had a bigger inventory than they
|
|||
|
|
had tags? Here an F-object comes in handy:</p>
|
|||
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">Count</span><span class="p">,</span> <span class="n">F</span>
|
|||
|
|
<span class="kn">from</span> <span class="nn">typeclasses.rooms</span> <span class="kn">import</span> <span class="n">Room</span>
|
|||
|
|
|
|||
|
|
<span class="n">result</span> <span class="o">=</span> <span class="p">(</span><span class="n">Room</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="n">num_objects</span><span class="o">=</span><span class="n">Count</span><span class="p">(</span><span class="s1">'locations_set'</span><span class="p">),</span>
|
|||
|
|
<span class="n">num_tags</span><span class="o">=</span><span class="n">Count</span><span class="p">(</span><span class="s1">'db_tags'</span><span class="p">))</span>
|
|||
|
|
<span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">num_objects__gt</span><span class="o">=</span><span class="n">F</span><span class="p">(</span><span class="s1">'num_tags'</span><span class="p">)))</span>
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
<p>F-objects allows for wrapping an annotated structure on the right-hand-side of the expression. It
|
|||
|
|
will be evaluated on-the-fly as needed.</p>
|
|||
|
|
</section>
|
|||
|
|
<section id="grouping-by-and-values">
|
|||
|
|
<h3>Grouping By and Values<a class="headerlink" href="#grouping-by-and-values" title="Permalink to this headline">¶</a></h3>
|
|||
|
|
<p>Suppose you used tags to mark someone belonging an organization. Now you want to make a list and
|
|||
|
|
need to get the membership count of every organization all at once. That’s where annotations and the
|
|||
|
|
<code class="docutils literal notranslate"><span class="pre">.values_list</span></code> queryset method come in. Values/Values Lists are an alternate way of returning a
|
|||
|
|
queryset - instead of objects, you get a list of dicts or tuples that hold selected properties from
|
|||
|
|
the the matches. It also allows you a way to ‘group up’ queries for returning information. For
|
|||
|
|
example, to get a display about each tag per Character and the names of the tag:</p>
|
|||
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">result</span> <span class="o">=</span> <span class="p">(</span><span class="n">Character</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_tags__db_category</span><span class="o">=</span><span class="s2">"organization"</span><span class="p">)</span>
|
|||
|
|
<span class="o">.</span><span class="n">values_list</span><span class="p">(</span><span class="s1">'db_tags__db_key'</span><span class="p">)</span>
|
|||
|
|
<span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="n">cnt</span><span class="o">=</span><span class="n">Count</span><span class="p">(</span><span class="s1">'id'</span><span class="p">))</span>
|
|||
|
|
<span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="s1">'-cnt'</span><span class="p">))</span>
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
<p>The result queryset will be a list of tuples ordered in descending order by the number of matches,
|
|||
|
|
in a format like the following:</p>
|
|||
|
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[(</span><span class="s1">'Griatch Fanclub'</span><span class="p">,</span> <span class="mi">3872</span><span class="p">),</span> <span class="p">(</span><span class="s2">"Chainsol's Ainneve Testers"</span><span class="p">,</span> <span class="mi">2076</span><span class="p">),</span> <span class="p">(</span><span class="s2">"Blaufeuer's Whitespace Fixers"</span><span class="p">,</span>
|
|||
|
|
<span class="mi">1903</span><span class="p">),</span>
|
|||
|
|
<span class="p">(</span><span class="s2">"Volund's Bikeshed Design Crew"</span><span class="p">,</span> <span class="mi">1764</span><span class="p">),</span> <span class="p">(</span><span class="s2">"Tehom's Misanthropes"</span><span class="p">,</span> <span class="mi">1</span><span class="p">)]</span>
|
|||
|
|
</pre></div>
|
|||
|
|
</div>
|
|||
|
|
</section>
|
|||
|
|
</section>
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<div class="clearer"></div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
|||
|
|
<div class="sphinxsidebarwrapper">
|
|||
|
|
<p class="logo"><a href="index.html">
|
|||
|
|
<img class="logo" src="_static/evennia_logo.png" alt="Logo"/>
|
|||
|
|
</a></p>
|
|||
|
|
<div 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" />
|
|||
|
|
<input type="submit" value="Go" />
|
|||
|
|
</form>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<script>$('#searchbox').show(0);</script>
|
|||
|
|
<p><h3><a href="index.html">Table of Contents</a></h3>
|
|||
|
|
<ul>
|
|||
|
|
<li><a class="reference internal" href="#">Tutorial Searching For Objects</a><ul>
|
|||
|
|
<li><a class="reference internal" href="#things-to-search-for">Things to search for</a></li>
|
|||
|
|
<li><a class="reference internal" href="#getting-objects-inside-another">Getting objects inside another</a></li>
|
|||
|
|
<li><a class="reference internal" href="#searching-using-object-search">Searching using <code class="docutils literal notranslate"><span class="pre">Object.search</span></code></a></li>
|
|||
|
|
<li><a class="reference internal" href="#searching-using-utils-search">Searching using <code class="docutils literal notranslate"><span class="pre">utils.search</span></code></a></li>
|
|||
|
|
<li><a class="reference internal" href="#queries-in-django">Queries in Django</a><ul>
|
|||
|
|
<li><a class="reference internal" href="#limiting-by-typeclass">Limiting by typeclass</a></li>
|
|||
|
|
</ul>
|
|||
|
|
</li>
|
|||
|
|
<li><a class="reference internal" href="#multiple-conditions">Multiple conditions</a><ul>
|
|||
|
|
<li><a class="reference internal" href="#complex-queries">Complex queries</a></li>
|
|||
|
|
<li><a class="reference internal" href="#annotations-and-f-objects">Annotations and <code class="docutils literal notranslate"><span class="pre">F</span></code> objects</a></li>
|
|||
|
|
<li><a class="reference internal" href="#grouping-by-and-values">Grouping By and Values</a></li>
|
|||
|
|
</ul>
|
|||
|
|
</li>
|
|||
|
|
</ul>
|
|||
|
|
</li>
|
|||
|
|
</ul>
|
|||
|
|
|
|||
|
|
<div role="note" aria-label="source link">
|
|||
|
|
<!--h3>This Page</h3-->
|
|||
|
|
<ul class="this-page-menu">
|
|||
|
|
<li><a href="_sources/Tutorial-Searching-For-Objects.md.txt"
|
|||
|
|
rel="nofollow">Show Page Source</a></li>
|
|||
|
|
</ul>
|
|||
|
|
</div><h3>Links</h3>
|
|||
|
|
<ul>
|
|||
|
|
<li><a href="https://www.evennia.com">Home page</a> </li>
|
|||
|
|
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
|||
|
|
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
|||
|
|
<li><a href="http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb">IRC</a> -
|
|||
|
|
<a href="https://discord.gg/NecFePw">Discord</a> -
|
|||
|
|
<a href="https://groups.google.com/forum/#%21forum/evennia">Forums</a>
|
|||
|
|
</li>
|
|||
|
|
<li><a href="http://evennia.blogspot.com/">Evennia Dev blog</a> </li>
|
|||
|
|
</ul>
|
|||
|
|
<h3>Versions</h3>
|
|||
|
|
<ul>
|
|||
|
|
<li><a href="../1.0-dev/index.html">1.0-dev (develop branch)</a></li>
|
|||
|
|
<li><a href="Tutorial-Searching-For-Objects.html">0.9.5 (v0.9.5 branch)</a></li>
|
|||
|
|
</ul>
|
|||
|
|
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="clearer"></div>
|
|||
|
|
</div>
|
|||
|
|
<div class="related" role="navigation" aria-label="related navigation">
|
|||
|
|
<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="nav-item nav-item-0"><a href="index.html">Evennia 0.9.5</a> »</li>
|
|||
|
|
<li class="nav-item nav-item-this"><a href="">Tutorial Searching For Objects</a></li>
|
|||
|
|
</ul>
|
|||
|
|
</div>
|
|||
|
|
<div class="footer" role="contentinfo">
|
|||
|
|
© Copyright 2020, The Evennia developer community.
|
|||
|
|
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
|||
|
|
</div>
|
|||
|
|
</body>
|
|||
|
|
</html>
|