django-ledger
django-ledger copied to clipboard
Using BaseClass for Views / Forms / Models
Is your feature request related to a problem? Please describe. No. By checking out the code i've noticed that most of the classes use common fields, properties, contexts
Describe the solution you'd like I'm workig on a similar project (it's like mini erp system) and I try to use shred base classes as much as I can, to avoid make repeated contexts in views, declare the same field in all models (like id, created_at, create_by, modified_at_modified_by, ...)...
Additional context Example
A Base Class Model :
class BaseModel(models.Model):
id = models.AutoField(_('Id'), primary_key=True)
active = models.BooleanField(_('Active'), default=True, blank=True, null=True)
created_at = models.DateField( _('Created at'), auto_now_add=True, blank=True, null=True)
updated_at = models.DateField( _('Updated at'), auto_now=True, blank=True, null=True)
created_by = models.ForeignKey('base.User', on_delete=models.PROTECT, related_name='%(class)s_created_by', verbose_name=_('Created by'))
updated_by = models.ForeignKey('base.User', on_delete=models.PROTECT, related_name='%(class)s_updated_by', verbose_name=_('Updated by'))
base_company = models.ForeignKey('base.Company', on_delete=models.PROTECT, blank=True, null=True, verbose_name=_('Company'), related_name="%(class)s_company")
class Meta:
ordering = ['pk']
abstract = True
Item Model inherits BaseModel :
class Item(BaseModel):
...
class Meta:
verbose_name = _("Item")
verbose_name_plural = _("Items")
A Base View regroups all the shared contexts and the template :
class BaseListView(ListView):
template_name = 'base/list.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
object_name = self.model._meta.object_name
verbose_name = self.model._meta.verbose_name
verbose_name_plural = self.model._meta.verbose_name_plural
context['page_title'] = _('{}'.format(verbose_name_plural))
context["btn_create_title"] = _('New {}'.format(verbose_name))
context["btn_update_title"] = _('Update {}'.format(verbose_name))
context['btn_detail_url'] = '{}:detail'.format(object_name)
context['add_url'] = reverse_lazy('{}:add'.format(object_name))
context['edit_url'] = '{}:edit'.format(object_name)
return context
def get_queryset(self):
queryset = self.model.objects.filter()
return queryset
class Meta:
abstract = True
And since all list pages are rendred the same way, (A table with some action buttons) why not using the same template ?
You see that what evev the self.object
is in ModelView, it will generate page title, action buttons' titles (Create new ..., Update ..., Delete ...) the same way. What happens if you guys decide to use "Edit .." for the edit button rather than "Update ...", you have to change this in all the Views.
Same things for CreateView, UpdateView, they use the same template (it's a little bit tricky, but I made to work properly)
This way, I can create a new Model -> View -> Form and make it works (List of objects, Create, Update & Delete Object) in few minutes
I'd love to help if I can, let me know what you think.
And this how my shared CreateView looks like :
class BaseCreateView(CreateView):
template_name = 'stock/item-form.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
verbose_name = self.model._meta.verbose_name
context["page_title"] = _('Create new {}'.format(verbose_name))
context["action_type"] = "create"
return context
def form_valid(self, form):
form.instance.created_by = self.request.user
form.instance.updated_by = self.request.user
form.instance.created_at = timezone.now()
form.instance.updated_at = timezone.now()
form.instance.base_company = self.request.user.current_company
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy('{}:detail'.format(self.model._meta.object_name), kwargs={'pk': self.object.pk})
class Meta:
abstract = True
I agree with your approach. Django Ledger makes use of MixIns to encapsulate common behavior among views and avoid repetition. Can you suggest changes to the Django Ledger code to accomplish what you are proposing?
Thanks
The code has been refactored since version 0.4 to incorporate good practices like the one described on this issue.