mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Correct django querying example. Resolve #3422
This commit is contained in:
parent
43e31abc8d
commit
577f66c3ec
8 changed files with 99 additions and 23 deletions
|
|
@ -2,16 +2,40 @@
|
|||
|
||||
## main branch
|
||||
|
||||
- [Feature] Add `evennia.ON_DEMAND_HANDLER` for making it easier to implement
|
||||
timed element with the on-demand approach (Griatch)
|
||||
- [Fix] Remove `AMP_ENABLED` setting since it services no real purpose and
|
||||
erroring out on setting it would make it even less useful (Griatch).
|
||||
- [Fix] `services` command with no args would traceback (regression) (Griatch)
|
||||
- Feature: Add [`evennia.ON_DEMAND_HANDLER`][new-ondemandhandler] for making it
|
||||
easier to implement changes that are calculated on-demand (Griatch)
|
||||
- [Feature][pull3412]: Make it possible to add custom webclient css in
|
||||
`webclient/css/custom.css`, same as for website (InspectorCaracal)
|
||||
- [Feature][pull3367]: [Component contrib][pull3367extra] got better
|
||||
inheritance, slot names to choose attr storage, speedups and fixes (ChrisLR)
|
||||
- Feature: Break up `DefaultObject.search` method into several helpers to make
|
||||
it easier to override (Griatch)
|
||||
- Fix: Resolve multimatch error with rpsystem contrib (Griatch)
|
||||
- Fix: Remove `AMP_ENABLED` setting since it services no real purpose and
|
||||
erroring out on setting it would make it even less useful (Griatch).
|
||||
- Feature: Remove too-strict password restrictions for Evennia logins, using
|
||||
django defaults instead for passwords with more varied characters.
|
||||
- Fix `services` command with no args would traceback (regression) (Griatch)
|
||||
- [Fix][pull3423]: Fix wilderness contrib error moving to an already existing
|
||||
wilderness room (InspectorCaracal)
|
||||
- [Fix][pull3425]: Don't always include example the crafting recipe when
|
||||
using the crafting contrib (InspectorCaracal)
|
||||
- [Fix][pull3426]: Traceback banning a channel using with only one nick
|
||||
(InspectorCaracal)
|
||||
- [Fix][pull3434]: Adjust lunr search weights to void clashing of cmd-aliases over
|
||||
keys which caused some help entries to shadow others (InspectorCaracal)
|
||||
- Fix: Make `menu/email_login` contribs honor `NEW_ACCOUNT_REGISTRATION_ENABLED`
|
||||
setting (Griatch)
|
||||
- Doc fixes (InspectorCaracal, Griatch)
|
||||
|
||||
[new-ondemandhandler][https://www.evennia.com/docs/latest/Components/OnDemandHandler.html]
|
||||
[pull3412]: https://github.com/evennia/evennia/pull/3412
|
||||
[pull3423]: https://github.com/evennia/evennia/pull/3423
|
||||
[pull3425]: https://github.com/evennia/evennia/pull/3425
|
||||
[pull3426]: https://github.com/evennia/evennia/pull/3426
|
||||
[pull3434]: https://github.com/evennia/evennia/pull/3434
|
||||
[pull3367]: https://github.com/evennia/evennia/pull/3367
|
||||
[pull3367extra]: https://www.evennia.com/docs/latest/Contribs/Contrib-Components.html
|
||||
|
||||
## Evennia 3.1.1
|
||||
|
||||
|
|
|
|||
|
|
@ -294,6 +294,20 @@ A lock is no good if nothing checks it -- and by default Evennia does not check
|
|||
|
||||
The same keywords are available to use with `obj.attributes.set()` and `obj.attributes.remove()`, those will check for the `attredit` lock type.
|
||||
|
||||
## Querying by Attribute
|
||||
|
||||
While you can get attributes using the `obj.attributes.get` handler, you can also find objects based on the Attributes they have through the `db_attributes` many-to-many field available on each typeclassed entity:
|
||||
|
||||
```python
|
||||
# find objects by attribue assigned (regardless of value)
|
||||
objs = evennia.ObjectDB.objects.filter(db_attributes__db_key="foo")
|
||||
# find objects with attribute of particular value assigned to them
|
||||
objs = evennia.ObjectDB.objects.filter(db_attributes__db_key="foo", db_attributes__db_value="bar")
|
||||
```
|
||||
|
||||
```{important}
|
||||
Internally, Attribute values are stored as _pickled strings_ (see next section). When querying, your search string is converted to the same format and matched in that form. While this means Attributes can store arbitrary Python structures, the drawback is that you cannot do more advanced database comparisons on them. For example doing `db_attributes__db__value__lt=4` or `__gt=0` will not work since less-than and greater-than doesn't do what you want between strings.
|
||||
```
|
||||
|
||||
## What types of data can I save in an Attribute?
|
||||
|
||||
|
|
|
|||
|
|
@ -30,12 +30,20 @@ class Character(ComponentHolderMixin, DefaultCharacter):
|
|||
# ...
|
||||
```
|
||||
|
||||
Components need to inherit the Component class directly and require a name.
|
||||
Components need to inherit the Component class and require a unique name.
|
||||
Components may inherit from other components but must specify another name.
|
||||
You can assign the same 'slot' to both components to have alternative implementations.
|
||||
```python
|
||||
from evennia.contrib.base_systems.components import Component
|
||||
|
||||
|
||||
class Health(Component):
|
||||
name = "health"
|
||||
|
||||
|
||||
class ItemHealth(Health):
|
||||
name = "item_health"
|
||||
slot = "health"
|
||||
```
|
||||
|
||||
Components may define DBFields or NDBFields at the class level.
|
||||
|
|
@ -103,7 +111,10 @@ character.components.add(vampirism)
|
|||
|
||||
...
|
||||
|
||||
vampirism_from_elsewhere = character.components.get("vampirism")
|
||||
vampirism = character.components.get("vampirism")
|
||||
|
||||
# Alternatively
|
||||
vampirism = character.cmp.vampirism
|
||||
```
|
||||
|
||||
Keep in mind that all components must be imported to be visible in the listing.
|
||||
|
|
@ -128,6 +139,14 @@ from typeclasses.components import health
|
|||
```
|
||||
Both of the above examples will work.
|
||||
|
||||
## Known Issues
|
||||
|
||||
Assigning mutable default values such as a list to a DBField will share it across instances.
|
||||
To avoid this, you must set autocreate=True on the field, like this.
|
||||
```python
|
||||
health = DBField(default=[], autocreate=True)
|
||||
```
|
||||
|
||||
## Full Example
|
||||
```python
|
||||
from evennia.contrib.base_systems import components
|
||||
|
|
|
|||
|
|
@ -98,8 +98,7 @@ found.
|
|||
|
||||
## Queryset field lookups
|
||||
|
||||
Above we found roses with exactly the `db_key` `"rose"`. This is an _exact_ match that is _case sensitive_,
|
||||
so it would not find `"Rose"`.
|
||||
Above we found roses with exactly the `db_key` `"rose"`. This is an _exact_ match that is _case sensitive_, so it would not find `"Rose"`.
|
||||
|
||||
```python
|
||||
# this is case-sensitive and the same as =
|
||||
|
|
@ -108,15 +107,13 @@ roses = Flower.objects.filter(db_key__exact="rose"
|
|||
# the i means it's case-insensitive
|
||||
roses = Flower.objects.filter(db_key__iexact="rose")
|
||||
```
|
||||
The Django field query language uses `__` similarly to how Python uses `.` to access resources. This
|
||||
is because `.` is not allowed in a function keyword.
|
||||
The Django field query language uses `__` similarly to how Python uses `.` to access resources. This is because `.` is not allowed in a function keyword.
|
||||
|
||||
```python
|
||||
roses = Flower.objects.filter(db_key__icontains="rose")
|
||||
```
|
||||
|
||||
This will find all flowers whose name contains the string `"rose"`, like `"roses"`, `"wild rose"` etc. The `i` in the beginning makes the search case-insensitive. Other useful variations to use
|
||||
are `__istartswith` and `__iendswith`. You can also use `__gt`, `__ge` for "greater-than"/"greater-or-equal-than" comparisons (same for `__lt` and `__le`). There is also `__in`:
|
||||
This will find all flowers whose name contains the string `"rose"`, like `"roses"`, `"wild rose"` etc. The `i` in the beginning makes the search case-insensitive. Other useful variations to use are `__istartswith` and `__iendswith`. You can also use `__gt`, `__ge` for "greater-than"/"greater-or-equal-than" comparisons (same for `__lt` and `__le`). There is also `__in`:
|
||||
|
||||
```python
|
||||
swords = Weapons.objects.filter(db_key__in=("rapier", "two-hander", "shortsword"))
|
||||
|
|
@ -178,7 +175,7 @@ will_transform = (
|
|||
.filter(
|
||||
db_location__db_tags__db_key__iexact="moonlit",
|
||||
db_attributes__db_key="lycantrophy",
|
||||
db_attributes__db_value__gt=2
|
||||
db_attributes__db_value__eq=2
|
||||
)
|
||||
)
|
||||
```
|
||||
|
|
@ -193,10 +190,13 @@ Don't confuse database fields with [Attributes](../../../Components/Attributes.m
|
|||
that we can treat like an object for this purpose; it references all Tags on the location)
|
||||
- ... and from those `Tags`, we looking for `Tags` whose `db_key` is "monlit" (non-case sensitive).
|
||||
- **Line 7**: ... We also want only Characters with `Attributes` whose `db_key` is exactly `"lycantrophy"`
|
||||
- **Line 8** :... at the same time as the `Attribute`'s `db_value` is greater-than 2.
|
||||
- **Line 8** :... at the same time as the `Attribute`'s `db_value` is exactly 2.
|
||||
|
||||
Running this query makes our newly lycantrophic Character appear in `will_transform` so we
|
||||
know to transform it. Success!
|
||||
Running this query makes our newly lycantrophic Character appear in `will_transform` so we know to transform it. Success!
|
||||
|
||||
```{important}
|
||||
You can't query for an Attribute `db_value` quite as freely as other data-types. This is because Attributes can store any Python entity and is actually stored as _strings_ on the database side. So while you can use `__eq=2` in the above example, you will not be able to `__gt=2` or `__lt=2` because these operations don't make sense for strings. See [Attributes](../../../Components/Attributes.md#querying-by-attribute) for more information on dealing with Attributes.
|
||||
```
|
||||
|
||||
## Queries with OR or NOT
|
||||
|
||||
|
|
@ -243,7 +243,7 @@ will_transform = (
|
|||
Q(db_location__db_tags__db_key__iexact="moonlit")
|
||||
& (
|
||||
Q(db_attributes__db_key="lycantrophy",
|
||||
db_attributes__db_value__gt=2)
|
||||
db_attributes__db_value__eq=2)
|
||||
| Q(db_tags__db_key__iexact="recently_bitten")
|
||||
))
|
||||
.distinct()
|
||||
|
|
@ -256,7 +256,7 @@ That's quite compact. It may be easier to see what's going on if written this wa
|
|||
from django.db.models import Q
|
||||
|
||||
q_moonlit = Q(db_location__db_tags__db_key__iexact="moonlit")
|
||||
q_lycantropic = Q(db_attributes__db_key="lycantrophy", db_attributes__db_value__gt=2)
|
||||
q_lycantropic = Q(db_attributes__db_key="lycantrophy", db_attributes__db_value__eq=2)
|
||||
q_recently_bitten = Q(db_tags__db_key__iexact="recently_bitten")
|
||||
|
||||
will_transform = (
|
||||
|
|
@ -362,9 +362,7 @@ result = (
|
|||
)
|
||||
```
|
||||
|
||||
Here we used `.annotate` to create two in-query 'variables' `num_objects` and `num_tags`. We then
|
||||
directly use these results in the filter. Using `F()` allows for also the right-hand-side of the filter
|
||||
condition to be calculated on the fly, completely within the database.
|
||||
Here we used `.annotate` to create two in-query 'variables' `num_objects` and `num_tags`. We then directly use these results in the filter. Using `F()` allows for also the right-hand-side of the filter condition to be calculated on the fly, completely within the database.
|
||||
|
||||
## Grouping and returning only certain properties
|
||||
|
||||
|
|
|
|||
|
|
@ -1115,7 +1115,6 @@ AUTH_PASSWORD_VALIDATORS = [
|
|||
},
|
||||
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
|
||||
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
|
||||
{"NAME": "evennia.server.validators.EvenniaPasswordValidator"},
|
||||
]
|
||||
|
||||
# Username validation plugins
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
```{eval-rst}
|
||||
evennia.contrib.base\_systems.components.exceptions
|
||||
==========================================================
|
||||
|
||||
.. automodule:: evennia.contrib.base_systems.components.exceptions
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
```{eval-rst}
|
||||
evennia.contrib.base\_systems.components.listing
|
||||
=======================================================
|
||||
|
||||
.. automodule:: evennia.contrib.base_systems.components.listing
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
```
|
||||
|
|
@ -14,7 +14,9 @@ evennia.contrib.base\_systems.components
|
|||
|
||||
evennia.contrib.base_systems.components.component
|
||||
evennia.contrib.base_systems.components.dbfield
|
||||
evennia.contrib.base_systems.components.exceptions
|
||||
evennia.contrib.base_systems.components.holder
|
||||
evennia.contrib.base_systems.components.listing
|
||||
evennia.contrib.base_systems.components.signals
|
||||
evennia.contrib.base_systems.components.tests
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue