| published by | Software Crafts |
|---|---|
| in blog | Software Crafts |
| original entry | Is this the beginning of a new Django admin... |
Ok, the title was clickbait! Today I properly started working on the new startup. First up is an abstract base model for every other model to inherit. I got to this point:
class BaseModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
external_id = models.UUIDField(default=uuid7, editable=False, unique=True)
class Meta(TypedModelMeta):
abstract = True
def get_absolute_url(self):
return reverse(...)
At this point, I thought could I have a detail view for any object in my database (without manually creating a view for it), accessed by get_absolute_url. Naturally Neapolitan came to mind and I started to play around with it and landed on this modified version of the CRUDView.
class MyRole:
def reverse(self, view, object=None):
url_name = f"{view.get_url_base()}-{self.url_name_component}"
url_kwarg = view.lookup_url_kwarg or view.lookup_field
match self:
case Role.LIST | Role.CREATE:
return reverse(url_name)
case _:
return reverse(
url_name,
kwargs={url_kwarg: getattr(object, view.lookup_field)},
)
Role.reverse = MyRole.reverse
class GenericCRUDView(CRUDView):
lookup_field = 'pk'
def setup(self, request, *args, **kwargs):
super().setup(request, *args, **kwargs)
app, model = self.request.path.split('/')[1].split('-')
self.model = apps.get_model(f"{app}.{model}")
self.fields = [field.name for field in self.model._meta.fields]
def get_url_base(self):
return f'{self.model._meta.app_label}-{self.model._meta.model_name}'
@classproperty
def url_base(cls):
return f'{cls.model._meta.app_label}-{cls.model._meta.model_name}'
@classmethod
def get_all_urls(cls):
urls = []
for model in apps.get_models():
GenericCRUDView.model = model
urls += GenericCRUDView.get_urls()
return urls
First up I added the classmethod of get_all_urls to go through each model and generate the urls required. Next the modification to setup is to dynamically set the model and fields based on the path from the browser which is <app_label>-<model_name>. This is in combination with overriding url_base to match.
This worked, except that the links generated only match the last model set as the class attribute in get_all_models. To fix this I had to monkey patch the reverse in the Role class to switch view.url_base for view.get_url_base which are the same except for one is the class and one is for the instance.
The main thing on the surface that is missing is an index page to list each of the models and we are close to the beginnings of an admin. As for me I will be content with having a single get_absolute_url method in my codebase, at least to begin with!