Porting and existing nested set hierarchy - django

I have a nested set category table developed with the PHP ORM Doctrine and I would like to port it to a Django app.
I started porting it to django-treebeard, but I am having difficulties and I am not sure it can work.
The original table had the needed fields lft, rgt and depth, so I added the tree_id field.
I also had a foreign key to Accounts with one tree/account. Thus the table hold multiple independent trees that are not under a common root, with the lft and depth columns starting at 1 for each tree. So basically one nested set for each account in the table.
I can add nodes to a tree just fine, but when I call the get_last_child method, I get nodes from other accounts.
Does anyone know if there is a way to use treebeard, mptt or any other package without having to restructure the trees?

I made some progress by adding the correct tree_id as a sequential number by account_id, which fixed some of the issues, with the query:
UPDATE category c,
(SELECT id, DENSE_RANK() OVER (ORDER BY account_id) AS seq
FROM category ) tree_rank
SET c.tree_id = tree_rank.seq
WHERE c.id = tree_rank.id;
Now trying to get the admin to work.

Related

Ordered ManyToMany relation in Django with custom Field

In Django, I would like to have an ordered many-to-many-relation. Assume I have, say, the models OrderedList and Item, and I want to be able to insert Item()s into an OrderedList() at a specific index, I want to be able to retrieve the Item()s of an OrderedList() in their order and also to change the order of Item()s on an OrderedList
I already found Define an order for ManyToManyField with django and https://github.com/gregmuellegger/django-sortedm2m
Both the github repo and the accepted answer in the SO question are working with the same architecture: They create an additional integer field, say order_index, on the junction ("Through") table which represents the position of the Item() on the OrderedList().
Honestly, I do not like that too much. If I see this correctly, having the order stored on the junction table can create inefficiency when I want to reorder Item()s: Imagine, I want to change the position of an Item() on an OrderedList() which has n Item()s. This means O(n) database updates to reorganize the order indices.
I would like to avoid this. I think of an architecture where I have an ordinary many-to-many-relation and one additional column on the OrderedList table which holds a list of Item ids, say items_order. In this architecture, I need one database update and one list operation on items_order - which should be way faster, I guess.
I believe the best way for this is to create a custom model Field. The docs state how to create a custom model Field (https://docs.djangoproject.com/en/2.1/howto/custom-model-fields/) and I can create my items_order field like this. But I did not find how to make a custom Field which, besides creating the order_list, also creates the junction table and takes care of updating the items_order whenever a new related Item() is added or removed from the relation. I think, I should subclass the ManyToMany Field (https://docs.djangoproject.com/en/2.1/_modules/django/db/models/fields/related/#ManyToManyField). But I don't know how to do this, so could you give me some guidance here?

Django filtering with F and Q operations

I have a model class in my django project:
*user_id
*amount
*net_balance
*created_on
I have a list of user_ids(let's say 3). I need to get the last row for each user_id and then do some operation and create a new row for each user id. How do this efficiently. I can certainly do 6 transactions (if there are 3 items in list of userids).
If you want the most recent entry then
YourModel.objects.filter(user=user_id).latest('created_on')
If I understand your question correctly then you need to get all the user_ids (presumably you have a separate User model?) and then loop through them - for each user getting the most recent entry and then create the new row.
You need 1 select (at least) for all the records you interested and 1 insert query for each record returned.
The select query can be generated by ORM abilities (aggregation) or you can use raw SQL if you fill comfortable. If you use PostgreSQL, you can use distinct ability (I recommended) as:
Model.objects.order_by('user_id', '-created_on').distinct('user_id')
or you can use aggregation abilities as:
Model.objects.filter(user_id__in=[1,2,3]).values('user_id', 'created_on').annotate(last_row=Max('created_on')).filter(created_on=F('last_row'))
The correct answer depends on your Django version and database. But there are lots of good features in Django to achieve this kind of stuffs.

Loading data from associated model in same query in rails

Basically, I have a Listing model, where each listing has a country id. I need the country name in my search results view. I know I can do #listing.country.name, but this performs an extra query for each listing in my search results. I'm using Thinking Sphinx, and in my controller I have
#listings = Listing.search(#ts_params).page(page_num).per(limit)
I have tried adding .includes(:countries) and variations thereof but no luck.
What's the best way to go about this? I want the country data to be fetched in the same query as the listings.
I have exactly the same issue with listing images - it is performing an extra query for every listing to find the image, when surely it can be done in one with joins.
Are you trying to eager load the associated model (to avoid an N + 1 query problem), or are you trying to load the associated model into fields on the parent model?
If it's the former, you're probably better off forgetting about :select and instead of :joins using:
ts_params[:sql][:include] = :countries, :listing_images
Now you should be able to call listing.countries and listing.listing_images to access child models, as normal.
Thinking Sphinx provides functionality to eager load associated entities, so for eager loading we don't need to add [:sql]. Following is the way to do this.
For eager loading associated entities using sphinx.
ts_params[:include] = [:country, :listing_image]
I managed to solve this using the :sql hash provided by Thinking Sphinx. I now have the following:
#ts_params[:sql][:joins] = "INNER JOIN countries ON countries.id = listings.country_id INNER JOIN listing_images ON listing_images.listing_id = listings.id"
#ts_params[:sql][:select] = "listings.*, countries.name as country_name, listing_images.image as image_name"
This is correctly retrieving the country name and image name, but I still have a bit of work to do in making it work with the images - I think that will deserve its own question!
Current v4 syntax is:
Article.search :sql => {:include => :user}
Ref: https://freelancing-gods.com/thinking-sphinx/v4/searching.html

Web2py: id as foreign key

I am trying to implement some tables that mimic inheritance in a relational (sqlite) database. My goal is to have one master table with general fields, and some child tables with specialized fields. Every record in the master table will have exactly one counterpart in exactly one of the specific tables. What I want looks like this:
Master table:
id (PK) #Your average web2py unique auto-incrementing int field
#Some general fields
Child tables:
id (PK, FK referencing the PK of the master table)
#Some specialized fields
Having a default "id" PK for each child table has no use to me. All I need is an FK reference to the master table, which can serve as the PK for the child tables. This means that the PK of the child tables will be unique, but will contain gaps. This is because a child table will only reference some of the records of the master table.
I get the impression that doing this (not giving the child tables the regular "id" PK) is against the Web2py way. So my questions are as follows:
Is this a Bad Idea™? If so, why?
How would I implement this? Can Web2py handle tables that don't have an auto-incrementing int as PK?
It's very important for me to apply the correct style and practice when writing code. I am open to alternative approaches.
Thank you for your help.
See the book section on keyed tables. If this is a database specifically for use with web2py, I suggest you stick with the standard web2py approach:
db.define_table('master', ...)
db.define_table('child', Field('master', db.master))

querying a result of cfquery or filtering cfquery

I have two tables of data categories and category relations. This is a setup to allow infinite levels of parent/child relationships.
I could put it into a linked list too I guess, but this might allow one child to have multiple parents if the need ever comes up.
I have a query that combines these two as well as some other tables, and using those I have a list of all categories. I want to sort them by the level they're at, without counting and updating the database with the depth level.
and now the question....
Is there a way to do a where operation on a query, or filter it based on a value such as parentID=2 ?
Check out About Query of Queries