Git Product home page Git Product logo

django-treenode's Introduction

๐Ÿ‘‹ Hello!

I'm Fabio Caccamo.

I'm a passionate, self-taught full-stack developer based in Torino, Italy. ๐Ÿ‡ฎ๐Ÿ‡น ๐ŸคŒ

I work mainly with ๐Ÿ Python, ๐Ÿฆ„ Django and Vue.js.

I love Open Source, I published and actively maintain many ๐Ÿ“ฆ libraries.

View all my libraries

๐Ÿฆ„ django-admin-interface
๐Ÿ“ฑ FCUUID
๐Ÿ python-benedict
๐Ÿ“ฑ FCFileManager
๐Ÿฆ„ django-treenode
๐Ÿฆ„ django-colorfield
๐Ÿฆ„ django-extra-settings
๐Ÿฆ„ django-maintenance-mode
๐Ÿ“ฑ FCCurrentLocationGeocoder
๐Ÿ python-fsutil
๐Ÿ“ฑ FCIPAddressGeocoder
๐Ÿฆ„ django-freeze
๐Ÿ python-codicefiscale
๐Ÿฆ„ django-redirects
๐Ÿ python-fontbro
๐Ÿ’ป utils.js
๐Ÿฆ„ django-cache-cleaner
:octocat: create-matrix-action
๐Ÿ’ป tabbo.js

django-treenode's People

Contributors

cperrin88 avatar dependabot[bot] avatar fabiocaccamo avatar github-actions[bot] avatar jvacek avatar nathan-cohen avatar pre-commit-ci[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-treenode's Issues

If an object has no parent, admin will throw an exception

I made a super simple, new Django app, and only added this package to test the admin.

Exception Type: AttributeError at /admin/tree/category/
Exception Value: 'Category' object has no attribute 'tn_parents_count'

Upvote & Fund

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar

UUID primary keys don't work

Python version
3.9

Django version
3.2.4

Package version
0.16.0

Current behavior (bug description)
If the primary key of a model is a UUID field the plugin doesn't work.

Traceback

Traceback (most recent call last):
  File "<venv>\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
  File "<venv>\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "<venv>\lib\site-packages\django\contrib\admin\options.py", line 616, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
  File "<venv>\lib\site-packages\django\utils\decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "<venv>\lib\site-packages\django\views\decorators\cache.py", line 44, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "<venv>\lib\site-packages\django\contrib\admin\sites.py", line 232, in inner
    return view(request, *args, **kwargs)
  File "<venv>\lib\site-packages\django\contrib\admin\options.py", line 1660, in change_view
    return self.changeform_view(request, object_id, form_url, extra_context)
  File "<venv>\lib\site-packages\django\utils\decorators.py", line 43, in _wrapper
    return bound_method(*args, **kwargs)
  File "<venv>\lib\site-packages\django\utils\decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "<venv>\lib\site-packages\django\contrib\admin\options.py", line 1540, in changeform_view
    return self._changeform_view(request, object_id, form_url, extra_context)
  File "<venv>\lib\site-packages\django\contrib\admin\options.py", line 1586, in _changeform_view
    self.save_model(request, new_object, form, not add)
  File "<venv>\lib\site-packages\django\contrib\admin\options.py", line 1099, in save_model
    obj.save()
  File "<venv>\lib\site-packages\django\db\models\base.py", line 726, in save
    self.save_base(using=using, force_insert=force_insert,
  File "<venv>\lib\site-packages\django\db\models\base.py", line 774, in save_base
    post_save.send(
  File "<venv>\lib\site-packages\django\dispatch\dispatcher.py", line 180, in send
    return [
  File "<venv>\lib\site-packages\django\dispatch\dispatcher.py", line 181, in <listcomp>
    (receiver, receiver(signal=self, sender=sender, **named))
  File "<venv>\lib\site-packages\treenode\signals.py", line 36, in post_save_treenode
    sender.update_tree()
  File "<venv>\lib\site-packages\treenode\models.py", line 371, in update_tree
    objs_data = cls.__get_nodes_data()
  File "<venv>\lib\site-packages\treenode\models.py", line 446, in __get_nodes_data
    objs_data_dict = {str(obj.pk):obj.__get_node_data(objs_list, objs_dict) for obj in objs_list}
  File "<venv>\lib\site-packages\treenode\models.py", line 446, in <dictcomp>
    objs_data_dict = {str(obj.pk):obj.__get_node_data(objs_list, objs_dict) for obj in objs_list}
  File "<venv>\lib\site-packages\treenode\models.py", line 417, in __get_node_data
    order_strs = [obj.__get_node_order_str() for obj in order_objs]
  File "<venv>\lib\site-packages\treenode\models.py", line 417, in <listcomp>
    order_strs = [obj.__get_node_order_str() for obj in order_objs]
  File "<venv>\lib\site-packages\treenode\models.py", line 394, in __get_node_order_str
    pk_val = min(self.pk, priority_max)
TypeError: '<' not supported between instances of 'int' and 'UUID'

Admin issue

There a few errors in the changelist_view

AttributeError: 'TestTreeNode' object has no attribute 'tn_parents_pks'

And

AttributeError: 'TestTreeNode' object has no attribute 'tn_parents_count'

I suppose ancestors should be used instead of parents

remove verbose logging in django console

it would be nice if the verbose logging in the django console could be removed, i.e. I get the following output for each added item:

[treenode] update acme.models.organization tree: executed 0 queries in 0.4567100000s.
 .
 .
 .
[treenode] update acme.models.organization tree: executed 0 queries in 0.589100000s.

Performance issues

Been trying to create a few thousand items without any hierarchy infos, like this:


# models.py

class Customer(TreeNodeModel):

    treenode_display_field = 'name'
    name = models.CharField(max_length=50)

    class Meta(TreeNodeModel.Meta):
        verbose_name = 'Customer'
        verbose_name_plural = 'Customer'

# script.py

for x in names:
    obj, created = Customer.objects.get_or_create(name=x)

But the DB becomes incredibly slow after a couple hundred rows eg

[treenode] update bpids.models.Customer tree: executed 0 queries in 1.9379002410000226s.
[treenode] update bpids.models.Customer tree: executed 0 queries in 1.9850395860000276s.
[treenode] update bpids.models.Customer tree: executed 0 queries in 2.2034165819999885s.
[treenode] update bpids.models.Customer tree: executed 0 queries in 2.5427609600000096s.
[treenode] update bpids.models.Customer tree: executed 0 queries in 2.6210373019999906s.
[treenode] update bpids.models.Customer tree: executed 0 queries in 3.163530485000024s.
[treenode] update bpids.models.Customer tree: executed 0 queries in 1.538068753999994s.

So totally unusable...

Anything I'm doing wrong?

on emit_post_migrate_signal sender_model.update_tree() raises an exception when used in multitenancy with django_tenants package

I have two schema types public and other type ..On migrating I get an error as that model is not in public schema but in that other type
Below is the error message


File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/django/core/management/commands/migrate.py", line 383, in handle
    emit_post_migrate_signal(
  File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/django/core/management/sql.py", line 52, in emit_post_migrate_signal
    models.signals.post_migrate.send(
  File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/django/dispatch/dispatcher.py", line 176, in send
    return [
           ^
  File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/django/dispatch/dispatcher.py", line 177, in <listcomp>
    (receiver, receiver(signal=self, sender=sender, **named))
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/treenode/signals.py", line 29, in post_migrate_treenode
    sender_model.update_tree()
  File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/treenode/models.py", line 425, in update_tree
    objs_data = cls.__get_nodes_data()
                ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/treenode/models.py", line 509, in __get_nodes_data
    objs_list = list(objs_qs)
                ^^^^^^^^^^^^^
  File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/django/db/models/query.py", line 398, in __iter__
    self._fetch_all()
  File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/django/db/models/query.py", line 1881, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/django/db/models/query.py", line 91, in __iter__
    results = compiler.execute_sql(
              ^^^^^^^^^^^^^^^^^^^^^
  File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 1562, in execute_sql
    cursor.execute(sql, params)
  File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/django/db/backends/utils.py", line 102, in execute
    return super().execute(sql, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/django/db/backends/utils.py", line 67, in execute
    return self._execute_with_wrappers(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers
    return executor(sql, params, many, context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/django/db/backends/utils.py", line 84, in _execute
    with self.db.wrap_database_errors:
  File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/django/db/utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/home/dante/anaconda3/envs/memplas/lib/python3.11/site-packages/django/db/backends/utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
django.db.utils.ProgrammingError: relation "company_stakeholder" does not exist
                                                            ^

Upvote & Fund

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar

Comments

Thank you so much! You have done a great job and created a very good product. At the same time, it should be noted that its main drawback is scarce documentation. It would be nice if you could take a little time and add some small comments to the code.
It's just that I, for example, spend a lot of time to understand what this or that parameter does. For example, I still did not understand what is node priority?
Tnx!

remove a node in tree without deleting descendants

It would be nice to allow for behaviour where deleting a node would create separate disjoint trees. Any suggestions how this could be achieved with the current implementations? I previously had just an FK field to parent node, which had a on_delete=SET_NULL which worked fine for me, and I would like to replicate this behaviour here.

Implement closure-tree to improve performance.

Hello!
I want to share the experience of using the module. Today I see many of its advantages and two main disadvantages. One of them I want to discuss. This is control over the order of elements.

Description of the problem.
The module does not have a transparent and understandable mechanism for ordering elements in the tree. In practice, the most common are two modes: alphabetical sorting and strict order set by the user. The logic dictates that the tn_priority field provided by the default form should do this. If it is set to 0 for all elements, then they must be ordered alphabetically. If it is specified, then the field value determines the order.

But alas, this is not the case.

Another method of establishing a coercive order of elements, which is intuitively prompted by experience, is also not suitable. This is an attempt to import data with the tn_order field set.

It would be nice if you made it easier to manage the order of items in tree.

PS. The main trouble is that with all my attachment to this module, without a mechanism for intelligible order management, I have to refuse to use it. And it just tears my soul to shreds :-(

Funding

  • You can sponsor this specific effort via a Polar.sh pledge below
  • We receive the pledge once the issue is completed & verified
Fund with Polar

Pagination

I scripted creating about 1000 items into my tree and it's a bit slow to load the admin list display and even more slow if I use a raw_id_field for the parent ID (the popup takes like 20 seconds to load).

Is there a way to enable pagination in the admin panel? It's just dumping the full 1000 I generated on each load.

bulk create / update ?

hi,

do you plan to provide the bulk_create/update methods on TreeNodeModel ?

for now I do a manual bulk_update specifying all the fields.

regards,
Jรฉrรฉmy

.update_tree() error value too long for type character varying(500)

treenode tries to set tn_siblings_pks and its could be longer than 500 charts. And thast only with 157 records in my table, where all of them root level

update data

{'tn_siblings_pks': '2,5,46,18,62,142,158,13,40,11,135,51,23,66,6,74,31,98,17,104,19,118,105,83,30,90,15,56,137,54,96,125,148,58,26,50,89,35,29,108,36,86,153,57,87,25,78,84,77,20,85,41,45,44,81,73,109,150,92,37,12,110,48,151,99,133,43,128,103,146,61,156,65,32,155,131,141,42,75,97,34,119,55,64,95,116,147,113,157,106,59,28,126,144,139,132,60,152,9,136,7,107,134,80,33,101,114,121,88,120,49,145,123,22,63,127,79,21,138,24,100,14,129,143,4,3,93,140,154,16,27,47,68,69,71,72,76,82,91,111,67,117,149,10,122,8,53,52,94,124,70,112,39,102,115,130,38', 'tn_siblings_count': 157, 'tn_order': 117, 'tn_index': 117}
Traceback (most recent call last):
  File "C:\Dev\PycharmProjects\rasimplefront\ra-front-simple-nu\back\venv\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
psycopg2.DataError: value too long for type character varying(500)
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "C:\Python36\lib\code.py", line 91, in runcode
    exec(code, self.locals)
  File "<input>", line 1, in <module>
  File "C:\Dev\PycharmProjects\rasimplefront\ra-front-simple-nu\back\venv\lib\site-packages\treenode\models.py", line 367, in update_tree
    cls.objects.filter(pk=obj_pk).update(**obj_data)
  File "C:\Dev\PycharmProjects\rasimplefront\ra-front-simple-nu\back\venv\lib\site-packages\django\db\models\query.py", line 693, in update
    rows = query.get_compiler(self.db).execute_sql(CURSOR)
  File "C:\Dev\PycharmProjects\rasimplefront\ra-front-simple-nu\back\venv\lib\site-packages\django\db\models\sql\compiler.py", line 1383, in execute_sql
    cursor = super().execute_sql(result_type)
  File "C:\Dev\PycharmProjects\rasimplefront\ra-front-simple-nu\back\venv\lib\site-packages\django\db\models\sql\compiler.py", line 1065, in execute_sql
    cursor.execute(sql, params)
  File "C:\Dev\PycharmProjects\rasimplefront\ra-front-simple-nu\back\venv\lib\site-packages\django\db\backends\utils.py", line 100, in execute
    return super().execute(sql, params)
  File "C:\Dev\PycharmProjects\rasimplefront\ra-front-simple-nu\back\venv\lib\site-packages\raven\contrib\django\client.py", line 127, in execute
    return real_execute(self, sql, params)
  File "C:\Dev\PycharmProjects\rasimplefront\ra-front-simple-nu\back\venv\lib\site-packages\django\db\backends\utils.py", line 68, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "C:\Dev\PycharmProjects\rasimplefront\ra-front-simple-nu\back\venv\lib\site-packages\django\db\backends\utils.py", line 77, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "C:\Dev\PycharmProjects\rasimplefront\ra-front-simple-nu\back\venv\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Dev\PycharmProjects\rasimplefront\ra-front-simple-nu\back\venv\lib\site-packages\django\db\utils.py", line 89, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "C:\Dev\PycharmProjects\rasimplefront\ra-front-simple-nu\back\venv\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
django.db.utils.DataError: value too long for type character varying(500)

that kind of make lib unusable

How to use methods like `set_parent` during manual RunPython in migrations?

Python version
3.9.1

Django version
2.2.24

Package version
0.17.0

Current behaviour (bug description)
My model was previously using the MPTT library, and so I'd like to transfer to TreeNode. However I am not really able to do the migration due to the methods not being available when using the apps.get_model tactic, and I think directly working on the keys might not be a good idea seeing as set_parent has things going on.

def migrate_mptt_treenode(apps, schema_editor):
    MyModel = apps.get_model("myapp", "MyModel")
    for c in MyModel.objects.all():
        if c.parent is not None:
            c.set_parent(c.parent)
            c.save()

The info about the parent was stored in parent before, which is a TreeForeignKey Field from MPTT. I want to first migrate in the new fields from treenode, make the migration, and then remove the inheritance for the MPTTModel after the data is moved.

Expected behaviour
I know that apps.get_model doesn't make the methods available, so it's not that this should work. Some alternatives for this use-case would be helpful though.

At the 6th level, treenode reverses the order of descendants.

Python version
3.8.0

Django version
2.2.7

Package version
django-treenode: 0.14.0

Current behavior (bug description)
Here is a single branch with 5 nodes:
image

When I add the 6th descendant node to the branch, the order of descendants begins to reverse as seen below:
image

When I add the 7th and 8th descendant, it follows the same reverse behavior:
image

Here's a snapshot of the table:
image

Am I doing something wrong?

Expected behavior
?

Thank you!

Ordering Problem with recursive method

Hi!

I've a problem when execute TreeNode Model with nested list, the Tree isnยดt respect the order iteration, for example:

FAKE_PAYLOAD = [
    { 'name': "LEGAL",
      'children': [{ 'name': "CORPORATIVO",
                     'children': [{ 'name': "Sub-SubFolder 1" },
                                  { 'name': "Sub-SubFolder 2" },
                                  { 'name': "Sub-SubFolder 3" },
                                  { 'name': "Sub-SubFolder 4" },
                                  { 'name': "Sub-SubFolder 5" },
                                  { 'name': "Sub-SubFolder 6" },
                                  { 'name': "Sub-SubFolder 7" },
                                  { 'name': "Sub-SubFolder 8" },
                                  { 'name': "Sub-SubFolder 9" },
                                  { 'name': "Sub-SubFolder 10" },
                                  { 'name': "Sub-SubFolder 11" },
                                  { 'name': "Sub-SubFolder 12" },
                                  { 'name': "Sub-SubFolder 13" },
                                  { 'name': "Sub-SubFolder 14" },
                                  { 'name': "Sub-SubFolder 15" },
                                  ] },
                   { 'name': "CONTRACTUAL",
                     'children': [
                         { 'name': "Sub-SubFolder 1" },
                         { 'name': "Sub-SubFolder 2" }] },
                   { 'name': "GOBIERNO",
                     'children': [{ 'name': "Sub-SubFolder 1" }] }
                   ] },
]

My model is like this:

class FakeFolder(TreeNodeModel):
    name = models.CharField(max_length=255)

    def __str__(self) -> str:
        return self.name

My recursive method is:

def write_tree(tree_list, parent = None):
    for folder in tree_list:
        folder_obj = FakeFolder.objects.create(name=folder['name'])
        if parent:
            folder_obj.set_parent(parent)
        if 'children' in folder:
            write_tree(folder['children'], folder_obj)

After, executed get_children() of root node, the list it seems wrong order:

FakeFolder.objects.all()[0].children
[<FakeFolder: CONTRACTUAL>, <FakeFolder: CORPORATIVO>, <FakeFolder: GOBIERNO>]

And the order of children_pks is '106,90,109', when the correct order must be maybe '90,106,109' or:

[<FakeFolder: CORPORATIVO>, <FakeFolder: CONTRACTUAL>, <FakeFolder: GOBIERNO>]

With this package it's possible to set order manually? I don't see a method for this. The only way that I've found is with the priority property but only works in descendent order

Thanks!

Add custom cache backend support

Appeared first on issue #19 by @aarondiazr

I see behind of magic performance one weakness, for example if execute this on microservice or serveless, will always go to database because the memory location of cache is independently of any instance of docker, maybe a feature with redis will be great.

Database Configuration error in update_tree

Hello,

I'm contacting you to report a database configuration problem in the update_tree method of the TreeNodeModel class, which causes the following error:
settings.DATABASES is improperly configured. Please supply the ENGINE value. Check settings documentation for more details.

The method concerned is as follows:

def update_tree(cls):
        debug_message_prefix = (
            f"[treenode] update {cls.__module__}.{cls.__name__} tree: "
        )

        with debug_performance(debug_message_prefix):
            # update db
            objs_data = cls.__get_nodes_data()

            with transaction.atomic():   # <- Here lies the problem
                obj_manager = cls.objects
                for obj_pk, obj_data in objs_data.items():
                    obj_manager.filter(pk=obj_pk).update(**obj_data)

            # update in-memory instances
            update_refs(cls, objs_data)

            # update cache instances
            update_cache(cls)

I suggest solving this problem by modifying the with transaction.atomic(): block as follows :
with transaction.atomic(using=router.db_for_write(AccessAttempt)):

The final result would be :

def update_tree(cls):
        debug_message_prefix = (
            f"[treenode] update {cls.__module__}.{cls.__name__} tree: "
        )

        with debug_performance(debug_message_prefix):
            # update db
            objs_data = cls.__get_nodes_data()

            with transaction.atomic(using=router.db_for_write(AccessAttempt)): # <- Correction applied here
                obj_manager = cls.objects
                for obj_pk, obj_data in objs_data.items():
                    obj_manager.filter(pk=obj_pk).update(**obj_data)

            # update in-memory instances
            update_refs(cls, objs_data)

            # update cache instances
            update_cache(cls)

Correction Proposal

  • i am willing to create a Pull Request to make this correction if you find it appropriate. I'd be happy to help solve this problem and improve this project.

  • By explicitly specifying using=router.db_for_write(AccessAttempt) when using transaction.atomic(), we make it clear to Django which database router should be used for this particular operation. This can be crucial in environments where there are multiple database configurations, to ensure that write operations are directed to the correct database that supports writing, thus avoiding potential problems associated with attempts to write to a read-only database.

Additional details

Affected class: TreeNodeModel
Relevant method: update_tree
Affected file: /treenode/models.py
I thank you in advance for your time and consideration and remain available to discuss this issue further if needed.

Upvote & Fund

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar

treenode's sorting is not OK

Hi,

i reproduce a directories treenode with name's sorting and in a directory viewer the sorting seem to be OK but with treenode, it's not OK.
It seem to me that there is a problem with letter and number.

see in attachments 2 screenshots, one to see the directory and the other to see in the treenode directory.

image

image

here is my pip list output :
backports.csv (1.0.7)
defusedxml (0.6.0)
diff-match-patch (20181111)
Django (2.1)
django-debug-toolbar (1.11)
django-extensions (2.1.7)
django-import-export (1.2.0)
django-js-asset (1.2.2)
django-treenode (0.13.1)
et-xmlfile (1.0.1)
jdcal (1.4.1)
odfpy (1.4.0)
openpyxl (2.6.2)
pip (9.0.1)
pkg-resources (0.0.0)
psycopg2-binary (2.8.2)
pydotplus (2.0.2)
pyparsing (2.4.0)
pytz (2019.1)
PyYAML (5.1)
setuptools (32.3.1)
six (1.12.0)
sqlparse (0.3.0)
tablib (0.13.0)
wheel (0.33.4)
xlrd (1.2.0)
xlwt (1.3.0)

question: migrating from django-mptt to django-treenode

I used some of your work in my projects, and they are fantastic; thank you for your hard work.

I have a question, but I'm hesitant to explore till I know whether there is a history example; I searched and couldn't discover anything informative.

I'm working on a project where I'm using django-mptt, and it's becoming clear that it has constraints that are harming the overall development quality and experience. Is it your understanding that transitioning from mptt to treenode is possible/feasible?

Thank you, Layth.

Order is too small for big trees

Hi,

Python version
3.9

Django version
3.2

Package version
0.17.0

Current behavior (bug description)
I try to store unix FS trees in PostgreSQL using django-treenode. The tree contains around 77000 files.
All the files are loaded flatten into db, then I do some batch update to rebuild the tree.

During the call to update_tree(), the DB update raises a "smallint out of range" error. It seems to be the order field that is out of range:
[...]"tn_depth" = 1, "tn_level" = 4, "tn_order" = 33673, "tn_index" = 6 WHERE[...]

I tried to force the order to 0, but it did not help.

Expected behavior
update_tree() is working on large trees.

Search for subnodes in accordion admin isn't possible

Search for subnodes in accordion admin isn't possible, because the parent nodes are collapsed and can not be opened.

Model:
class Element(TreeNodeModel): TYPES = Choices('Namespace', 'Class', 'Object') name = models.CharField(max_length=255, blank=False, null=False, unique=True) model_type = models.CharField( choices=TYPES, default=TYPES.Object, max_length=100) treenode_display_field = 'name'

Admin:
@admin.register(models.Element) class ElementAdmin(TreeNodeModelAdmin): # admin.ModelAdmin treenode_accordion = True autocomplete_fields = ['tn_parent'] list_display = ('id', 'model_type', ) search_fields = ['name', 'tn_parent__name'] exclude = ('tn_priority', ) form = TreeNodeForm

No search:
grafik

Search for child node:
grafik

Note in docs about thread/multi process safety

The worst problem I've had with treebeard is lack of thread/multi process safety.

It's easily demonstrated by running two processes at the same time that each have a loop that adds nodes to the tree.
(because the key generation + adding nodes is not an atomic operation).

Does django-treenode solve this ?

If it does it would be great to have a note in the README.

String PK support

Hello,

Currently, trying to compare string primary keys will fail because treenode will try to compare the pk (a string) to a number.

image

Could we please add a support to string primary keys ? :)

Thank you very much !

QUESTION: Tree of different models

Hi,
I'm currently building an application and I want to manage a tree of different models in the django admin console. Like the following:

โ”œโ”€โ”€ Chapter1
โ””โ”€โ”€ Chapter2
    โ”œโ”€โ”€ Part1
    โ”œโ”€โ”€ Part2

Is this possilbe or is there a better way to achive this in django admin ? :)

List of reserved field names

I think it would be helpful to have list of reserved field names that should not be used, for example 'level' as I just discovered. Thanks for the library. Keep up the great work.

Implement treenode in CreateView or ModelForm

I am trying implement treenode without admin, and I was curious to know if you have an example of either a CreateView or a ModelForm. Or have any suggestions. I really like your efforts, amazing job, but I do not want regular users into the admin.

tn_descendants_count is too small for big trees

Python version
3.9

Django version
3.2

Package version
0.18.0

Current behavior (bug description)
since the fix of #44, a new exception is raised during my big tree building.

Expected behavior
use treenode for my ~ 100k nodes tree.

Cache update error

Python version 3.9
Django version 3.2
Package version 0.16.0

Current behavior (bug description)
I just want to say that the error manifests itself in very exotic circumstances.

  1. I created an abstract model from TreeNodeModel
  2. Dynamically, using the operator type(), I create an instance of the tree model, inheriting the model from the previously created abstract model. Entries in ContentType and Permissions have been created. The model is registered in the apps register.
  3. Dynamically using schema_editor.create_model() tables are created in the database

Now the essence of the error. When trying to add a new entry through the admin site, an error occurs in the cache:
Can't pickle <class 'my_app_name.my_module.my_model'>: attribute lookup my_model on my_app_name.my_module failed

Error tracing:
File "D:\Envs\django\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "D:\Envs\django\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "D:\Envs\django\lib\site-packages\django\contrib\admin\options.py", line 616, in wrapper
return self.admin_site.admin_view(view)(*args, **kwargs)
File "D:\Envs\django\lib\site-packages\django\utils\decorators.py", line 130, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "D:\Envs\django\lib\site-packages\django\views\decorators\cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "D:\Envs\django\lib\site-packages\django\contrib\admin\sites.py", line 232, in inner
return view(request, *args, **kwargs)
File "D:\Envs\django\lib\site-packages\django\contrib\admin\options.py", line 1655, in add_view
return self.changeform_view(request, None, form_url, extra_context)
File "D:\Envs\django\lib\site-packages\django\utils\decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "D:\Envs\django\lib\site-packages\django\utils\decorators.py", line 130, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "D:\Envs\django\lib\site-packages\django\contrib\admin\options.py", line 1538, in changeform_view
return self._changeform_view(request, object_id, form_url, extra_context)
File "D:\Envs\django\lib\site-packages\django\contrib\admin\options.py", line 1584, in _changeform_view
self.save_model(request, new_object, form, not add)
File "D:\Envs\django\lib\site-packages\django\contrib\admin\options.py", line 1097, in save_model
obj.save()
File "D:\Envs\django\lib\site-packages\django\db\models\base.py", line 726, in save
self.save_base(using=using, force_insert=force_insert,
File "D:\Envs\django\lib\site-packages\django\db\models\base.py", line 774, in save_base
post_save.send(
File "D:\Envs\django\lib\site-packages\django\dispatch\dispatcher.py", line 180, in send
return [
File "D:\Envs\django\lib\site-packages\django\dispatch\dispatcher.py", line 181, in
(receiver, receiver(signal=self, sender=sender, **named))
File "D:\Envs\django\lib\site-packages\treenode\signals.py", line 36, in post_save_treenode
sender.update_tree()
File "D:\Envs\django\lib\site-packages\treenode\models.py", line 382, in update_tree
update_cache(cls)
File "D:\Envs\django\lib\site-packages\treenode\cache.py", line 61, in update_cache
_set_cached_collections(l, d)
File "D:\Envs\django\lib\site-packages\treenode\cache.py", line 33, in _set_cached_collections
c.set('treenode_list', l)

File "D:\Envs\django\lib\site-packages\django\core\cache\backends\locmem.py", line 56, in set
pickled = pickle.dumps(value, self.pickle_protocol)

I understand that dynamic use of the model was not provided for by you, as well as by the developers of Django. But I am weak in dealing with the cache. Perhaps I missed something when creating the model, registering it. I'm asking for ideas on what could have gone wrong. Models created in this way from standard prototypes work great.

I would appreciate any ideas

django dataload > 'NoneType' object has no attribute 'get_parent_pk'

Python version
3.11

Django version
4.1.7

Package version
0.19.0

Current behavior (bug description)

With Simple Model with no relation

class MyModel(models.Model, TreeNodeModel):
    ...
    name: str = models.CharField(max_length=50)
    treenode_display_field = "name"
    ...

After some inserts with parentals relations, then a django dumpdata with this model only :

python manage.py dumpdata MyModel --output=my_model.json

on a standart django dataload :

python manage.py loaddata my_model
> AttributeError: Problem installing fixture 'my_model.json': 'NoneType' object has no attribute 'get_parent_pk'

Expected behavior

dataload OK

Fund with Polar

Queries getting slower during progress

Thank you for providing this nice library. I am using it in a scientific project for twitter analysis. However, the db inserts seem to slow down a lot after a couple of days running it in production mode:

[treenode] update delab.models.Tweet tree: executed 0 queries in 71.44206510693766s.
[treenode] update delab.models.Tweet tree: executed 0 queries in 71.87405565101653s.
[treenode] update delab.models.Tweet tree: executed 0 queries in 66.6588648010511s.
[treenode] update delab.models.Tweet tree: executed 0 queries in 71.47152532404289s.
[treenode] update delab.models.Tweet tree: executed 0 queries in 79.63660701399203s.

I opened the issue also within my project, if you are interested in the way the library is used:
juliandehne/delab#15

Probably, I will write a unit test to verify it is an issue with the treenode library.

Any ideas?

Fund with Polar

Django-treenode for Django 2.1

Hello, I use your application django-treenode I really like it.
I would like to ask to update it to the version of Django 2.1.
Now it works on versions 2.0.8, and the error appears at 2.1 when the admin panel is opened. The error message is shown below.
Thanks for the help.

Environment:

Request Method: GET
Request URL: http://127.0.0.1:8000/admin/platforms/platforms/

Django Version: 2.1
Python Version: 3.7.0
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sitemaps',
'debug_toolbar',
'django_cleanup',
'comment',
'users',
'software',
'platforms',
'category',
'main',
'activity',
'markdownify',
'treenode']
Installed 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',
'debug_toolbar.middleware.DebugToolbarMiddleware']

Traceback:

File "C:\Users\Work\Desktop\choiceapps\venv\lib\site-packages\django\core\handlers\exception.py" in inner
34. response = get_response(request)

File "C:\Users\Work\Desktop\choiceapps\venv\lib\site-packages\django\core\handlers\base.py" in _get_response
126. response = self.process_exception_by_middleware(e, request)

File "C:\Users\Work\Desktop\choiceapps\venv\lib\site-packages\django\core\handlers\base.py" in _get_response
124. response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Users\Work\Desktop\choiceapps\venv\lib\site-packages\django\contrib\admin\options.py" in wrapper
607. return self.admin_site.admin_view(view)(*args, **kwargs)

File "C:\Users\Work\Desktop\choiceapps\venv\lib\site-packages\django\utils\decorators.py" in _wrapped_view
142. response = view_func(request, *args, **kwargs)

File "C:\Users\Work\Desktop\choiceapps\venv\lib\site-packages\django\views\decorators\cache.py" in _wrapped_view_func
44. response = view_func(request, *args, **kwargs)

File "C:\Users\Work\Desktop\choiceapps\venv\lib\site-packages\django\contrib\admin\sites.py" in inner
223. return view(request, *args, **kwargs)

File "C:\Users\Work\Desktop\choiceapps\venv\lib\site-packages\django\utils\decorators.py" in _wrapper
45. return bound_method(*args, **kwargs)

File "C:\Users\Work\Desktop\choiceapps\venv\lib\site-packages\django\utils\decorators.py" in _wrapped_view
142. response = view_func(request, *args, **kwargs)

File "C:\Users\Work\Desktop\choiceapps\venv\lib\site-packages\django\contrib\admin\options.py" in changelist_view
1685. cl = self.get_changelist_instance(request)

File "C:\Users\Work\Desktop\choiceapps\venv\lib\site-packages\django\contrib\admin\options.py" in get_changelist_instance
745. sortable_by,

File "C:\Users\Work\Desktop\choiceapps\venv\lib\site-packages\django\contrib\admin\views\main.py" in init
80. self.queryset = self.get_queryset(request)

File "C:\Users\Work\Desktop\choiceapps\venv\lib\site-packages\django\contrib\admin\views\main.py" in get_queryset
359. filters_use_distinct) = self.get_filters(request)

File "C:\Users\Work\Desktop\choiceapps\venv\lib\site-packages\django\contrib\admin\views\main.py" in get_filters
113. for list_filter in self.list_filter:

Exception Type: TypeError at /admin/platforms/platforms/
Exception Value: 'NoneType' object is not iterable

[Question] Can I use this library to represent related models?

I have the following models:

  • Structure
  • StructureSeries
  • StructureSeriesSlot

The model Structure has many StructureSeries. In turn, StructureSeries has many StructureSeriesSlot.

I noticed your example covers only for the records within the same model class to be treenodes within that model class.

Does it work for related models (related via ForeignKey Field)?

django-fast-treenode

@fabiocaccamo , have you seen django-fast-treenode ?

I suggested that perhaps the changes in django-fast-treenode should be contributed to this package rather than maintained separately. What do you think?

Upvote & Fund

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar

Suggestion: have `treenode_display_field` use `__str__()` as default fallback

We don't have a name-like field in our model, and our __str__ is a combination of the pk, and some other fields. I had to create this in order to have the Admin work, but it would be nice if this could be handled library-side default.

@property
def name(self):
    return str(self)

Something like "unless the treenode_display_field is provided, try using the class' __str__ if it has one)"

This way you wouldn't have to define treenode_display_field in most cases at all

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.