Last active
November 14, 2020 10:42
-
-
Save spookylukey/33afaa72edbb8d436fea45182aae49bc to your computer and use it in GitHub Desktop.
Visidata 1.x glue code for Django models and attrs, with type support
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from datetime import date | |
import visidata | |
from django.db.models import QuerySet | |
def get_main_attrs(instance): | |
if hasattr(instance, '_meta'): | |
return meta_to_col_list(instance._meta) | |
elif hasattr(instance, '__attrs_attrs__'): | |
return [(field.name, field.type or visidata.anytype) | |
for field in instance.__attrs_attrs__] | |
return [] | |
def meta_to_col_list(_meta): | |
retval = [] | |
for field in _meta.get_fields(): | |
if not hasattr(field, 'get_attname'): | |
continue | |
if getattr(field, 'many_to_many', False): | |
continue | |
retval.append((field.get_attname(), django_to_vd_type(field))) | |
return retval | |
def django_to_vd_type(field): | |
return { | |
'AutoField': int, | |
'BigAutoField': int, | |
'BigIntegerField': int, | |
'BooleanField': int, | |
'DateField': date, | |
'DecimalField': float, | |
'FloatField': float, | |
'ForeignKey': int, # good enough for now... | |
'PositiveIntegerField': int, | |
'PositiveSmallIntegerField': int, | |
'SmallIntegerField': int, | |
'CharField': str, | |
'TextField': str, | |
}.get(field.get_internal_type(), visidata.anytype) | |
class QuerySetSheet(visidata.Sheet): | |
@visidata.asyncthread | |
def reload(self): | |
self.rows = [] | |
self.columns = [ | |
visidata.ColumnAttr(name, type=t) | |
for name, t in meta_to_col_list(self.source.model._meta) | |
] | |
for item in visidata.Progress(self.source.iterator(), total=self.source.count()): | |
self.rows.append(item) | |
class AutoSheet(visidata.Sheet): | |
def reload(self): | |
self.rows = self.source | |
if len(self.rows) == 0: | |
self.columns = [] | |
else: | |
self.columns = [visidata.ColumnAttr(name, type=t) | |
for name, t in get_main_attrs(self.rows[0]) | |
] | |
def vd(objects): | |
""" | |
Wrapper around visidata.run with custom sheet types | |
""" | |
sheet = None | |
if isinstance(objects, QuerySet): | |
sheet = QuerySetSheet(objects.model.__name__, source=objects) | |
elif isinstance(objects, list) and len(objects) > 0: | |
instance = objects[0] | |
if hasattr(instance, '_meta') or hasattr(instance, '__attrs_attrs__'): | |
sheet = AutoSheet(instance.__class__.__name__, source=objects) | |
if sheet is None: | |
sheet = visidata.load_pyobj('', objects) | |
return visidata.run(sheet) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See https://gist.github.com/spookylukey/08ba8a0b937b0d2d1367643f7bf7d1d0 for VisiData 2