Skip to content

Commit 97e7335

Browse files
Updated to separate networkx and pandas from required imports
1 parent 6d7b9ae commit 97e7335

File tree

6 files changed

+220
-184
lines changed

6 files changed

+220
-184
lines changed

django_postgresql_dag/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from django.core.exceptions import ValidationError
1313

1414
from .exceptions import NodeNotReachableException
15-
from .transformations import _ordered_filter
15+
from .utils import _ordered_filter
1616
from .query_builders import (
1717
AncestorQuery,
1818
DescendantQuery,

django_postgresql_dag/query_builders.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from abc import ABC, abstractmethod
22
from django.core.exceptions import ImproperlyConfigured
3-
from .transformations import get_instance_characteristics, get_queryset_characteristics
3+
from .utils import get_instance_characteristics, get_queryset_characteristics
44

55

66
class BaseQuery(ABC):

django_postgresql_dag/transformations.py

Lines changed: 3 additions & 182 deletions
Original file line numberDiff line numberDiff line change
@@ -3,191 +3,12 @@
33
django-postgresql-dag to alternate formats.
44
"""
55

6-
from itertools import chain
7-
86
import networkx as nx
97
import pandas as pd
10-
from django.core.exceptions import FieldDoesNotExist
11-
from django.db.models import Case, When
12-
from django.db.models.fields import DateTimeField, UUIDField
13-
from django.db.models.fields.files import FileField, ImageField
14-
from django.db.models.fields.related import ManyToManyField
15-
16-
from .exceptions import (GraphModelsCannotBeParsedException,
17-
IncorrectUsageException)
18-
19-
20-
def _ordered_filter(queryset, field_names, values):
21-
"""
22-
Filters the provided queryset for 'field_name__in values' for each given field_name in [field_names]
23-
orders results in the same order as provided values
24-
25-
For instance
26-
_ordered_filter(self.__class__.objects, "pk", pks)
27-
returns a queryset of the current class, with instances where the 'pk' field matches an pk in pks
28-
29-
"""
30-
if not isinstance(field_names, list):
31-
field_names = [field_names]
32-
case = []
33-
for pos, value in enumerate(values):
34-
when_condition = {field_names[0]: value, "then": pos}
35-
case.append(When(**when_condition))
36-
order_by = Case(*case)
37-
filter_condition = {field_name + "__in": values for field_name in field_names}
38-
return queryset.filter(**filter_condition).order_by(order_by)
39-
40-
41-
def get_instance_characteristics(instance):
42-
"""
43-
Returns a tuple of the node & edge model classes and the instance_type
44-
for the provided instance
45-
"""
46-
try:
47-
# Assume a queryset of nodes was provided
48-
_NodeModel = instance._meta.model
49-
_EdgeModel = instance._meta.model._meta.get_field("parents").through
50-
instance_type = "node"
51-
except FieldDoesNotExist:
52-
try:
53-
# Assume a queryset of edges was provided
54-
_EdgeModel = instance._meta.model
55-
_NodeModel = instance._meta.model._meta.get_field("parent").related_model
56-
instance_type = "edge"
57-
except FieldDoesNotExist:
58-
raise GraphModelsCannotBeParsedException
59-
return (_NodeModel, _EdgeModel, instance_type)
60-
61-
62-
def get_queryset_characteristics(queryset):
63-
"""
64-
Returns a tuple of the node & edge model classes and the queryset type
65-
for the provided queryset
66-
"""
67-
try:
68-
# Assume a queryset of nodes was provided
69-
_NodeModel = queryset.model
70-
_EdgeModel = queryset.model._meta.get_field("parents").through
71-
queryset_type = "nodes_queryset"
72-
except FieldDoesNotExist:
73-
try:
74-
# Assume a queryset of edges was provided
75-
_EdgeModel = queryset.model
76-
_NodeModel = queryset.model._meta.get_field("parent").related_model
77-
queryset_type = "edges_queryset"
78-
except FieldDoesNotExist:
79-
raise GraphModelsCannotBeParsedException
80-
return (_NodeModel, _EdgeModel, queryset_type)
81-
82-
83-
def model_to_dict(instance, fields=None, date_strf=None):
84-
"""
85-
Returns a dictionary of {field_name: field_value} for a given model instance
86-
e.g.: model_to_dict(myqueryset.first(), fields=["id",])
87-
88-
For DateTimeFields, a formatting string can be provided
89-
90-
Adapted from: https://ziwon.github.io/post/using_custom_model_to_dict_in_django/
91-
"""
92-
93-
if not fields:
94-
raise IncorrectUsageException("fields list must be provided")
95-
96-
opts = instance._meta
97-
data = {}
98-
__fields = list(map(lambda a: a.split("__")[0], fields or []))
99-
100-
for f in chain(opts.concrete_fields, opts.private_fields, opts.many_to_many):
101-
is_editable = getattr(f, "editable", False)
102-
103-
if fields and f.name not in __fields:
104-
continue
105-
106-
if isinstance(f, DateTimeField):
107-
dt = f.value_from_object(instance)
108-
# Format based on format string provided, otherwise return a timestamp
109-
data[f.name] = dt.strftime(date_strf) if date_strf else dt.timestamp()
110-
111-
elif isinstance(f, ImageField):
112-
image = f.value_from_object(instance)
113-
data[f.name] = image.url if image else None
114-
115-
elif isinstance(f, FileField):
116-
file = f.value_from_object(instance)
117-
data[f.name] = file.url if file else None
118-
119-
elif isinstance(f, ManyToManyField):
120-
if instance.pk is None:
121-
data[f.name] = []
122-
else:
123-
qs = f.value_from_object(instance)
124-
if qs._result_cache is not None:
125-
data[f.name] = [item.pk for item in qs]
126-
else:
127-
try:
128-
m2m_field = list(
129-
filter(lambda a: f.name in a and a.find("__") != -1, fields)
130-
)[0]
131-
key = m2m_field[len(f.name) + 2 :]
132-
data[f.name] = list(qs.values_list(key, flat=True))
133-
except IndexError:
134-
data[f.name] = list(qs.values_list("pk", flat=True))
135-
136-
if isinstance(f, UUIDField):
137-
uuid = f.value_from_object(instance)
138-
data[f.name] = str(uuid) if uuid else None
139-
140-
# ToDo: Process other model fields
141-
142-
elif is_editable:
143-
data[f.name] = f.value_from_object(instance)
144-
145-
funcs = set(__fields) - set(list(data.keys()))
146-
for func in funcs:
147-
obj = getattr(instance, func)
148-
if inspect.ismethod(obj):
149-
data[func] = obj()
150-
else:
151-
data[func] = obj
152-
return data
153-
154-
155-
def edges_from_nodes_queryset(nodes_queryset):
156-
"""Given an Edge Model and a QuerySet or RawQuerySet of nodes,
157-
returns a queryset of the associated edges"""
158-
_NodeModel, _EdgeModel, queryset_type = get_queryset_characteristics(nodes_queryset)
159-
160-
if queryset_type == "nodes_queryset":
161-
return _ordered_filter(_EdgeModel.objects, ["parent", "child"], nodes_queryset)
162-
raise IncorrectQuerysetTypeException
163-
164-
165-
def nodes_from_edges_queryset(edges_queryset):
166-
"""Given a Node Model and a QuerySet or RawQuerySet of edges,
167-
returns a queryset of the associated nodes"""
168-
_NodeModel, _EdgeModel, queryset_type = get_queryset_characteristics(edges_queryset)
169-
170-
if queryset_type == "edges_queryset":
171-
172-
nodes_list = (
173-
_ordered_filter(
174-
_NodeModel.objects,
175-
[
176-
f"{_NodeModel.__name__}_child",
177-
],
178-
edges_queryset,
179-
)
180-
| _ordered_filter(
181-
_NodeModel.objects,
182-
[
183-
f"{_NodeModel.__name__}_parent",
184-
],
185-
edges_queryset,
186-
)
187-
).values_list("pk")
1888

189-
return _NodeModel.objects.filter(pk__in=nodes_list)
190-
raise IncorrectQuerysetTypeException
9+
from .utils import (_ordered_filter, get_queryset_characteristics,
10+
model_to_dict, edges_from_nodes_queryset,
11+
nodes_from_edges_queryset)
19112

19213

19314
def nx_from_queryset(

0 commit comments

Comments
 (0)