From 2cb8a0138a147286d42b82e2682fe2e11e12de65 Mon Sep 17 00:00:00 2001 From: Lubos Matl Date: Mon, 21 Sep 2020 10:32:36 +0200 Subject: [PATCH] Added SmartModel default __str__ method and add ordering to first/last queryset method --- chamber/models/__init__.py | 27 ++++++++++++++++--- docs/models.rst | 4 +++ .../test_chamber/tests/models/__init__.py | 14 ++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/chamber/models/__init__.py b/chamber/models/__init__.py index 4d59305..6255a9c 100644 --- a/chamber/models/__init__.py +++ b/chamber/models/__init__.py @@ -264,6 +264,24 @@ 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 @@ -295,6 +313,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) @@ -529,9 +553,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): diff --git a/docs/models.rst b/docs/models.rst index 17ea0f4..fc4f7f0 100644 --- a/docs/models.rst +++ b/docs/models.rst @@ -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')`` diff --git a/example/dj/apps/test_chamber/tests/models/__init__.py b/example/dj/apps/test_chamber/tests/models/__init__.py index 100a49e..29bd7fe 100644 --- a/example/dj/apps/test_chamber/tests/models/__init__.py +++ b/example/dj/apps/test_chamber/tests/models/__init__.py @@ -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)