Skip to content

Commit 2bde85b

Browse files
Started improving organization and formatting
1 parent cc013b5 commit 2bde85b

File tree

3 files changed

+123
-59
lines changed

3 files changed

+123
-59
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""Provides exceptions relevant to graphs"""
2+
3+
4+
class NodeNotReachableException(Exception):
5+
"""
6+
Exception for node distance and path
7+
"""
8+
9+
pass
10+

django_postgresql_dag/models.py

Lines changed: 60 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
from django.db.models import Case, When
1818
from django.core.exceptions import ValidationError
1919

20+
from .exceptions import NodeNotReachableException
21+
from .transformations import *
22+
2023
LIMITING_FK_EDGES_CLAUSE_1 = (
2124
"""AND second.{fk_field_name}_{pk_name} = %(limiting_fk_edges_instance_pk)s"""
2225
)
@@ -189,35 +192,6 @@
189192
"""
190193

191194

192-
class NodeNotReachableException(Exception):
193-
"""
194-
Exception for node distance and path
195-
"""
196-
197-
pass
198-
199-
200-
def _filter_order(queryset, field_names, values):
201-
"""
202-
Filters the provided queryset for 'field_name__in values' for each given field_name in [field_names]
203-
orders results in the same order as provided values
204-
205-
For instance
206-
_filter_order(self.__class__.objects, "pk", pks)
207-
returns a queryset of the current class, with instances where the 'pk' field matches an pk in pks
208-
209-
"""
210-
if not isinstance(field_names, list):
211-
field_names = [field_names]
212-
case = []
213-
for pos, value in enumerate(values):
214-
when_condition = {field_names[0]: value, "then": pos}
215-
case.append(When(**when_condition))
216-
order_by = Case(*case)
217-
filter_condition = {field_name + "__in": values for field_name in field_names}
218-
return queryset.filter(**filter_condition).order_by(order_by)
219-
220-
221195
def node_factory(edge_model, children_null=True, base_model=models.Model):
222196
edge_model_table = edge_model._meta.db_table
223197

@@ -258,7 +232,7 @@ def remove_child(self, child, delete_node=False):
258232
if delete_node:
259233
# Note: Per django docs:
260234
# https://docs.djangoproject.com/en/dev/ref/models/instances/#deleting-objects
261-
# This only deletes the object in the database; the Python instance will still
235+
# This only deletes the object in the database; the Python instance will still
262236
# exist and will still have data in its fields.
263237
child.delete()
264238

@@ -272,7 +246,7 @@ def remove_parent(self, parent, delete_node=False):
272246
if delete_node:
273247
# Note: Per django docs:
274248
# https://docs.djangoproject.com/en/dev/ref/models/instances/#deleting-objects
275-
# This only deletes the object in the database; the Python instance will still
249+
# This only deletes the object in the database; the Python instance will still
276250
# exist and will still have data in its fields.
277251
parent.delete()
278252

@@ -281,7 +255,7 @@ def filter_order_pks(self, pks):
281255
Generates a queryset, based on the current class and the provided pks
282256
"""
283257
return _filter_order(self.__class__.objects, "pk", pks)
284-
258+
285259
def get_pk_name(self):
286260
"""Sometimes we set a field other than 'pk' for the primary key.
287261
This method is used to get the correct primary key field name for the
@@ -310,12 +284,12 @@ def ancestors_raw(self, max_depth=20, **kwargs):
310284
if fk_field_name is not None:
311285
ancestors_clauses_1 += "\n" + LIMITING_FK_EDGES_CLAUSE_1.format(
312286
relationship_table=edge_model_table,
313-
pk_name=self.get_pk_name(),
287+
pk_name=self.get_pk_name(),
314288
fk_field_name=fk_field_name,
315289
)
316290
ancestors_clauses_2 += "\n" + LIMITING_FK_EDGES_CLAUSE_2.format(
317291
relationship_table=edge_model_table,
318-
pk_name=self.get_pk_name(),
292+
pk_name=self.get_pk_name(),
319293
fk_field_name=fk_field_name,
320294
)
321295
query_parameters[
@@ -324,13 +298,19 @@ def ancestors_raw(self, max_depth=20, **kwargs):
324298

325299
# Nodes that MUST NOT be included in the results
326300
if disallowed_nodes_queryset is not None:
327-
ancestors_clauses_1 += "\n" + DISALLOWED_ANCESTORS_NODES_CLAUSE_1.format(
328-
relationship_table=edge_model_table,
329-
pk_name=self.get_pk_name(),
301+
ancestors_clauses_1 += (
302+
"\n"
303+
+ DISALLOWED_ANCESTORS_NODES_CLAUSE_1.format(
304+
relationship_table=edge_model_table,
305+
pk_name=self.get_pk_name(),
306+
)
330307
)
331-
ancestors_clauses_2 += "\n" + DISALLOWED_ANCESTORS_NODES_CLAUSE_2.format(
332-
relationship_table=edge_model_table,
333-
pk_name=self.get_pk_name(),
308+
ancestors_clauses_2 += (
309+
"\n"
310+
+ DISALLOWED_ANCESTORS_NODES_CLAUSE_2.format(
311+
relationship_table=edge_model_table,
312+
pk_name=self.get_pk_name(),
313+
)
334314
)
335315
query_parameters["disallowed_ancestors_node_pks"] = str(
336316
set(disallowed_nodes_queryset.values_list("pk", flat=True))
@@ -357,6 +337,8 @@ def ancestors_raw(self, max_depth=20, **kwargs):
357337
pass # Not implemented yet
358338

359339
NodeModel = self._meta.model
340+
print(ancestors_clauses_1)
341+
print(ancestors_clauses_2)
360342
raw_qs = NodeModel.objects.raw(
361343
ANCESTORS_QUERY.format(
362344
relationship_table=edge_model_table,
@@ -366,6 +348,7 @@ def ancestors_raw(self, max_depth=20, **kwargs):
366348
),
367349
query_parameters,
368350
)
351+
print(query_parameters)
369352
return raw_qs
370353

371354
def ancestors(self, **kwargs):
@@ -406,12 +389,12 @@ def descendants_raw(self, max_depth=20, **kwargs):
406389
if fk_field_name is not None:
407390
descendants_clauses_1 += "\n" + LIMITING_FK_EDGES_CLAUSE_1.format(
408391
relationship_table=edge_model_table,
409-
pk_name=self.get_pk_name(),
392+
pk_name=self.get_pk_name(),
410393
fk_field_name=fk_field_name,
411394
)
412395
descendants_clauses_2 += "\n" + LIMITING_FK_EDGES_CLAUSE_2.format(
413396
relationship_table=edge_model_table,
414-
pk_name=self.get_pk_name(),
397+
pk_name=self.get_pk_name(),
415398
fk_field_name=fk_field_name,
416399
)
417400
query_parameters[
@@ -420,13 +403,19 @@ def descendants_raw(self, max_depth=20, **kwargs):
420403

421404
# Nodes that MUST NOT be included in the results
422405
if disallowed_nodes_queryset is not None:
423-
descendants_clauses_1 += "\n" + DISALLOWED_DESCENDANTS_NODES_CLAUSE_1.format(
424-
relationship_table=edge_model_table,
425-
pk_name=self.get_pk_name(),
406+
descendants_clauses_1 += (
407+
"\n"
408+
+ DISALLOWED_DESCENDANTS_NODES_CLAUSE_1.format(
409+
relationship_table=edge_model_table,
410+
pk_name=self.get_pk_name(),
411+
)
426412
)
427-
descendants_clauses_2 += "\n" + DISALLOWED_DESCENDANTS_NODES_CLAUSE_2.format(
428-
relationship_table=edge_model_table,
429-
pk_name=self.get_pk_name(),
413+
descendants_clauses_2 += (
414+
"\n"
415+
+ DISALLOWED_DESCENDANTS_NODES_CLAUSE_2.format(
416+
relationship_table=edge_model_table,
417+
pk_name=self.get_pk_name(),
418+
)
430419
)
431420
query_parameters["disallowed_downward_node_pks"] = str(
432421
set(disallowed_nodes_queryset.values_list("pk", flat=True))
@@ -437,13 +426,19 @@ def descendants_raw(self, max_depth=20, **kwargs):
437426

438427
# Nodes that MAY be included in the results
439428
if allowed_nodes_queryset is not None:
440-
descendants_clauses_1 += "\n" + ALLOWED_DESCENDANTS_NODES_CLAUSE_1.format(
441-
relationship_table=edge_model_table,
442-
pk_name=self.get_pk_name(),
429+
descendants_clauses_1 += (
430+
"\n"
431+
+ ALLOWED_DESCENDANTS_NODES_CLAUSE_1.format(
432+
relationship_table=edge_model_table,
433+
pk_name=self.get_pk_name(),
434+
)
443435
)
444-
descendants_clauses_2 += "\n" + ALLOWED_DESCENDANTS_NODES_CLAUSE_2.format(
445-
relationship_table=edge_model_table,
446-
pk_name=self.get_pk_name(),
436+
descendants_clauses_2 += (
437+
"\n"
438+
+ ALLOWED_DESCENDANTS_NODES_CLAUSE_2.format(
439+
relationship_table=edge_model_table,
440+
pk_name=self.get_pk_name(),
441+
)
447442
)
448443
query_parameters["allowed_descendants_node_pks"] = str(
449444
set(allowed_nodes_queryset.values_list("pk", flat=True))
@@ -574,7 +569,7 @@ def path_raw(self, target_node, directional=True, max_depth=20, **kwargs):
574569
if fk_field_name is not None:
575570
downward_clauses += "\n" + PATH_LIMITING_FK_EDGES_CLAUSE.format(
576571
relationship_table=edge_model_table,
577-
pk_name=self.get_pk_name(),
572+
pk_name=self.get_pk_name(),
578573
fk_field_name=fk_field_name,
579574
)
580575
query_parameters[
@@ -777,19 +772,25 @@ def descendants(self, node, **kwargs):
777772
"""
778773
Returns a queryset of all edges descended from the given node
779774
"""
780-
return _filter_order(self.model.objects, "parent", node.self_and_descendants(**kwargs))
775+
return _filter_order(
776+
self.model.objects, "parent", node.self_and_descendants(**kwargs)
777+
)
781778

782779
def ancestors(self, node, **kwargs):
783780
"""
784781
Returns a queryset of all edges which are ancestors of the given node
785782
"""
786-
return _filter_order(self.model.objects, "child", node.ancestors_and_self(**kwargs))
783+
return _filter_order(
784+
self.model.objects, "child", node.ancestors_and_self(**kwargs)
785+
)
787786

788787
def clan(self, node, **kwargs):
789788
"""
790789
Returns a queryset of all edges for ancestors, self, and descendants
791790
"""
792-
return _filter_order(self.model.objects, ["parent", "child"], node.clan(**kwargs))
791+
return _filter_order(
792+
self.model.objects, ["parent", "child"], node.clan(**kwargs)
793+
)
793794

794795
def path(self, start_node, end_node, **kwargs):
795796
"""
@@ -826,7 +827,7 @@ def edge_factory(
826827
try:
827828
node_model_name = node_model.split(".")[1]
828829
except IndexError:
829-
830+
830831
node_model_name = node_model
831832
else:
832833
node_model_name = node_model._meta.model_name
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""
2+
Functions for transforming RawQuerySet or other outputs of
3+
django-postgresql-dag to alternate formats.
4+
"""
5+
6+
import networkx as nx
7+
import pandas
8+
9+
10+
def _filter_order(queryset, field_names, values):
11+
"""
12+
Filters the provided queryset for 'field_name__in values' for each given field_name in [field_names]
13+
orders results in the same order as provided values
14+
15+
For instance
16+
_filter_order(self.__class__.objects, "pk", pks)
17+
returns a queryset of the current class, with instances where the 'pk' field matches an pk in pks
18+
19+
"""
20+
if not isinstance(field_names, list):
21+
field_names = [field_names]
22+
case = []
23+
for pos, value in enumerate(values):
24+
when_condition = {field_names[0]: value, "then": pos}
25+
case.append(When(**when_condition))
26+
order_by = Case(*case)
27+
filter_condition = {field_name + "__in": values for field_name in field_names}
28+
return queryset.filter(**filter_condition).order_by(order_by)
29+
30+
31+
def rawqueryset_to_values_list(rawqueryset):
32+
"""Returns a list of lists of each instance"""
33+
columns = rawqueryset.columns
34+
for row in rawqueryset:
35+
yield tuple(getattr(row, column) for column in columns)
36+
37+
38+
def rawqueryset_to_dataframe(rawqueryset):
39+
"""Retruns a pandas dataframe"""
40+
return pandas.DataFrame(
41+
rawqueryset_to_values_list(rawqueryset), columns=list(rawqueryset.columns)
42+
)
43+
44+
45+
def nx_from_edges(queryset, fields_array=None):
46+
"""Provided a queryset of edges, builds a NetworkX graph"""
47+
48+
graph = nx.Graph()
49+
50+
51+
def nx_from_nodes(queryset):
52+
pass
53+

0 commit comments

Comments
 (0)