Skip to content

Commit

Permalink
Added SmartModel default __str__ method and add ordering to first/las…
Browse files Browse the repository at this point in the history
…t queryset method
  • Loading branch information
Lubos Matl committed Sep 21, 2020
1 parent e8cbb50 commit d634a94
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 4 deletions.
34 changes: 30 additions & 4 deletions chamber/models/__init__.py
Expand Up @@ -6,6 +6,7 @@

import django
from django.db import models, transaction, OperationalError
from django.db.models.manager import BaseManager
from django.db.models.base import ModelBase
from django.utils.translation import ugettext_lazy as _
from django.utils.functional import cached_property
Expand Down Expand Up @@ -264,11 +265,33 @@ def change_and_save(self, update_only_changed_fields=False, **changed_fields):
bulk_change_and_save(self, update_only_changed_fields=update_only_changed_fields, **changed_fields)
return self.filter()

def first(self, *field_names):
"""
Adds possibility to set order fields to default Django first method.
"""
if field_names:
return self.order_by(*field_names).first()
else:
return super().first()

def last(self, *field_names):
"""
Adds possibility to set order fields to default Django last method.
"""
if field_names:
return self.order_by(*field_names).last()
else:
return super().last()


class SmartQuerySet(SmartQuerySetMixin, models.QuerySet):
pass


class SmartManager(BaseManager.from_queryset(SmartQuerySet)):
pass


class SmartModelBase(ModelBase):
"""
Smart model meta class that register dispatchers to the post or pre save signals.
Expand All @@ -284,7 +307,7 @@ def __new__(cls, name, bases, attrs):

class SmartModel(AuditModel, metaclass=SmartModelBase):

objects = SmartQuerySet.as_manager()
objects = SmartManager()

dispatchers = []

Expand All @@ -295,6 +318,12 @@ def __init__(self, *args, **kwargs):
self.changed_fields = DynamicChangedFields(self)
self.post_save = Signal(self)

class Meta:
abstract = True

def __str__(self):
return '{} #{}'.format(self._meta.verbose_name, self.pk)

@classmethod
def from_db(cls, db, field_names, values):
new = super().from_db(db, field_names, values)
Expand Down Expand Up @@ -529,9 +558,6 @@ def get_locked_instance(self):

return self.__class__.objects.filter(pk=self.pk).select_for_update().get()

class Meta:
abstract = True


class SmartOptions(Options):

Expand Down
4 changes: 4 additions & 0 deletions docs/models.rst
Expand Up @@ -284,6 +284,10 @@ will assume the custom filters to be there).

Changes selected fields on the selected queryset and saves it and returns changed objects in the queryset. Difference from update is that there is called save method on the instance, but it is slower. If you want to update only changed fields in the database you can use parameter ``update_only_changed_fields`` to achieve it

.. method:: first(**field_names)

Method is only shortcut to ``Model.objects.order_by('field_name').first()``. With this method you can use ``Model.objects.first('field_name')``

.. method:: last(**field_names)

Method is only shortcut to ``Model.objects.order_by('field_name').last()``. With this method you can use ``Model.objects.last('field_name')``
14 changes: 14 additions & 0 deletions example/dj/apps/test_chamber/tests/models/__init__.py
Expand Up @@ -317,3 +317,17 @@ def test_smart_queryset_fast_distinct(self):
assert_equal(qs.count(), 2)
assert_equal(tuple(qs.values_list('pk', flat=True)), (t.pk, t.pk))
assert_equal(qs.fast_distinct().count(), 1)

def test_smart_model_first_and_last_with_order(self):
test3 = TestSmartModel.objects.create(name='3')
test2 = TestSmartModel.objects.create(name='2')
test1 = TestSmartModel.objects.create(name='1')

assert_equal(TestSmartModel.objects.first('id'), test3)
assert_equal(TestSmartModel.objects.last('id'), test1)

assert_equal(TestSmartModel.objects.first('name'), test1)
assert_equal(TestSmartModel.objects.last('name'), test3)

assert_equal(TestSmartModel.objects.filter(name='2').first(), test2)
assert_equal(TestSmartModel.objects.filter(name='2').last(), test2)

0 comments on commit d634a94

Please sign in to comment.