Django Staskstore model
=========================================================================================
[updated fork of django-staskstore-model](https://pypi.org/project/django-stackstore-model/)
`django-staskstore-model` is a library that can support model versioning in a minimal amount of steps.
- Support Django 3, 4 and 5
- Support Python3.8, 3.9, 3.10, 3.11 and 3.12
- Admin extensions are supported.
# Usage
## Model
```
# models.py
from stackstore.models import AbstractStackModel
class MySampleModel(AbstractStackModel):
title = models.CharField(
max_length=100,
null=False,
blank=False,
)
body = models.TextField(
max_length=1000,
null=False,
blank=False,
)
```
Python shell
```
# Create First version instance
>>> instance = MySampleModel.objects.create(title="Test", body="This is test text")
>>> instance.pk
1
# If you save this instance, create new version instance
>>> instance.title = "Test (version2)"
>>> instance.save()
>>> instance.pk
2
# If you can fetch previous version
>>> previous_instance = instance.previous_instance()
>>> previous_instance.pk
1
# You can get next version
>>> previous_instance.next_instance().pk
2
```
## Admin Extension
### Filter to show only the latest version of the object
<img src="https://raw.githubusercontent.com/wiki/salexkidd/django-stackstore-model/images/latest_only.gif" width="800px">
### Show only items with the same stackgroup_uuid
<img src="https://raw.githubusercontent.com/wiki/salexkidd/django-stackstore-model/images/same_item.gif" width="800px">
# API
## QuerySet & Manager
### latest_from_stack_group
Returns a QuerySet of the most recent objects in each Stackgroup.
```
# Create instance
>>> instance_breakfast = MySampleModel.objects.create(title="Today's breakfast", body="Spam with Egg") # Create <MySampleModel: MySampleModel object (1)>
>>> instance_lunch = MySampleModel.objects.create(title="Today's lunch", body="Spam with Beacon") # Create <MySampleModel: MySampleModel object (2)>
# Save each instance
>>> instance_breakfast.body = "Fried Egg with bread"
>>> instance_breakfast.save() # Save method create new <MySampleModel: MySampleModel object (3)>
>>> instance_lunch.body = "Meat Pasta"
>>> instance_lunch.save() # Save method create new <MySampleModel: MySampleModel object (4)>
>>> MySampleModel.objects.latest_from_stack_group() # You can fetch 3 & 4 My Sample Model
<StackStoreQuerySet [<MySampleModel: MySampleModel object (3)>, <MySampleModel: MySampleModel object (4)>]>
```
### get_latest_from_stack_group
Returns an object that matches the collation parameter from the latest set of objects in each Stackgroup.
```
# Create instance
>>> instance_breakfast = MySampleModel.objects.create(title="Today's breakfast", body="Spam with Egg") # Create <MySampleModel: MySampleModel object (1)>
>>> instance_lunch = MySampleModel.objects.create(title="Today's lunch", body="Spam with Beacon") # Create <MySampleModel: MySampleModel object (2)>
# Save each instance
>>> instance_breakfast.body = "Fried Egg with bread"
>>> instance_breakfast.save() # Save method create new <MySampleModel: MySampleModel object (3)>
>>> MySampleModel.objects.get_latest_from_stack_group(body="Fried Egg with bread")
<MySampleModel: MySampleModel object (3)>
```
## model object
### save
When an object is saved, a new object is created and assigned the same stack_group_uuid as the object from which it was saved.
This means that a new version will be generated.
```
>>> instance_breakfast = MySampleModel.objects.create(title="Today's breakfast", body="Spam with Egg") # Create <MySampleModel: MySampleModel object (1)>
>>> instance_breakfast.body = "Fried Egg with bread"
>>> instance_breakfast.save() # Save method create version object <MySampleModel: MySampleModel object (2)>
>>> MySampleModel.objects.all()
<StackStoreQuerySet [<MySampleModel: MySampleModel object (1)>, <MySampleModel: MySampleModel object (2)>]>
```
If you want to save the overwrite without creating a new version, you should pass `False` to `__create_new_version` in the `save` method.
```
>>> instance_breakfast = MySampleModel.objects.create(title="Today's breakfast", body="Spam with Egg")
>>> instance_breakfast.save(__create_new_version=False)
>>> instance_breakfast.pk
1
```
### force_delete
Remove the object.
```
>>> instance_breakfast = MySampleModel.objects.create(title="Today's breakfast", body="Spam with Egg") # Create <MySampleModel: MySampleModel object (1)>
>>> MySampleModel.objects.all()
<StackStoreQuerySet [<MySampleModel: MySampleModel object (1)>]>
>>> instance_breakfast.force_delete()
>>> MySampleModel.objects.all()
<StackStoreQuerySet []>
```
Calling the existing `delete` method will raise a NotImplementedError exception.
### same_group_items
Returns a QuerySet that returns all objects belonging to the same Stackgroup.
```
>>> instance_breakfast = MySampleModel.objects.create(title="Today's breakfast", body="Spam with Egg") # Create <MySampleModel: MySampleModel object (1)>
>>> [instance_breakfast.save() for i in range(2)]
>>> instance_breakfast.same_group_items()
<StackStoreQuerySet [<MySampleModel: MySampleModel object (3)>, <MySampleModel: MySampleModel object (2)>, <MySampleModel: MySampleModel object (1)>]>
```
### previous_instance
Returns the previous version of the object.
```
>>> instance_breakfast = MySampleModel.objects.create(title="Today's breakfast", body="Spam with Egg") # Create <MySampleModel: MySampleModel object (1)>
>>> [instance_breakfast.save() for i in range(2)]
>>> second_gen_instance = instance_breakfast.same_group_items().order_by("pk")[1]
>>> second_gen_instance.previous_instance()
<MySampleModel: MySampleModel object (1)>
```
Throws a DoesNotExist exception if the object does not exist.
### next_instance
Returns the next version of the object.
```
>>> instance_breakfast = MySampleModel.objects.create(title="Today's breakfast", body="Spam with Egg") # Create <MySampleModel: MySampleModel object (1)>
>>> [instance_breakfast.save() for i in range(2)]
>>> second_gen_instance = instance_breakfast.same_group_items()[1]
>>> second_gen_instance.next_instance()
<MySampleModel: MySampleModel object (3)>
```
Throws a DoesNotExist exception if the object does not exist.
### latest_instance
Returns the most recent object of the Stackgroup to which its own object belongs.
```
>>> instance_breakfast = MySampleModel.objects.create(title="Today's breakfast", body="Spam with Egg") # Create <MySampleModel: MySampleModel object (1)>
>>> [instance_breakfast.save() for i in range(2)]
>>> first_gen_instance = instance_breakfast.same_group_items().order_by("pk")[0]
>>> first_gen_instance.latest_instance()
<MySampleModel: MySampleModel object (3)>
```
Throws a DoesNotExist exception if the object does not exist.
### earliest_instance
Returns the oldest object in the Stackgroup to which its own object belongs.
```
>>> instance_breakfast = MySampleModel.objects.create(title="Today's breakfast", body="Spam with Egg") # Create <MySampleModel: MySampleModel object (1)>
>>> [instance_breakfast.save() for i in range(2)]
>>> third_gen_instance = instance_breakfast.same_group_items().order_by("pk")[2]
>>> third_gen_instance.earliest_instance()
<MySampleModel: MySampleModel object (1)>
```
Throws a DoesNotExist exception if the object does not exist.
# Demo
The Docker configuration is provided. Please use the following command to start it. Go to [http://localhost:8000](http://localhost:8000) when the launch is complete.
```
$ docker-compose up
```
Login account is ID: `admin` Password: `admin`
# License
MIT License
Raw data
{
"_id": null,
"home_page": "https://github.com/c2emarket-ooppyy/django-stackstore-model",
"name": "django-stackstore-model-ooppyy",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": "django, model, versioning",
"author": "OoppyY",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/48/27/8a5e2444c4add44d6d278d76e260bce8c6a4b2767506bdaf73a045bb3026/django-stackstore-model-ooppyy-1.0.tar.gz",
"platform": null,
"description": "Django Staskstore model\n=========================================================================================\n\n[updated fork of django-staskstore-model](https://pypi.org/project/django-stackstore-model/)\n\n`django-staskstore-model` is a library that can support model versioning in a minimal amount of steps.\n\n- Support Django 3, 4 and 5\n- Support Python3.8, 3.9, 3.10, 3.11 and 3.12\n- Admin extensions are supported.\n\n# Usage\n\n## Model\n\n```\n# models.py\nfrom stackstore.models import AbstractStackModel\n\n\nclass MySampleModel(AbstractStackModel):\n title = models.CharField(\n max_length=100,\n null=False,\n blank=False,\n )\n\n body = models.TextField(\n max_length=1000,\n null=False,\n blank=False,\n )\n```\n\nPython shell\n```\n\n# Create First version instance\n>>> instance = MySampleModel.objects.create(title=\"Test\", body=\"This is test text\")\n>>> instance.pk\n1\n\n# If you save this instance, create new version instance\n>>> instance.title = \"Test (version2)\"\n>>> instance.save()\n>>> instance.pk\n2\n\n# If you can fetch previous version\n>>> previous_instance = instance.previous_instance()\n>>> previous_instance.pk\n1\n\n# You can get next version\n>>> previous_instance.next_instance().pk\n2\n```\n\n## Admin Extension\n\n### Filter to show only the latest version of the object\n\n<img src=\"https://raw.githubusercontent.com/wiki/salexkidd/django-stackstore-model/images/latest_only.gif\" width=\"800px\">\n\n\n### Show only items with the same stackgroup_uuid\n\n<img src=\"https://raw.githubusercontent.com/wiki/salexkidd/django-stackstore-model/images/same_item.gif\" width=\"800px\">\n\n\n# API\n\n## QuerySet & Manager\n\n### latest_from_stack_group\n\nReturns a QuerySet of the most recent objects in each Stackgroup.\n\n```\n# Create instance\n>>> instance_breakfast = MySampleModel.objects.create(title=\"Today's breakfast\", body=\"Spam with Egg\") # Create <MySampleModel: MySampleModel object (1)>\n>>> instance_lunch = MySampleModel.objects.create(title=\"Today's lunch\", body=\"Spam with Beacon\") # Create <MySampleModel: MySampleModel object (2)>\n\n# Save each instance\n>>> instance_breakfast.body = \"Fried Egg with bread\"\n>>> instance_breakfast.save() # Save method create new <MySampleModel: MySampleModel object (3)>\n\n>>> instance_lunch.body = \"Meat Pasta\"\n>>> instance_lunch.save() # Save method create new <MySampleModel: MySampleModel object (4)>\n\n>>> MySampleModel.objects.latest_from_stack_group() # You can fetch 3 & 4 My Sample Model\n<StackStoreQuerySet [<MySampleModel: MySampleModel object (3)>, <MySampleModel: MySampleModel object (4)>]>\n\n```\n### get_latest_from_stack_group\n\nReturns an object that matches the collation parameter from the latest set of objects in each Stackgroup.\n\n```\n# Create instance\n>>> instance_breakfast = MySampleModel.objects.create(title=\"Today's breakfast\", body=\"Spam with Egg\") # Create <MySampleModel: MySampleModel object (1)>\n>>> instance_lunch = MySampleModel.objects.create(title=\"Today's lunch\", body=\"Spam with Beacon\") # Create <MySampleModel: MySampleModel object (2)>\n\n# Save each instance\n>>> instance_breakfast.body = \"Fried Egg with bread\"\n>>> instance_breakfast.save() # Save method create new <MySampleModel: MySampleModel object (3)>\n\n>>> MySampleModel.objects.get_latest_from_stack_group(body=\"Fried Egg with bread\")\n<MySampleModel: MySampleModel object (3)>\n```\n\n\n## model object\n\n### save\n\nWhen an object is saved, a new object is created and assigned the same stack_group_uuid as the object from which it was saved.\nThis means that a new version will be generated.\n\n```\n>>> instance_breakfast = MySampleModel.objects.create(title=\"Today's breakfast\", body=\"Spam with Egg\") # Create <MySampleModel: MySampleModel object (1)>\n>>> instance_breakfast.body = \"Fried Egg with bread\"\n>>> instance_breakfast.save() # Save method create version object <MySampleModel: MySampleModel object (2)>\n>>> MySampleModel.objects.all()\n<StackStoreQuerySet [<MySampleModel: MySampleModel object (1)>, <MySampleModel: MySampleModel object (2)>]>\n```\n\nIf you want to save the overwrite without creating a new version, you should pass `False` to `__create_new_version` in the `save` method.\n\n```\n>>> instance_breakfast = MySampleModel.objects.create(title=\"Today's breakfast\", body=\"Spam with Egg\")\n>>> instance_breakfast.save(__create_new_version=False)\n>>> instance_breakfast.pk\n1\n```\n\n### force_delete\n\nRemove the object.\n\n```\n>>> instance_breakfast = MySampleModel.objects.create(title=\"Today's breakfast\", body=\"Spam with Egg\") # Create <MySampleModel: MySampleModel object (1)>\n>>> MySampleModel.objects.all()\n<StackStoreQuerySet [<MySampleModel: MySampleModel object (1)>]>\n>>> instance_breakfast.force_delete()\n>>> MySampleModel.objects.all()\n<StackStoreQuerySet []>\n```\n\nCalling the existing `delete` method will raise a NotImplementedError exception.\n\n### same_group_items\n\nReturns a QuerySet that returns all objects belonging to the same Stackgroup.\n\n```\n>>> instance_breakfast = MySampleModel.objects.create(title=\"Today's breakfast\", body=\"Spam with Egg\") # Create <MySampleModel: MySampleModel object (1)>\n>>> [instance_breakfast.save() for i in range(2)]\n>>> instance_breakfast.same_group_items()\n<StackStoreQuerySet [<MySampleModel: MySampleModel object (3)>, <MySampleModel: MySampleModel object (2)>, <MySampleModel: MySampleModel object (1)>]>\n```\n\n### previous_instance\n\nReturns the previous version of the object.\n\n```\n>>> instance_breakfast = MySampleModel.objects.create(title=\"Today's breakfast\", body=\"Spam with Egg\") # Create <MySampleModel: MySampleModel object (1)>\n>>> [instance_breakfast.save() for i in range(2)]\n>>> second_gen_instance = instance_breakfast.same_group_items().order_by(\"pk\")[1]\n>>> second_gen_instance.previous_instance()\n<MySampleModel: MySampleModel object (1)>\n```\n\nThrows a DoesNotExist exception if the object does not exist.\n\n\n### next_instance\n\nReturns the next version of the object.\n\n```\n>>> instance_breakfast = MySampleModel.objects.create(title=\"Today's breakfast\", body=\"Spam with Egg\") # Create <MySampleModel: MySampleModel object (1)>\n>>> [instance_breakfast.save() for i in range(2)]\n>>> second_gen_instance = instance_breakfast.same_group_items()[1]\n>>> second_gen_instance.next_instance()\n<MySampleModel: MySampleModel object (3)>\n```\n\nThrows a DoesNotExist exception if the object does not exist.\n\n\n### latest_instance\n\nReturns the most recent object of the Stackgroup to which its own object belongs.\n\n```\n>>> instance_breakfast = MySampleModel.objects.create(title=\"Today's breakfast\", body=\"Spam with Egg\") # Create <MySampleModel: MySampleModel object (1)>\n>>> [instance_breakfast.save() for i in range(2)]\n>>> first_gen_instance = instance_breakfast.same_group_items().order_by(\"pk\")[0]\n>>> first_gen_instance.latest_instance()\n<MySampleModel: MySampleModel object (3)>\n```\n\nThrows a DoesNotExist exception if the object does not exist.\n\n\n### earliest_instance\n\nReturns the oldest object in the Stackgroup to which its own object belongs.\n\n```\n>>> instance_breakfast = MySampleModel.objects.create(title=\"Today's breakfast\", body=\"Spam with Egg\") # Create <MySampleModel: MySampleModel object (1)>\n>>> [instance_breakfast.save() for i in range(2)]\n>>> third_gen_instance = instance_breakfast.same_group_items().order_by(\"pk\")[2]\n>>> third_gen_instance.earliest_instance()\n<MySampleModel: MySampleModel object (1)>\n```\n\nThrows a DoesNotExist exception if the object does not exist.\n\n\n# Demo\n\nThe Docker configuration is provided. Please use the following command to start it. Go to [http://localhost:8000](http://localhost:8000) when the launch is complete.\n\n```\n$ docker-compose up\n```\n\nLogin account is ID: `admin` Password: `admin`\n\n# License\n\nMIT License\n",
"bugtrack_url": null,
"license": null,
"summary": "Django stackstore model",
"version": "1.0",
"project_urls": {
"Homepage": "https://github.com/c2emarket-ooppyy/django-stackstore-model"
},
"split_keywords": [
"django",
" model",
" versioning"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "bed12368c83b227787c6e11ee64cf1e5a489b24d89ca625cb33028f5a8ceeb6c",
"md5": "0001b44ebf46bc6888cd262be031d4c9",
"sha256": "5d5b4e0f73da963d4824dd63253640833f45554af44989aea1f1eb3b07596d46"
},
"downloads": -1,
"filename": "django_stackstore_model_ooppyy-1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "0001b44ebf46bc6888cd262be031d4c9",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 6596,
"upload_time": "2024-10-22T15:31:47",
"upload_time_iso_8601": "2024-10-22T15:31:47.090401Z",
"url": "https://files.pythonhosted.org/packages/be/d1/2368c83b227787c6e11ee64cf1e5a489b24d89ca625cb33028f5a8ceeb6c/django_stackstore_model_ooppyy-1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "48278a5e2444c4add44d6d278d76e260bce8c6a4b2767506bdaf73a045bb3026",
"md5": "1e7bea1a0fe7274dcd2839a1f77af11f",
"sha256": "792d75ce0aeb7638d5c5519ddee1312276d98c30c19751508d918ae0364f9585"
},
"downloads": -1,
"filename": "django-stackstore-model-ooppyy-1.0.tar.gz",
"has_sig": false,
"md5_digest": "1e7bea1a0fe7274dcd2839a1f77af11f",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 5456,
"upload_time": "2024-10-22T15:31:48",
"upload_time_iso_8601": "2024-10-22T15:31:48.349602Z",
"url": "https://files.pythonhosted.org/packages/48/27/8a5e2444c4add44d6d278d76e260bce8c6a4b2767506bdaf73a045bb3026/django-stackstore-model-ooppyy-1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-22 15:31:48",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "c2emarket-ooppyy",
"github_project": "django-stackstore-model",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"circle": true,
"tox": true,
"lcname": "django-stackstore-model-ooppyy"
}