django-anvil v0.1
🔍Search docs...⌘K
Core concepts

The Resource class

A Resource is the single declarative description of everything Anvil generates for a model. Define it once in <app>/resources.py; it registers itself automatically (the same way Django's own admin.py autodiscovery works) — no manual registration call needed.

from django_anvil.core.resource import Resource
from django_anvil.mixins import SoftDeleteViewSetMixin, TimestampedSerializerMixin
from .models import Product

class ProductResource(Resource):
    model = Product
    fields = ["id", "name", "price", "stock", "is_active", "created_at"]
    read_only_fields = ["id", "created_at"]
    searchable = ["name"]
    filters = ["is_active"]
    sortable = ["price", "created_at"]
    mixins = [SoftDeleteViewSetMixin, TimestampedSerializerMixin]

    # optional -- see their own pages
    permissions = {}
    tenant_scoped = False
    audited = False

Field declarations

AttributeControls
fieldsEvery field exposed on the serializer (readable + writable, unless also listed in read_only_fields)
read_only_fieldsVisible in responses, rejected in request bodies
searchableWired into DRF's SearchFilter (?search=)
filtersWired into django-filter's DjangoFilterBackend (?field=value)
sortableWired into DRF's OrderingFilter (?ordering=-field)

These wrap django-filter and DRF's own filter backends directly — Anvil doesn't reimplement filtering, it just wires the declaration through.

What gets generated

One anvil resource Product call produces:

FileContent
api/serializers.pyProductSerializer(ModelSerializer)
api/views.pyProductViewSet(ModelViewSet) — full CRUD, filters wired
api/urls.pyRouter registration for the viewset
admin.pyProductAdmin registration, merged into the file if it already has content
tests/test_product_api.pyList/create/retrieve/delete tests against a real running API, using the DRF test client

Every generated file is normal, readable Django/DRF code — no runtime magic, no base classes you can't read the source of. Edit it by hand afterward like anything else in your project; that's the point.

Mixins

django_anvil.mixins ships real, reusable behavior — not codegen templates. A Resource opts in by listing them in mixins; the generator wires the matching one into the serializer or viewset base classes based on its name (...SerializerMixin vs ...ViewSetMixin).

SoftDeleteViewSetMixin

Requires an is_deleted boolean field. Excludes soft-deleted rows from every query and turns DELETE into setting the flag instead of removing the row.

class SoftDeleteViewSetMixin:
    def get_queryset(self):
        return super().get_queryset().filter(is_deleted=False)

    def perform_destroy(self, instance):
        instance.is_deleted = True
        instance.save(update_fields=["is_deleted"])

OwnerScopedViewSetMixin

Requires an owner FK to the user model. Scopes every action — including list/retrieve — to request.user's own rows, and auto-assigns the owner on create. Fails closed (empty, not a crash) for anonymous requests.

⚠️

This means "your own stuff only", for every action — like a private notes or wishlist feature. Don't pair it with permissions = {"view": "public"}" expecting a public-reads/private-writes feed (e.g. product reviews visible to everyone); that needs a different get_queryset than this mixin provides out of the box.

TimestampedSerializerMixin

Marks created_at/updated_at read-only on the serializer if present, so callers can't set timestamps through the API even if you forgot to list them in read_only_fields.

Write your own the same way: a plain class following the naming convention, mixed into the generated ModelViewSet/ModelSerializer. Multiple mixins compose via normal Python MRO — put the one that should run last-in-chain closest to the base class.

Multiple Resources in one app

serializers.py, views.py, urls.py, and admin.py are shared, per-app files. Generating a second Resource (Coupon, say) into an app that already has Product adds its classes alongside — merges the router registration, folds new imports into existing from ..models import ... lines (sorted, deduplicated), and never disturbs Product's own generated code.

python manage.py anvil resource Product
python manage.py anvil resource Coupon   # adds CouponSerializer/ViewSet alongside Product's