From dd50b3ec9fb0814186f3174ca4269a4090a46212 Mon Sep 17 00:00:00 2001 From: Gerben Neven Date: Mon, 2 Mar 2020 13:22:51 +0000 Subject: [PATCH 01/11] create setup.py --- setup.py | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 setup.py diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..0d012eb --- /dev/null +++ b/setup.py @@ -0,0 +1,9 @@ +from distutils.core import setup + +setup( + name='Casbin Django ORM Adapter', + version='0.1dev', + packages=['casbin_django_orm_adaptor',], + license='Creative Commons Attribution-Noncommercial-Share Alike license', + long_description=open('README.md').read(), +) \ No newline at end of file From 7189a222e08b9146d6b9f0d99bb7065d377f08cf Mon Sep 17 00:00:00 2001 From: Gerben Neven Date: Mon, 2 Mar 2020 13:24:18 +0000 Subject: [PATCH 02/11] fix typo in package location --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0d012eb..902b554 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='Casbin Django ORM Adapter', version='0.1dev', - packages=['casbin_django_orm_adaptor',], + packages=['casbin_django_orm_adapter',], license='Creative Commons Attribution-Noncommercial-Share Alike license', long_description=open('README.md').read(), ) \ No newline at end of file From e1d50cbef5740e6a7df70a1ceb2fed18af044704 Mon Sep 17 00:00:00 2001 From: Gerben Neven Date: Mon, 2 Mar 2020 13:39:33 +0000 Subject: [PATCH 03/11] simplify setup call --- setup.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/setup.py b/setup.py index 902b554..9e33071 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,3 @@ from distutils.core import setup -setup( - name='Casbin Django ORM Adapter', - version='0.1dev', - packages=['casbin_django_orm_adapter',], - license='Creative Commons Attribution-Noncommercial-Share Alike license', - long_description=open('README.md').read(), -) \ No newline at end of file +setup() \ No newline at end of file From 07b0f12cfc5fb169c9f330b237e78be6d1e5e074 Mon Sep 17 00:00:00 2001 From: Gerben Neven Date: Mon, 2 Mar 2020 13:42:44 +0000 Subject: [PATCH 04/11] use package name on name field --- setup.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9e33071..983bf9c 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,9 @@ from distutils.core import setup -setup() \ No newline at end of file +setup( + name='casbin_django_orm_adapter', + version='0.1dev', + packages=['casbin_django_orm_adapter',], + license='Creative Commons Attribution-Noncommercial-Share Alike license', + long_description=open('README.md').read(), +) \ No newline at end of file From 852ce82e3935633d92386ad8656772cc0c204125 Mon Sep 17 00:00:00 2001 From: Gerben Neven Date: Mon, 2 Mar 2020 13:51:43 +0000 Subject: [PATCH 05/11] setup as django app --- casbin_django_orm_adapter/apps.py | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 casbin_django_orm_adapter/apps.py diff --git a/casbin_django_orm_adapter/apps.py b/casbin_django_orm_adapter/apps.py new file mode 100644 index 0000000..c524d15 --- /dev/null +++ b/casbin_django_orm_adapter/apps.py @@ -0,0 +1,4 @@ +from django.apps import AppConfig + +class CasbinDjangoORMAdapterConfig(AppConfig): + name = 'casbin_orm_adapter' \ No newline at end of file From 3e39769d1f7c94ca97e72999edeb5363c48b121d Mon Sep 17 00:00:00 2001 From: Gerben Neven Date: Tue, 3 Mar 2020 15:18:57 +0000 Subject: [PATCH 06/11] add working django app + setup.py --- casbin_adapter/.DS_Store | Bin 0 -> 6148 bytes casbin_adapter/__init__.py | 0 casbin_adapter/adapter.py | 73 ++++++++++++ casbin_adapter/apps.py | 5 + casbin_adapter/migrations/.DS_Store | Bin 0 -> 6148 bytes casbin_adapter/migrations/0001_initial.py | 30 +++++ casbin_adapter/migrations/__init__.py | 0 casbin_adapter/models.py | 36 ++++++ casbin_adapter/tests/.DS_Store | Bin 0 -> 6148 bytes casbin_adapter/tests/__init__.py | 0 .../tests}/rbac_model.conf | 2 +- .../tests}/rbac_policy.csv | 2 +- .../tests}/test_adapter.py | 90 +++++++++------ casbin_django_orm_adapter/__init__.py | 1 - casbin_django_orm_adapter/adapter.py | 104 ------------------ casbin_django_orm_adapter/apps.py | 4 - setup.py | 11 +- 17 files changed, 208 insertions(+), 150 deletions(-) create mode 100644 casbin_adapter/.DS_Store create mode 100644 casbin_adapter/__init__.py create mode 100644 casbin_adapter/adapter.py create mode 100644 casbin_adapter/apps.py create mode 100644 casbin_adapter/migrations/.DS_Store create mode 100644 casbin_adapter/migrations/0001_initial.py create mode 100644 casbin_adapter/migrations/__init__.py create mode 100644 casbin_adapter/models.py create mode 100644 casbin_adapter/tests/.DS_Store create mode 100644 casbin_adapter/tests/__init__.py rename {tests => casbin_adapter/tests}/rbac_model.conf (75%) rename {tests => casbin_adapter/tests}/rbac_policy.csv (82%) rename {tests => casbin_adapter/tests}/test_adapter.py (61%) delete mode 100644 casbin_django_orm_adapter/__init__.py delete mode 100644 casbin_django_orm_adapter/adapter.py delete mode 100644 casbin_django_orm_adapter/apps.py diff --git a/casbin_adapter/.DS_Store b/casbin_adapter/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 0: + line.v0 = rule[0] + if len(rule) > 1: + line.v1 = rule[1] + if len(rule) > 2: + line.v2 = rule[2] + if len(rule) > 3: + line.v3 = rule[3] + if len(rule) > 4: + line.v4 = rule[4] + if len(rule) > 5: + line.v5 = rule[5] + return line + + def save_policy(self, model): + """saves all policy rules to the storage.""" + # See https://casbin.org/docs/en/adapters#autosave + # for why this is deleting all rules + CasbinRule.objects.all().delete() + + lines = [] + for sec in ["p", "g"]: + if sec not in model.model.keys(): + continue + for ptype, ast in model.model[sec].items(): + for rule in ast.policy: + lines.append(self._create_policy_line(ptype, rule)) + CasbinRule.objects.bulk_create(lines) + return True + + def add_policy(self, sec, ptype, rule): + """adds a policy rule to the storage.""" + line = self._create_policy_line(ptype, rule) + line.save() + + def remove_policy(self, sec, ptype, rule): + """removes a policy rule from the storage.""" + queryParams = {'ptype': ptype} + for i, v in enumerate(rule): + queryParams[f'v{i}'] = v + rows_deleted, _ = CasbinRule.objects.filter(**queryParams).delete() + return True if rows_deleted > 0 else False + + def remove_filtered_policy(self, sec, ptype, field_index, *field_values): + """removes policy rules that match the filter from the storage. + This is part of the Auto-Save feature. + """ + queryParams = {'ptype': ptype} + if not(0 <= field_index <= 5): + return False + if not (1 <= field_index + len(field_values) <= 6): + return False + for i, v in enumerate(field_values): + queryParams[f'v{i + field_index}'] = v + rows_deleted, _ = CasbinRule.objects.filter(**queryParams).delete() + return True if rows_deleted > 0 else False diff --git a/casbin_adapter/apps.py b/casbin_adapter/apps.py new file mode 100644 index 0000000..1d19f74 --- /dev/null +++ b/casbin_adapter/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class CasbinAdapterConfig(AppConfig): + name = 'casbin_adapter' diff --git a/casbin_adapter/migrations/.DS_Store b/casbin_adapter/migrations/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0'.format(self.id, str(self)) diff --git a/casbin_adapter/tests/.DS_Store b/casbin_adapter/tests/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0') - engine = create_engine("sqlite://") - - session = sessionmaker(bind=engine) - Base.metadata.create_all(engine) - s = session() - - s.add(rule) - s.commit() + rule.save() self.assertRegex(repr(rule), r'') - s.close() diff --git a/casbin_django_orm_adapter/__init__.py b/casbin_django_orm_adapter/__init__.py deleted file mode 100644 index b4b0e61..0000000 --- a/casbin_django_orm_adapter/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .adapter import CasbinRule, Adapter, Base diff --git a/casbin_django_orm_adapter/adapter.py b/casbin_django_orm_adapter/adapter.py deleted file mode 100644 index 33380dd..0000000 --- a/casbin_django_orm_adapter/adapter.py +++ /dev/null @@ -1,104 +0,0 @@ -from casbin import persist -from django.db import models - - -class CasbinRule(models.Model): - ptype = models.CharField(max_length=255) - v0 = models.CharField(max_length=255) - v1 = models.CharField(max_length=255) - v2 = models.CharField(max_length=255) - v3 = models.CharField(max_length=255) - v4 = models.CharField(max_length=255) - v5 = models.CharField(max_length=255) - - class Meta: - db_table = 'casbin_rule' - - def __str__(self): - text = self.ptype - - if self.v0: - text = text + ', ' + self.v0 - if self.v1: - text = text + ', ' + self.v1 - if self.v2: - text = text + ', ' + self.v2 - if self.v3: - text = text + ', ' + self.v3 - if self.v4: - text = text + ', ' + self.v4 - if self.v5: - text = text + ', ' + self.v5 - return text - - def __repr__(self): - return ''.format(self.id, str(self)) - - -class Adapter(persist.Adapter): - """the interface for Casbin adapters.""" - - def __init__(self, engine): - # if isinstance(engine, str): - # self._engine = create_engine(engine) - # else: - # self._engine = engine - # - # session = sessionmaker(bind=self._engine) - # self._session = session() - # - # Base.metadata.create_all(self._engine) - - self._engine = models.Manager() - - def load_policy(self, model): - """loads all policy rules from the storage.""" - lines = self._engine.all() - # lines = self._session.query(CasbinRule).all() - for line in lines: - persist.load_policy_line(str(line), model) - - def _save_policy_line(self, ptype, rule): - line = CasbinRule(ptype=ptype) - if len(rule) > 0: - line.v0 = rule[0] - if len(rule) > 1: - line.v1 = rule[1] - if len(rule) > 2: - line.v2 = rule[2] - if len(rule) > 3: - line.v3 = rule[3] - if len(rule) > 4: - line.v4 = rule[4] - if len(rule) > 5: - line.v5 = rule[5] - # self._session.add(line) - # self._session.commit() - models.CasbinRule.objects.create(line) - - def save_policy(self, model): - """saves all policy rules to the storage.""" - for sec in ["p", "g"]: - if sec not in model.model.keys(): - continue - for ptype, ast in model.model[sec].items(): - for rule in ast.policy: - self._save_policy_line(ptype, rule) - return True - - def add_policy(self, sec, ptype, rule): - """adds a policy rule to the storage.""" - self._save_policy_line(ptype, rule) - - def remove_policy(self, sec, ptype, rule): - """removes a policy rule from the storage.""" - pass - - def remove_filtered_policy(self, sec, ptype, field_index, *field_values): - """removes policy rules that match the filter from the storage. - This is part of the Auto-Save feature. - """ - pass - - # def __del__(self): - # self._session.close() diff --git a/casbin_django_orm_adapter/apps.py b/casbin_django_orm_adapter/apps.py deleted file mode 100644 index c524d15..0000000 --- a/casbin_django_orm_adapter/apps.py +++ /dev/null @@ -1,4 +0,0 @@ -from django.apps import AppConfig - -class CasbinDjangoORMAdapterConfig(AppConfig): - name = 'casbin_orm_adapter' \ No newline at end of file diff --git a/setup.py b/setup.py index 983bf9c..545012b 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,8 @@ -from distutils.core import setup +from setuptools import setup, find_packages setup( - name='casbin_django_orm_adapter', - version='0.1dev', - packages=['casbin_django_orm_adapter',], - license='Creative Commons Attribution-Noncommercial-Share Alike license', - long_description=open('README.md').read(), + name='casbin-django-orm-adapter', + version="0.0.1", + packages=find_packages(), + license="Apache-2.0", ) \ No newline at end of file From 0baf64d978648b8aaec3db0f346f0747ee10a487 Mon Sep 17 00:00:00 2001 From: Gerben Neven Date: Tue, 3 Mar 2020 15:37:20 +0000 Subject: [PATCH 07/11] update readme usage example --- README.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 736afe3..4bf3ea7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -Django ORM Adapter for PyCasbin -==== +# Django ORM Adapter for PyCasbin [![Build Status](https://www.travis-ci.org/pycasbin/django-orm-adapter.svg?branch=master)](https://www.travis-ci.org/pycasbin/django-orm-adapter) [![Coverage Status](https://coveralls.io/repos/github/pycasbin/django-orm-adapter/badge.svg)](https://coveralls.io/github/pycasbin/django-orm-adapter) @@ -29,13 +28,23 @@ Based on [Officially Supported Databases](https://docs.djangoproject.com/en/3.0/ pip install casbin_django_orm_adapter ``` +Add `casbin_adapter` to your `INSTALLED_APPS` + +```python +INSTALLED_APPS = [ + ... + 'casbin_adapter', + ... +] +``` + ## Simple Example ```python -import casbin_django_orm_adapter import casbin +from casbin_adapter.adapter import Adapter -adapter = casbin_django_orm_adapter.Adapter('sqlite:///test.db') +adapter = Adapter() e = casbin.Enforcer('path/to/model.conf', adapter, True) @@ -51,7 +60,6 @@ else: pass ``` - ### Getting Help - [PyCasbin](https://github.com/casbin/pycasbin) From 535a7aedb1be820a5495aa0f80345a2dadd74300 Mon Sep 17 00:00:00 2001 From: Gerben Neven Date: Tue, 3 Mar 2020 15:39:19 +0000 Subject: [PATCH 08/11] add note to readme on migrations --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4bf3ea7..b1e11ee 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ INSTALLED_APPS = [ ] ``` +To run schema migration, execute `python manage.py migrate casbin_adapter + ## Simple Example ```python From 971aca2958abb3916180ec057fe5a10a2876d607 Mon Sep 17 00:00:00 2001 From: Gerben Neven Date: Thu, 30 Apr 2020 21:03:48 +0200 Subject: [PATCH 09/11] =?UTF-8?q?remove=20.DS=5FStore=20=F0=9F=98=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +++- casbin_adapter/.DS_Store | Bin 6148 -> 0 bytes casbin_adapter/migrations/.DS_Store | Bin 6148 -> 0 bytes casbin_adapter/tests/.DS_Store | Bin 6148 -> 0 bytes 4 files changed, 3 insertions(+), 1 deletion(-) delete mode 100644 casbin_adapter/.DS_Store delete mode 100644 casbin_adapter/migrations/.DS_Store delete mode 100644 casbin_adapter/tests/.DS_Store diff --git a/.gitignore b/.gitignore index aeecc56..414f17c 100644 --- a/.gitignore +++ b/.gitignore @@ -129,4 +129,6 @@ dmypy.json .pyre/ .idea/ -*.iml \ No newline at end of file +*.iml + +.DS_Store diff --git a/casbin_adapter/.DS_Store b/casbin_adapter/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 Date: Tue, 5 May 2020 15:15:03 +0200 Subject: [PATCH 10/11] run tests through django, move tests dir to root --- .travis.yml | 2 +- {casbin_adapter/tests => tests}/__init__.py | 0 .../tests => tests}/rbac_model.conf | 0 .../tests => tests}/rbac_policy.csv | 0 tests/settings.py | 39 +++++++++++++++++++ .../tests => tests}/test_adapter.py | 4 +- 6 files changed, 42 insertions(+), 3 deletions(-) rename {casbin_adapter/tests => tests}/__init__.py (100%) rename {casbin_adapter/tests => tests}/rbac_model.conf (100%) rename {casbin_adapter/tests => tests}/rbac_policy.csv (100%) create mode 100644 tests/settings.py rename {casbin_adapter/tests => tests}/test_adapter.py (98%) diff --git a/.travis.yml b/.travis.yml index 6e6069d..7ddbda9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ install: - pip install -r requirements.txt - pip install coveralls script: -- coverage run -m unittest discover -s tests -t tests +- coverage run -m django test --settings=tests.settings after_success: - coveralls deploy: diff --git a/casbin_adapter/tests/__init__.py b/tests/__init__.py similarity index 100% rename from casbin_adapter/tests/__init__.py rename to tests/__init__.py diff --git a/casbin_adapter/tests/rbac_model.conf b/tests/rbac_model.conf similarity index 100% rename from casbin_adapter/tests/rbac_model.conf rename to tests/rbac_model.conf diff --git a/casbin_adapter/tests/rbac_policy.csv b/tests/rbac_policy.csv similarity index 100% rename from casbin_adapter/tests/rbac_policy.csv rename to tests/rbac_policy.csv diff --git a/tests/settings.py b/tests/settings.py new file mode 100644 index 0000000..9c4e87f --- /dev/null +++ b/tests/settings.py @@ -0,0 +1,39 @@ +SECRET_KEY = 'not-a-production-secret' + +INSTALLED_APPS = [ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "casbin_adapter", + "tests", +] + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", +] + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ] + }, + } +] + +DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}} diff --git a/casbin_adapter/tests/test_adapter.py b/tests/test_adapter.py similarity index 98% rename from casbin_adapter/tests/test_adapter.py rename to tests/test_adapter.py index 96182ee..0177c59 100644 --- a/casbin_adapter/tests/test_adapter.py +++ b/tests/test_adapter.py @@ -4,8 +4,8 @@ from unittest import TestCase from django.test import TestCase -from ..models import CasbinRule -from ..adapter import Adapter +from casbin_adapter.models import CasbinRule +from casbin_adapter.adapter import Adapter def get_fixture(path): From 2d405a950e757bdc77d24208b0cf21b714928b73 Mon Sep 17 00:00:00 2001 From: Gerben Neven Date: Tue, 5 May 2020 15:35:41 +0200 Subject: [PATCH 11/11] remove f-strings for py3.5 compatibility --- casbin_adapter/adapter.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/casbin_adapter/adapter.py b/casbin_adapter/adapter.py index 0509d65..f46b142 100644 --- a/casbin_adapter/adapter.py +++ b/casbin_adapter/adapter.py @@ -52,22 +52,22 @@ def add_policy(self, sec, ptype, rule): def remove_policy(self, sec, ptype, rule): """removes a policy rule from the storage.""" - queryParams = {'ptype': ptype} + query_params = {'ptype': ptype} for i, v in enumerate(rule): - queryParams[f'v{i}'] = v - rows_deleted, _ = CasbinRule.objects.filter(**queryParams).delete() + query_params['v{}'.format(i)] = v + rows_deleted, _ = CasbinRule.objects.filter(**query_params).delete() return True if rows_deleted > 0 else False def remove_filtered_policy(self, sec, ptype, field_index, *field_values): """removes policy rules that match the filter from the storage. This is part of the Auto-Save feature. """ - queryParams = {'ptype': ptype} + query_params = {'ptype': ptype} if not(0 <= field_index <= 5): return False if not (1 <= field_index + len(field_values) <= 6): return False for i, v in enumerate(field_values): - queryParams[f'v{i + field_index}'] = v - rows_deleted, _ = CasbinRule.objects.filter(**queryParams).delete() + query_params['v{}'.format(i + field_index)] = v + rows_deleted, _ = CasbinRule.objects.filter(**query_params).delete() return True if rows_deleted > 0 else False