From 1b3b94e06e8eb102054051e63d564e7a1c0b832a Mon Sep 17 00:00:00 2001 From: CoprDistGit Date: Wed, 31 May 2023 04:45:20 +0000 Subject: automatic import of python-django-pg-returning --- .gitignore | 1 + python-django-pg-returning.spec | 627 ++++++++++++++++++++++++++++++++++++++++ sources | 1 + 3 files changed, 629 insertions(+) create mode 100644 python-django-pg-returning.spec create mode 100644 sources diff --git a/.gitignore b/.gitignore index e69de29..c5f31c4 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +/django-pg-returning-2.0.0.tar.gz diff --git a/python-django-pg-returning.spec b/python-django-pg-returning.spec new file mode 100644 index 0000000..9fe2250 --- /dev/null +++ b/python-django-pg-returning.spec @@ -0,0 +1,627 @@ +%global _empty_manifest_terminate_build 0 +Name: python-django-pg-returning +Version: 2.0.0 +Release: 1 +Summary: A small library implementing PostgreSQL ability to return rows in DML statements for Django +License: BSD 3-clause "New" or "Revised" License +URL: https://github.com/M1hacka/django-pg-returning +Source0: https://mirrors.nju.edu.cn/pypi/web/packages/a3/82/1628d0c5255ba302d1f09af7bd5ecc6fe982e24a031ac54cb93a7bf1b6c5/django-pg-returning-2.0.0.tar.gz +BuildArch: noarch + +Requires: python3-django +Requires: python3-psycopg2 +Requires: python3-typing + +%description +[![Python unit tests](https://github.com/M1ha-Shvn/django-pg-returning/actions/workflows/python-tests.yml/badge.svg)](https://github.com/M1ha-Shvn/django-pg-returning/actions/workflows/python-tests.yml) [![Upload Python Package](https://github.com/M1ha-Shvn/django-pg-returning/actions/workflows/python-publish.yml/badge.svg)](https://github.com/M1ha-Shvn/django-pg-returning/actions/workflows/python-publish.yml) [![Downloads](https://pepy.tech/badge/django-pg-returning/month)](https://pepy.tech/project/django-pg-returning) + +# django-pg-returning +A small library implementing PostgreSQL ability to return rows in DML statements for Django. +[Link to PostgreSQL docs](https://www.postgresql.org/docs/10/static/sql-update.html) + +## Requirements +* Python Python 3.6+ + Previous versions may also work, but are not tested with CI +* django >= 1.8 + Previous versions may also work, but are not tested with CI. + bulk_create_returning method doesn't support .only() and .defer() filters for django before 1.10. +* psycopg2 +* typing for python < 3.5 +* PostgreSQL 9.4+ + Previous versions may also work, but are not tested with CI. + +## Installation +Install via pip: +`pip install django-pg-returning` +or via setup.py: +`python setup.py install` + +## Usage + +### Integration +The easiest way to integrate, is to inherit your model from `UpdateReturningModel` instead of `django.db.models.Model`. +It already has redeclared Manager, supporting returning operations. +```python +from django.db import models +from django_pg_returning import UpdateReturningModel + +class MyModel(UpdateReturningModel): + field = models.IntegerField() +``` + +If you already have custom manager, you can implement `get_queryset()` method in it: +```python +from django.db import models +from django_pg_returning import UpdateReturningQuerySet, UpdateReturningModel + +class MyManager(models.Manager): + def get_queryset(self): + return UpdateReturningQuerySet(using=self.db, model=self.model) + +class MyModel(UpdateReturningModel): + objects = MyManager() + + field = models.IntegerField() +``` + +And if you have custom manager you can use a mixin: +```python +from django.db import models +from django_pg_returning import UpdateReturningMixin, UpdateReturningModel + +class MyQuerySet(models.QuerySet, UpdateReturningMixin): + pass + +class MyManager(models.Manager): + def get_queryset(self): + return MyQuerySet(using=self.db, model=self.model) + +class MyModel(UpdateReturningModel): + objects = MyManager() + + field = models.IntegerField() +``` + +### Methods +#### QuerySet methods +After QuerySet mixin is integrated with your model, your QuerySet-s will have 3 additional methods: +```python +from django.db.models import Value + +# Any django queryset you like +qs = MyModel.objects.all() + +# Update and return a ReturningQuerySet, described below +result = qs.update_returning(field=1) + +# Delete data and return a ReturningQuerySet, described below +result = qs.delete_returning() + +# Acts like django's QuerySet.create() method, but updates all model fields to values stored in database +# Can be used to retrieve values, saved by database default/triggers etc. +result = MyModel.objects.create_returning(field=Value(1) + Value(2)) +print(result.field) # prints: "3" instead of "Value(1) + Value(2)" + +# Acts like django's QuerySet.bulk_create() method, but updates all model fields to values stored in database +# Can be used to retrieve values, saved by database default/triggers etc. +result = MyModel.objects.bulk_create_returning([MyModel(field=Value(1) + Value(2))]) +print(result[0].field) # prints: "3" instead of "Value(1) + Value(2)" +``` +By default methods get all fields, fetched by the model. +To limit fields returned, you can use standard +[QuerySet.only()](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#django.db.models.query.QuerySet.only) +and +[QuerySet.defer()](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#defer) methods. +`create_returning` doesn't support these methods. +`bulk_create_returning` doesn't support these methods for django before 1.10. + + +#### Model methods +If model instance is created, basic `save()` method is called. +If model is updated, database record is updated, and saved fields are refreshed with database values. +This may be useful, if you update fields with [F() expressions](https://docs.djangoproject.com/en/2.1/ref/models/expressions/#f-expressions). +By default all fields are saved and refreshed. +Use [update_fields](https://docs.djangoproject.com/en/2.1/ref/models/instances/#specifying-which-fields-to-save) to specify concrete fields to save and refresh. +```python +from django.db.models import Value, F + +instance = MyModel(pk=1, field=Value(1)) +instance.save_returning() +print(instance.field) +# Output: 2 +# if basic save() called: F('field') + Value(1) + +instance.field = F('field') + 1 + +# Basic save method will not change field and you don't know, what value is in database +instance.save() +print(instance.field) +# Output: F('field') + Value(1) + +# Library method gives ability to fetch updated result +instance.save_returning() +print(instance.field) +# Output: 2 +``` + +*Important notes*: +1) If you don't fetch field, and then try to get it, +library acts as django does - makes extra database query to fetch attribute deferred. +2) These queries are not lazy, as well as basic +[QuerySet.update()](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#update) +and +[QuerySet.delete()](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#delete) +methods. +3) Primary key field is fetched not looking at limiting methods, as django needs it to form a QuerySet + +### ReturningQuerySet +The result of returning functions is django_pg_returning.ReturningQuerySet. +It is based on django's RawQuerySet, but adds some extra methods to be used easier. +The main difference is that *ReturningQuerySet caches query results*, + while RawQuerySet executes query each time it is iterated. +All ReturningQuerySet methods are not executed on database side, they are executed in python on cached result. +The only way, ReturningQuerySet makes extra database query - is deferred field loading, described above. +Implemented methods: +```python +# UPDATE ... RETURNING query is executed here once. The result is cached. +result = MyModel.objects.all().update_returning(field=1) + +# Get number of values fetched +print(result.count(), len(result)) +# Output: 1, 1 + +# Index and slicing. Note that the order of result is not guaranteed by the database. +print(result[1], result[0:2]) +# Output: MyModel(...), [MyModel(...), MyModel(...), MyModel(...)] + +# Sintax sugar for indexing +print(result.first(), result.last()) +# Output: MyModel(...), MyModel(...) + +# Fetching values and values_list. Both methods use cache and return lists, not ValuesQuerySet like django does. +# values() method cakked without fields will return all fields, fetched in returning method. +# values_list() method called without fields will raise exception, as order or fields in result tuple is not obvious. + +print(result.values()) +# Output: [{'id': 1, 'field': 1}, {'id': 2, 'field': 2}] + +print(result.values('field')) +# Output: [{'field': 1}, {'field': 2}] + +print(result.values_list('field', flat=True)) +# Output: [1, 2] + +print(result.values_list('field', 'id', named=True)) +# Output: [Row(field=1, id=1), Row(field=2, id=2)] +``` + +## Thanks for support +![JetBrains](https://opt-819215.ssl.1c-bitrix-cdn.ru/upload/resize_cache/iblock/285/198_208_140cd750bba9870f18aada2478b24840a/2854e262418789c194fcaa4427f1db05.png "JetBrains") + + +%package -n python3-django-pg-returning +Summary: A small library implementing PostgreSQL ability to return rows in DML statements for Django +Provides: python-django-pg-returning +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +%description -n python3-django-pg-returning +[![Python unit tests](https://github.com/M1ha-Shvn/django-pg-returning/actions/workflows/python-tests.yml/badge.svg)](https://github.com/M1ha-Shvn/django-pg-returning/actions/workflows/python-tests.yml) [![Upload Python Package](https://github.com/M1ha-Shvn/django-pg-returning/actions/workflows/python-publish.yml/badge.svg)](https://github.com/M1ha-Shvn/django-pg-returning/actions/workflows/python-publish.yml) [![Downloads](https://pepy.tech/badge/django-pg-returning/month)](https://pepy.tech/project/django-pg-returning) + +# django-pg-returning +A small library implementing PostgreSQL ability to return rows in DML statements for Django. +[Link to PostgreSQL docs](https://www.postgresql.org/docs/10/static/sql-update.html) + +## Requirements +* Python Python 3.6+ + Previous versions may also work, but are not tested with CI +* django >= 1.8 + Previous versions may also work, but are not tested with CI. + bulk_create_returning method doesn't support .only() and .defer() filters for django before 1.10. +* psycopg2 +* typing for python < 3.5 +* PostgreSQL 9.4+ + Previous versions may also work, but are not tested with CI. + +## Installation +Install via pip: +`pip install django-pg-returning` +or via setup.py: +`python setup.py install` + +## Usage + +### Integration +The easiest way to integrate, is to inherit your model from `UpdateReturningModel` instead of `django.db.models.Model`. +It already has redeclared Manager, supporting returning operations. +```python +from django.db import models +from django_pg_returning import UpdateReturningModel + +class MyModel(UpdateReturningModel): + field = models.IntegerField() +``` + +If you already have custom manager, you can implement `get_queryset()` method in it: +```python +from django.db import models +from django_pg_returning import UpdateReturningQuerySet, UpdateReturningModel + +class MyManager(models.Manager): + def get_queryset(self): + return UpdateReturningQuerySet(using=self.db, model=self.model) + +class MyModel(UpdateReturningModel): + objects = MyManager() + + field = models.IntegerField() +``` + +And if you have custom manager you can use a mixin: +```python +from django.db import models +from django_pg_returning import UpdateReturningMixin, UpdateReturningModel + +class MyQuerySet(models.QuerySet, UpdateReturningMixin): + pass + +class MyManager(models.Manager): + def get_queryset(self): + return MyQuerySet(using=self.db, model=self.model) + +class MyModel(UpdateReturningModel): + objects = MyManager() + + field = models.IntegerField() +``` + +### Methods +#### QuerySet methods +After QuerySet mixin is integrated with your model, your QuerySet-s will have 3 additional methods: +```python +from django.db.models import Value + +# Any django queryset you like +qs = MyModel.objects.all() + +# Update and return a ReturningQuerySet, described below +result = qs.update_returning(field=1) + +# Delete data and return a ReturningQuerySet, described below +result = qs.delete_returning() + +# Acts like django's QuerySet.create() method, but updates all model fields to values stored in database +# Can be used to retrieve values, saved by database default/triggers etc. +result = MyModel.objects.create_returning(field=Value(1) + Value(2)) +print(result.field) # prints: "3" instead of "Value(1) + Value(2)" + +# Acts like django's QuerySet.bulk_create() method, but updates all model fields to values stored in database +# Can be used to retrieve values, saved by database default/triggers etc. +result = MyModel.objects.bulk_create_returning([MyModel(field=Value(1) + Value(2))]) +print(result[0].field) # prints: "3" instead of "Value(1) + Value(2)" +``` +By default methods get all fields, fetched by the model. +To limit fields returned, you can use standard +[QuerySet.only()](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#django.db.models.query.QuerySet.only) +and +[QuerySet.defer()](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#defer) methods. +`create_returning` doesn't support these methods. +`bulk_create_returning` doesn't support these methods for django before 1.10. + + +#### Model methods +If model instance is created, basic `save()` method is called. +If model is updated, database record is updated, and saved fields are refreshed with database values. +This may be useful, if you update fields with [F() expressions](https://docs.djangoproject.com/en/2.1/ref/models/expressions/#f-expressions). +By default all fields are saved and refreshed. +Use [update_fields](https://docs.djangoproject.com/en/2.1/ref/models/instances/#specifying-which-fields-to-save) to specify concrete fields to save and refresh. +```python +from django.db.models import Value, F + +instance = MyModel(pk=1, field=Value(1)) +instance.save_returning() +print(instance.field) +# Output: 2 +# if basic save() called: F('field') + Value(1) + +instance.field = F('field') + 1 + +# Basic save method will not change field and you don't know, what value is in database +instance.save() +print(instance.field) +# Output: F('field') + Value(1) + +# Library method gives ability to fetch updated result +instance.save_returning() +print(instance.field) +# Output: 2 +``` + +*Important notes*: +1) If you don't fetch field, and then try to get it, +library acts as django does - makes extra database query to fetch attribute deferred. +2) These queries are not lazy, as well as basic +[QuerySet.update()](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#update) +and +[QuerySet.delete()](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#delete) +methods. +3) Primary key field is fetched not looking at limiting methods, as django needs it to form a QuerySet + +### ReturningQuerySet +The result of returning functions is django_pg_returning.ReturningQuerySet. +It is based on django's RawQuerySet, but adds some extra methods to be used easier. +The main difference is that *ReturningQuerySet caches query results*, + while RawQuerySet executes query each time it is iterated. +All ReturningQuerySet methods are not executed on database side, they are executed in python on cached result. +The only way, ReturningQuerySet makes extra database query - is deferred field loading, described above. +Implemented methods: +```python +# UPDATE ... RETURNING query is executed here once. The result is cached. +result = MyModel.objects.all().update_returning(field=1) + +# Get number of values fetched +print(result.count(), len(result)) +# Output: 1, 1 + +# Index and slicing. Note that the order of result is not guaranteed by the database. +print(result[1], result[0:2]) +# Output: MyModel(...), [MyModel(...), MyModel(...), MyModel(...)] + +# Sintax sugar for indexing +print(result.first(), result.last()) +# Output: MyModel(...), MyModel(...) + +# Fetching values and values_list. Both methods use cache and return lists, not ValuesQuerySet like django does. +# values() method cakked without fields will return all fields, fetched in returning method. +# values_list() method called without fields will raise exception, as order or fields in result tuple is not obvious. + +print(result.values()) +# Output: [{'id': 1, 'field': 1}, {'id': 2, 'field': 2}] + +print(result.values('field')) +# Output: [{'field': 1}, {'field': 2}] + +print(result.values_list('field', flat=True)) +# Output: [1, 2] + +print(result.values_list('field', 'id', named=True)) +# Output: [Row(field=1, id=1), Row(field=2, id=2)] +``` + +## Thanks for support +![JetBrains](https://opt-819215.ssl.1c-bitrix-cdn.ru/upload/resize_cache/iblock/285/198_208_140cd750bba9870f18aada2478b24840a/2854e262418789c194fcaa4427f1db05.png "JetBrains") + + +%package help +Summary: Development documents and examples for django-pg-returning +Provides: python3-django-pg-returning-doc +%description help +[![Python unit tests](https://github.com/M1ha-Shvn/django-pg-returning/actions/workflows/python-tests.yml/badge.svg)](https://github.com/M1ha-Shvn/django-pg-returning/actions/workflows/python-tests.yml) [![Upload Python Package](https://github.com/M1ha-Shvn/django-pg-returning/actions/workflows/python-publish.yml/badge.svg)](https://github.com/M1ha-Shvn/django-pg-returning/actions/workflows/python-publish.yml) [![Downloads](https://pepy.tech/badge/django-pg-returning/month)](https://pepy.tech/project/django-pg-returning) + +# django-pg-returning +A small library implementing PostgreSQL ability to return rows in DML statements for Django. +[Link to PostgreSQL docs](https://www.postgresql.org/docs/10/static/sql-update.html) + +## Requirements +* Python Python 3.6+ + Previous versions may also work, but are not tested with CI +* django >= 1.8 + Previous versions may also work, but are not tested with CI. + bulk_create_returning method doesn't support .only() and .defer() filters for django before 1.10. +* psycopg2 +* typing for python < 3.5 +* PostgreSQL 9.4+ + Previous versions may also work, but are not tested with CI. + +## Installation +Install via pip: +`pip install django-pg-returning` +or via setup.py: +`python setup.py install` + +## Usage + +### Integration +The easiest way to integrate, is to inherit your model from `UpdateReturningModel` instead of `django.db.models.Model`. +It already has redeclared Manager, supporting returning operations. +```python +from django.db import models +from django_pg_returning import UpdateReturningModel + +class MyModel(UpdateReturningModel): + field = models.IntegerField() +``` + +If you already have custom manager, you can implement `get_queryset()` method in it: +```python +from django.db import models +from django_pg_returning import UpdateReturningQuerySet, UpdateReturningModel + +class MyManager(models.Manager): + def get_queryset(self): + return UpdateReturningQuerySet(using=self.db, model=self.model) + +class MyModel(UpdateReturningModel): + objects = MyManager() + + field = models.IntegerField() +``` + +And if you have custom manager you can use a mixin: +```python +from django.db import models +from django_pg_returning import UpdateReturningMixin, UpdateReturningModel + +class MyQuerySet(models.QuerySet, UpdateReturningMixin): + pass + +class MyManager(models.Manager): + def get_queryset(self): + return MyQuerySet(using=self.db, model=self.model) + +class MyModel(UpdateReturningModel): + objects = MyManager() + + field = models.IntegerField() +``` + +### Methods +#### QuerySet methods +After QuerySet mixin is integrated with your model, your QuerySet-s will have 3 additional methods: +```python +from django.db.models import Value + +# Any django queryset you like +qs = MyModel.objects.all() + +# Update and return a ReturningQuerySet, described below +result = qs.update_returning(field=1) + +# Delete data and return a ReturningQuerySet, described below +result = qs.delete_returning() + +# Acts like django's QuerySet.create() method, but updates all model fields to values stored in database +# Can be used to retrieve values, saved by database default/triggers etc. +result = MyModel.objects.create_returning(field=Value(1) + Value(2)) +print(result.field) # prints: "3" instead of "Value(1) + Value(2)" + +# Acts like django's QuerySet.bulk_create() method, but updates all model fields to values stored in database +# Can be used to retrieve values, saved by database default/triggers etc. +result = MyModel.objects.bulk_create_returning([MyModel(field=Value(1) + Value(2))]) +print(result[0].field) # prints: "3" instead of "Value(1) + Value(2)" +``` +By default methods get all fields, fetched by the model. +To limit fields returned, you can use standard +[QuerySet.only()](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#django.db.models.query.QuerySet.only) +and +[QuerySet.defer()](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#defer) methods. +`create_returning` doesn't support these methods. +`bulk_create_returning` doesn't support these methods for django before 1.10. + + +#### Model methods +If model instance is created, basic `save()` method is called. +If model is updated, database record is updated, and saved fields are refreshed with database values. +This may be useful, if you update fields with [F() expressions](https://docs.djangoproject.com/en/2.1/ref/models/expressions/#f-expressions). +By default all fields are saved and refreshed. +Use [update_fields](https://docs.djangoproject.com/en/2.1/ref/models/instances/#specifying-which-fields-to-save) to specify concrete fields to save and refresh. +```python +from django.db.models import Value, F + +instance = MyModel(pk=1, field=Value(1)) +instance.save_returning() +print(instance.field) +# Output: 2 +# if basic save() called: F('field') + Value(1) + +instance.field = F('field') + 1 + +# Basic save method will not change field and you don't know, what value is in database +instance.save() +print(instance.field) +# Output: F('field') + Value(1) + +# Library method gives ability to fetch updated result +instance.save_returning() +print(instance.field) +# Output: 2 +``` + +*Important notes*: +1) If you don't fetch field, and then try to get it, +library acts as django does - makes extra database query to fetch attribute deferred. +2) These queries are not lazy, as well as basic +[QuerySet.update()](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#update) +and +[QuerySet.delete()](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#delete) +methods. +3) Primary key field is fetched not looking at limiting methods, as django needs it to form a QuerySet + +### ReturningQuerySet +The result of returning functions is django_pg_returning.ReturningQuerySet. +It is based on django's RawQuerySet, but adds some extra methods to be used easier. +The main difference is that *ReturningQuerySet caches query results*, + while RawQuerySet executes query each time it is iterated. +All ReturningQuerySet methods are not executed on database side, they are executed in python on cached result. +The only way, ReturningQuerySet makes extra database query - is deferred field loading, described above. +Implemented methods: +```python +# UPDATE ... RETURNING query is executed here once. The result is cached. +result = MyModel.objects.all().update_returning(field=1) + +# Get number of values fetched +print(result.count(), len(result)) +# Output: 1, 1 + +# Index and slicing. Note that the order of result is not guaranteed by the database. +print(result[1], result[0:2]) +# Output: MyModel(...), [MyModel(...), MyModel(...), MyModel(...)] + +# Sintax sugar for indexing +print(result.first(), result.last()) +# Output: MyModel(...), MyModel(...) + +# Fetching values and values_list. Both methods use cache and return lists, not ValuesQuerySet like django does. +# values() method cakked without fields will return all fields, fetched in returning method. +# values_list() method called without fields will raise exception, as order or fields in result tuple is not obvious. + +print(result.values()) +# Output: [{'id': 1, 'field': 1}, {'id': 2, 'field': 2}] + +print(result.values('field')) +# Output: [{'field': 1}, {'field': 2}] + +print(result.values_list('field', flat=True)) +# Output: [1, 2] + +print(result.values_list('field', 'id', named=True)) +# Output: [Row(field=1, id=1), Row(field=2, id=2)] +``` + +## Thanks for support +![JetBrains](https://opt-819215.ssl.1c-bitrix-cdn.ru/upload/resize_cache/iblock/285/198_208_140cd750bba9870f18aada2478b24840a/2854e262418789c194fcaa4427f1db05.png "JetBrains") + + +%prep +%autosetup -n django-pg-returning-2.0.0 + +%build +%py3_build + +%install +%py3_install +install -d -m755 %{buildroot}/%{_pkgdocdir} +if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi +if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi +if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi +if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi +pushd %{buildroot} +if [ -d usr/lib ]; then + find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/lib64 ]; then + find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/bin ]; then + find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/sbin ]; then + find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst +fi +touch doclist.lst +if [ -d usr/share/man ]; then + find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst +fi +popd +mv %{buildroot}/filelist.lst . +mv %{buildroot}/doclist.lst . + +%files -n python3-django-pg-returning -f filelist.lst +%dir %{python3_sitelib}/* + +%files help -f doclist.lst +%{_docdir}/* + +%changelog +* Wed May 31 2023 Python_Bot - 2.0.0-1 +- Package Spec generated diff --git a/sources b/sources new file mode 100644 index 0000000..374f84d --- /dev/null +++ b/sources @@ -0,0 +1 @@ +c0c40eefdf3185a82a7f1e0f59540cc0 django-pg-returning-2.0.0.tar.gz -- cgit v1.2.3