diff --git a/MANIFEST.in b/MANIFEST.in index c1a7121..9d5d250 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,2 @@ include LICENSE -include README.md +include README.rst diff --git a/README.md b/README.md deleted file mode 100644 index b5f6ce5..0000000 --- a/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# django-database-view - -A simple pluggable application that allows to work with database views. - -So far only MySQL is supported as backend, but more could be added if necessary. - -## Quick start - -1. In your models.py create classes which extend dbview.DbView like this: - - ```python - - from django.db import models - from dbview.models import DbView - - class ModelA(models.Model): - fielda = models.CharField() - fieldc = models.IntegerField() - - class MyView(DbView): - fieldA = models.OneToOneField(ModelA, primary_key=True, - db_column='fielda__id') - fieldB = models.IntegerField(blank=True, null=True, db_column='fieldb') - - @classmethod - def view(cls): - ''' - This method returns the SQL string that creates the view, in this - example fieldB is the result of annotating another column - ''' - qs = modelA.objects.all().\ - annotate(fieldb=models.Sum('fieldc')) .\ - annotate(fielda__id=models.F('pk')) .\ - order_by('fielda__id') .\ - values('fielda__id', 'fieldb') - return str(qs.query) - ``` - -Alternatively `get_view_str` method could be used to write a custom SQL: - - ```python - - class MyView(DbView): - - # ... - - @classmethod - def get_view_str(cls): - return """ - CREATE VIEW my_view AS ( - SELECT ... - ) - """ - ``` - -2. Then create a migration point for your view generation, edit that migration -and modify it, add: `from dbview.helpers import CreateView` and replace the -line the call to `migrations.CreateModel` with `CreateView`. - -3. Migrate your database and start using your database views. diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..3996e56 --- /dev/null +++ b/README.rst @@ -0,0 +1,69 @@ +#################### +django-database-view +#################### + +A simple pluggable application that allows to work with database views. + +Quick start +=========== + +1. Install the package:: + + pip install django-database-models + +2. In your ``models.py`` create classes which extend ``dbview.models.DbView`` + like this: + + .. code-block:: python + + from django.db import models + from dbview.models import DbView + + class ModelA(models.Model): + fielda = models.CharField() + fieldc = models.IntegerField() + + class MyView(DbView): + fieldA = models.OneToOneField(ModelA, primary_key=True, + db_column='fielda__id') + fieldB = models.IntegerField(blank=True, null=True, db_column='fieldb') + + @classmethod + def view(cls): + """ + This method returns the SQL string that creates the view, + in this example fieldB is the result of annotating another column + """ + qs = modelA.objects.all( + ).annotate( + fieldb=models.Sum('fieldc'), + ).annotate( + fielda__id=models.F('pk'), + ).order_by( + 'fielda__id', + ).values( + 'fielda__id', + 'fieldb', + ) + return str(qs.query) + + Alternatively ``get_view_str`` method could be used to write a custom SQL: + + .. code-block:: python + + class MyView(DbView): + # ... + + @classmethod + def get_view_str(cls): + return """ + CREATE VIEW my_view AS ( + SELECT ... + )""" + +3. Then create a migration point for your view generation, edit that + migration and modify it, add: + ``from dbview.helpers import CreateView`` and replace the line the + call to ``migrations.CreateModel`` with ``CreateView``. + +4. Migrate your database and start using your database views. diff --git a/dbview/helpers.py b/dbview/helpers.py index 5e82b73..24bc072 100644 --- a/dbview/helpers.py +++ b/dbview/helpers.py @@ -22,7 +22,8 @@ class CreateView(migrations.CreateModel): elif hasattr(model, 'get_view_str'): self._create_view_from_raw_sql(model.get_view_str(), schema_editor) else: - raise Exception(f"{model} has neither view nor get_view_str") + raise Exception('{} has neither view nor get_view_str'.format( + model)) def database_backwards(self, app_label, schema_editor, from_state, to): fake_model = from_state.apps.get_model(app_label, self.name) @@ -34,7 +35,7 @@ class CreateView(migrations.CreateModel): if hasattr(models, self.name): return getattr(models, self.name) - # TODO: recursive search + # TODO: identify model more reliably and support more than 1 level for submodule in models.__dict__.values(): if hasattr(submodule, self.name): return getattr(submodule, self.name) diff --git a/setup.py b/setup.py index 96ce65a..4243f44 100644 --- a/setup.py +++ b/setup.py @@ -1,15 +1,16 @@ import os from setuptools import setup -# allow setup.py to be run from any path -os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) + +def read(fname): + return open(os.path.join(os.path.dirname(__file__), fname)).read() + setup( name='django-database-view', - version='0.2.0', + version='0.2.1', packages=['dbview'], - setup_requires=['setuptools-markdown'], - long_description_markdown_filename='README.md', + long_description=read('README.rst'), include_package_data=True, license='MIT', description='A simple Django app to handle database views.', @@ -29,6 +30,10 @@ setup( 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', ],