Ralph API resources¶
How to create new API resource based on Django model¶
# model
from django.db import models
class Foo(model.Model):
bar = models.CharField(max_length=10)
# API
from ralph.api import RalphAPISerializer, RalphAPIViewSet, router
class FooSerializer(RalphAPISerializer):
class Meta:
model = Foo
class FooViewSet(RalphAPIViewSet):
queryset = Foo.objects.all()
serializer_class = FooSerializer
# use Ralph router instance to register new viewset
router.register(r'foos', FooViewSet)
What are built-in features of Ralph API classes?¶
RalphAPISerializer¶
- include both object PK and its url (see
ralph.api.serializers.RalphAPISerializer.get_default_field_namesfor details). - every sub-serializer (even instantiated directly as a field in other serializer) have current context set.
- use
ralph.api.serializers.ReversedChoiceFieldfor all choice fields - this serializer allow to pass value by name instead of key. Additionally it present value in user-friendly format by-name. This field works perfectly withdj.choices.Choices. - include permissions per field checking using
ralph.lib.permissions.api.PermissionsPerFieldSerializerMixin- only fields to which user has access will be returned. This field also handle view-only permission as read-only field. - include permission validation on object level for related fields - if related field model use permissions for object, then only objects to which user has access could be selected/displayed in related field.
- validate data using model's clean validation (set
_validate_using_model_cleantoFalsein your save seriazlier to turn this off)
RalphAPIViewSet¶
- default serializer for save actions (POST, PUT, PATCH) in which every relation will be serialized using
rest_framework.serializers.PrimaryKeyRelatedField(so user should specify object PK in relation field). This serializer could be overwritten usingsave_serializer_classattribute inRalphAPIViewSet. - include
ralph.api.utils.QuerysetRelatedMixinwhich can easily handle select_related and prefetch_related on queryset. By default select_related is fill with related admin site list_select_related value. - include
ralph.api.viewsets.AdminSearchFieldsMixinthanks to which search fields will be by default taken from related admin site. - include
ralph.api.permissions.RalphPermission, which check if user is properly authenticated (throughIsAuthenticated), user has access to object (throughObjectPermissionsMixin) and user has proper Django admin permissions (add_*,change_*,delete_*) requested model.
Filter backends¶
By default RalphAPIViewSet use the following filter backends:
* rest_framework.filters.DjangoFilterBackend - provides basic filtering for Django model - in RalphAPIViewSet (through AdminSearchFieldsMixin) filter fields are associated with model's admin.
* ralph.lib.permissions.api.PermissionsForObjectFilter - limit result only to object for which user has permission at least to view.
* rest_framework.filters.OrderingFilter - order queryset using order url param.
* ralph.api.filters.ExtendedFiltersBackend - allows to filter for multiple fields using single query param - it's usefull especially for polymorphic models. To use extended filters define extended_filter_fields in your view, ex. extended_filter_fields = {'name': ['asset__hostname', ip__address', 'cloudhost__hostname'] - this filter will allow you to search using name query param and it will be resolved to compound search (using OR operator) for fields asset__hostname, ip__address or cloudhost__hostname (ex. <URL>?name=abc will result in search Q(asset__hostname=abc) | Q(ip__address=abc) | Q(cloudhost__hostname=abc)).
* ralph.api.filters.LookupFilterBackend - filter by lookups (using Django's __ convention) in query params, ex. <URL>?barcode__startswit=123 or <URL>?invoice_date__lte=2015-01-01.
* ralph.api.filters.TagsFilterBackend - Filter queryset by tags. Multiple tags could be specified in url query: <URL>?tag=abc&tag=def&tag=123.
Note that polymorphic models (api resources) by default support lookup filters and extended filters, so you could call compound query on your polymorphic-root model, ex.
<URL>/base-objects/?name__startswith=abc, which will be resolved to query, checking if one of fields defined inextended_filter_fields(in above exampleasset__hostname,ip__addressorcloudhost__hostname) startswithabc.