Package: django-orm-views
django_orm_viewsThe package for managing database views using django, without the migrations.
It can be used for generating database views and reading from them using django orm system.What does this support?This package adds support to Django forwritingPostgres views using:Raw SQLDjango QuerysetsThey look something like this:classMySQLView(PostgresViewFromSQL):sql="""SELECT col_a, col_b FROM table_1;"""classMyQuerysetView(PostgresViewFromQueryset):@classmethoddefget_queryset(cls):return(Table1.objects.values('col_a','col_b'))The package allows reading from a view using django ORM. For a view to be readable, it has to be inherited from
one of the readable view abstractions -ReadableViewFromQuerysetorReadableViewFromSQL. It would look like this:classMyReadableView(ReadableViewFromQueryset):@classmethoddefget_queryset(cls):return(Table1.objects.values('col_a','col_b'))result=MyReadableView.objects.all()result=MyReadableView.objects.filter(name="test")result=MyReadableView.objects.get(id=1)Thenamefor the view in the database is generated automatically in the base class -BasePostgresView.
It's not possible at the moment to define a custom name in the database for a readable view. Though it's possible if the
view is not readable (not inherited from the readable view abstraction).Since a readable view is basically a not managed django model, you might want to
set some custom meta data for it by defining a Meta class inside the readable view (
For example changing the data source -db_table).! Notethat defining a custom Meta class is not allowed in the current version of
the package and will lead to an error!See some more examples in the testshereThis also supports the construction of materialised views viaPostgresMaterialisedViewMixin. Note that the functionrefresh_materialized_viewwill
need to be managed by the user in order to keep these up to date where required.What does this not support?Any database engines aside from Postgres (unless syntax happens to be the same!)Defining custom name for a readable view in the database. Although it's
possible for a view that is not readable.Defining custom Meta class in a readable view as it can be done for a django model
to define additional settings E.g.db_tableWhen should I use this?Our use-case is for a database which is managed by Django
in which we would like to provide an analytics-friendly
representation of some of our data.  This involves giving
analytics direct access to our database (whilst using a
permissions framework), but using views to expose the data
in a more simple way, as well as obscuring data which
we consider personally identifiable/sensitive.There are other frameworks existing which do similar things,
usually including reads via the ORM.  We found that these
packages all generate migrations (despite being unmanaged)
and we wanted to remove this from the django migrations process
altogether - there seemed to be no value add by including
migrations and they would just muddy our migration states.Cool! But how do I use this?pip install django-orm-viewsAdd'django_orm_views'to yourINSTALLED_APPSCreate apostgres_views.py(file or package) inside any appAdd aPostgresViewFromQuerysetorPostgresViewFromSQLto yourpostgres_views.py(as above)run./manage.py sync_viewsApostgres_views.pyfile might look something like the following:classComplexViewFromQueryset(PostgresViewFromQueryset):prefix='test'# This is optional, but allows you to prefix the table names for views@classmethoddefget_queryset(cls):# Return a `.values` with the query you desirereturn(TestModelWithForeignKey.objects.all().annotate(double_integer_col=F('foreign_key__integer_col')*2).values('id','foreign_key__id','foreign_key__integer_col','foreign_key__character_col','foreign_key__date_col','foreign_key__datetime_col','double_integer_col',))When we run the./manage.py sync_views, we'll create a view calledtest_complexviewfromquerysetunder
theviewsschema.Note, you can put./manage.py sync_viewsinto your CI/CD.  It works by:Opening a transactionDropping the views schemaRecreating the views schemaRecreating all views under that schemaCommitting the transactionWhat's still to come?Support for more database engines.  This currently only supports Postgres,
but should be a reasonably light shift to support other database engines.Making the package more configurable using settings.Consideration of 0 downtime deployments with views.Note, this can still be achieved with the current implementation,
but a bad migration (with a view depending) could
cascade a view and create downtime.  Ideally migrations +
view creation should happen in a single transaction.ContributingFeel free to fork the package and propose changes.  The repo comes with a test django project which
can be used to effectively test changes.  It also demonstrates the functionality pretty well.