mirror of
https://github.com/evennia/evennia.git
synced 2026-03-31 21:17:17 +02:00
Add action for setting attributes via endpoint
This commit is contained in:
parent
6f350c60c2
commit
2798dfb712
5 changed files with 92 additions and 8 deletions
|
|
@ -277,7 +277,7 @@ class PickledObjectField(models.Field):
|
|||
return value
|
||||
|
||||
def value_to_string(self, obj):
|
||||
value = self._get_val_from_obj(obj)
|
||||
value = self.value_from_object(obj)
|
||||
return self.get_db_prep_value(value)
|
||||
|
||||
def get_internal_type(self):
|
||||
|
|
|
|||
|
|
@ -1,3 +1,14 @@
|
|||
"""
|
||||
Serializers in the Django Rest Framework are similar to Forms in normal django.
|
||||
They're used for transmitting and validating data, both going to clients and
|
||||
coming to the server. However, where forms often contained presentation logic,
|
||||
such as specifying widgets to use for selection, serializers typically leave
|
||||
those decisions in the hands of clients, and are more focused on converting
|
||||
data from the server to JSON (serialization) for a response, and validating
|
||||
and converting JSON data sent from clients to our enpoints into python objects,
|
||||
often django model instances, that we can use (deserialization).
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from evennia.objects.models import ObjectDB
|
||||
|
|
|
|||
|
|
@ -110,3 +110,24 @@ class TestEvenniaRESTApi(EvenniaTest):
|
|||
# check success when sending the required data
|
||||
response = self.client.post(view_url, data=view.create_data)
|
||||
self.assertEqual(response.status_code, 201, f"Response was {response.data}")
|
||||
|
||||
def test_set_attribute(self):
|
||||
views = self.get_view_details("set-attribute")
|
||||
for view in views:
|
||||
with self.subTest(msg=f"Testing {view.view_name}"):
|
||||
view_url = reverse(f"api:{view.view_name}", kwargs={"pk": view.obj.pk})
|
||||
# check failures from not sending required fields
|
||||
response = self.client.post(view_url)
|
||||
self.assertEqual(response.status_code, 400, f"Response was: {response.data}")
|
||||
# test adding an attribute
|
||||
self.assertEqual(view.obj.db.some_test_attr, None)
|
||||
attr_name = "some_test_attr"
|
||||
attr_data = {"db_key": attr_name, "db_value": "test_value"}
|
||||
response = self.client.post(view_url, data=attr_data)
|
||||
self.assertEqual(response.status_code, 200, f"Response was: {response.data}")
|
||||
self.assertEquals(view.obj.attributes.get(attr_name), "test_value")
|
||||
# now test removing it
|
||||
attr_data = {"db_key": attr_name}
|
||||
response = self.client.post(view_url, data=attr_data)
|
||||
self.assertEqual(response.status_code, 200, f"Response was: {response.data}")
|
||||
self.assertEquals(view.obj.attributes.get(attr_name), None)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,20 @@
|
|||
"""
|
||||
The Django Rest Framework provides a way of generating urls for different
|
||||
views that implement standard CRUD operations in a quick way, using 'routers'
|
||||
and 'viewsets'. A viewset implements standard CRUD actions and any custom actions
|
||||
that you want, and then a router will automatically generate URLs based on the
|
||||
actions that it detects for a viewset. For example, below we create a DefaultRouter.
|
||||
We then register ObjectDBViewSet, a viewset for CRUD operations for ObjectDB
|
||||
instances, to the 'objects' base endpoint. That will generate a number of URLs
|
||||
like the following:
|
||||
list objects: action: GET, url: /objects/, view name: object-list
|
||||
create object: action: POST, url: /objects/, view name: object-list
|
||||
retrieve object: action: GET, url: /objects/<:pk>, view name: object-detail
|
||||
update object: action: POST, url: /objects/<:pk>, view name: object-detail
|
||||
delete object: action: DELETE, url: /objects/<:pk>, view name: object-detail
|
||||
set attribute: action: POST, url: /objects/<:pk>/set-attribute, view name: object-set-attribute
|
||||
"""
|
||||
|
||||
from rest_framework import routers
|
||||
from evennia.web.api.views import (
|
||||
ObjectDBViewSet,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ can generate a number of views for the common CRUD operations.
|
|||
"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import status
|
||||
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
|
||||
|
|
@ -18,17 +20,28 @@ from evennia.web.api.permissions import EvenniaPermission
|
|||
|
||||
|
||||
class TypeclassViewSetMixin(object):
|
||||
"""
|
||||
This mixin adds some shared functionality to each viewset of a typeclass. They all use the same
|
||||
permission classes and filter backend. You can override any of these in your own viewsets.
|
||||
"""
|
||||
# permission classes determine who is authorized to call the view
|
||||
permission_classes = [EvenniaPermission]
|
||||
# the filter backend allows for retrieval views to have filter arguments passed to it
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
|
||||
|
||||
class ObjectDBViewSet(TypeclassViewSetMixin, ModelViewSet):
|
||||
serializer_class = ObjectDBSerializer
|
||||
queryset = ObjectDB.objects.all()
|
||||
filterset_class = ObjectDBFilterSet
|
||||
|
||||
@action(detail=True, methods=["put", "post"])
|
||||
def add_attribute(self, request, pk=None):
|
||||
def set_attribute(self, request, pk=None):
|
||||
"""
|
||||
This is an example of a custom action added to a viewset. Based on the name of the
|
||||
method, it will create a default url_name (used for reversing) and url_path.
|
||||
The 'pk' argument is automatically passed to this action because it has a url path
|
||||
of the format <object type>/:pk/set-attribute. The get_object method is automatically
|
||||
set in the expected viewset classes that will inherit this, using the pk that's
|
||||
passed along to retrieve the object.
|
||||
|
||||
This action will set an attribute if the db_value is defined, or remove it
|
||||
if no db_value is provided.
|
||||
"""
|
||||
attr = AttributeSerializer(data=request.data)
|
||||
obj = self.get_object()
|
||||
if attr.is_valid(raise_exception=True):
|
||||
|
|
@ -44,27 +57,49 @@ class ObjectDBViewSet(TypeclassViewSetMixin, ModelViewSet):
|
|||
handler.add(key=key, value=value, category=category)
|
||||
else:
|
||||
handler.remove(key=key, category=category)
|
||||
return Response(AttributeSerializer(obj.db_attributes.all(), many=True).data, status=status.HTTP_200_OK)
|
||||
return Response(attr.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
class ObjectDBViewSet(TypeclassViewSetMixin, ModelViewSet):
|
||||
"""
|
||||
An example of a basic viewset for all ObjectDB instances. It declares the
|
||||
serializer to use for both retrieving and changing/creating/deleting
|
||||
instances. Serializers are similar to django forms, used for the
|
||||
transmitting of data (typically json).
|
||||
"""
|
||||
serializer_class = ObjectDBSerializer
|
||||
queryset = ObjectDB.objects.all()
|
||||
filterset_class = ObjectDBFilterSet
|
||||
|
||||
|
||||
class CharacterViewSet(ObjectDBViewSet):
|
||||
"""
|
||||
This overrides the queryset to only retrieve Character objects
|
||||
based on your DefaultCharacter typeclass path.
|
||||
"""
|
||||
queryset = DefaultCharacter.objects.typeclass_search(DefaultCharacter.path, include_children=True)
|
||||
|
||||
|
||||
class RoomViewSet(ObjectDBViewSet):
|
||||
"""Viewset for Room objects"""
|
||||
queryset = DefaultRoom.objects.typeclass_search(DefaultRoom.path, include_children=True)
|
||||
|
||||
|
||||
class ExitViewSet(ObjectDBViewSet):
|
||||
"""Viewset for Exit objects"""
|
||||
queryset = DefaultExit.objects.typeclass_search(DefaultExit.path, include_children=True)
|
||||
|
||||
|
||||
class AccountDBViewSet(TypeclassViewSetMixin, ModelViewSet):
|
||||
"""Viewset for Account objects"""
|
||||
serializer_class = AccountDBSerializer
|
||||
queryset = AccountDB.objects.all()
|
||||
filterset_class = AccountDBFilterSet
|
||||
|
||||
|
||||
class ScriptDBViewSet(TypeclassViewSetMixin, ModelViewSet):
|
||||
"""Viewset for Script objects"""
|
||||
serializer_class = ScriptDBSerializer
|
||||
queryset = ScriptDB.objects.all()
|
||||
filterset_class = ScriptDBFilterSet
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue