Source code for djmvc
"""djmvc public API.
:data:`site` is the root :class:`Site` controller. Append controllers to
``site.routes`` in each app's ``djmvc.py`` module; :meth:`Site.build` imports
those modules via autodiscovery (like Django admin's ``admin.py``).
"""
from django.db import models as db_models
from django.utils.module_loading import autodiscover_modules
from .controller import Controller
from .view import View
from .model import ModelMixin
from .views import generic
[docs]
class ModelController(ModelMixin, Controller):
"""CRUD controller for a single Django model.
Attributes:
routes: Default list, detail, create, update, delete, and bulk-delete
views. Extend with ``ModelController.routes + [MyView]`` or
replace entries by codename (see :class:`~djmvc.registry.Registry`).
model: Django model class managed by this controller.
icon (str): Bootstrap Icons name for the navigation list view.
color (str): Bulma color for the navigation list icon.
"""
routes = [
generic.ListView,
generic.DetailView,
generic.UpdateView,
generic.DeleteView,
generic.DeleteObjectsView,
generic.CreateView,
]
@property
def codename(self):
"""URL segment from :attr:`model` name (lowercase)."""
return self.model.__name__.lower()
[docs]
def has_permission(self, view):
"""Check Django permissions for *view* via the permission backend."""
return view.has_permission_backend()
[docs]
def get_queryset(self, view):
"""Return all rows for *view*; override to scope per user or role."""
return self.model._default_manager.all()
json_fields = None
[docs]
def get_json_fields(self):
"""Field names exposed in JSON responses."""
if self.json_fields is not None:
return list(self.json_fields)
return [f.name for f in self.model._meta.fields]
def get_FIELD_json(self, obj, field):
value = getattr(obj, field)
if callable(value):
value = value()
if value is not None and not isinstance(value, (str, int, float, bool)):
value = str(value)
return value
[docs]
def serialize(self, obj, fields=None):
"""Map a model instance to a JSON-serializable dict."""
fields = fields or self.get_json_fields()
return {
field: getattr(
self,
f'get_{field}_json',
self.get_FIELD_json,
)(obj, field)
for field in fields
}
def get_swagger_model_name(self, request):
return self.model.__name__
def get_swagger_model_definition(self, request):
result = {'properties': {}, 'type': 'object'}
int_fields = (
db_models.IntegerField,
db_models.BigIntegerField,
db_models.AutoField,
db_models.PositiveIntegerField,
db_models.PositiveSmallIntegerField,
db_models.SmallIntegerField,
)
for field in self.model._meta.fields:
custom = getattr(self, f'swagger_field_{field.name}_definition', None)
if custom:
result['properties'][field.name] = custom
continue
field_def = {}
if isinstance(field, int_fields):
field_def['type'] = 'integer'
elif isinstance(field, db_models.BooleanField):
field_def['type'] = 'boolean'
elif isinstance(field, db_models.JSONField):
field_def['type'] = 'object'
else:
field_def['type'] = 'string'
result['properties'][field.name] = field_def
return result
[docs]
class Home(generic.TemplateView):
"""Site root page at ``/``."""
urlpath = ''
[docs]
def has_permission(self):
"""Allow anonymous access to the home page."""
return True
[docs]
class Site(Controller):
"""Root site controller; autodiscovers ``djmvc.py`` in installed apps."""
urlpath = ''
routes = [
Home,
]
[docs]
def autodiscover(self):
"""Import ``djmvc`` modules from every installed app."""
autodiscover_modules('djmvc')
return self
def build(self):
"""Autodiscover app routes, then build the route registry."""
self.autodiscover()
return super().build()
site = Site()