Modelling a 'web' in a Django database - django

I have a use case where I have a 'web' with the following relationships; what's the best way to model this in Django?
There is a logical top layer (could be modelled as a single 'very top' node if required)
There are logical leaves at the bottom
Nodes can have relationships to nodes in the layer above and/or below but never to siblings
So like that chinese game with a coin dropping through pins, there are multiple routes from top to bottom but a traversal will always work, albeit in some manner determined elsewherre (actually user input in my case).
I have tried using ManyToMany relationships but can't see how to spot the top and bottom of the relationships; do I need to switch to many OneToMany relationships for independent child and parent relationships?

I don't think you can make this kind of graph explicit in the data structure, but you can enfore it with semantic actions in the creation/update of nodes. Let's say you have a model of a Node:
class Node(models.Model):
connections = ManyToManyField(Node)
layer_level = IntegerField(null=False, default=1)
In the constructor and the magic setter __setattr__ you can then check if the connections of the node all have a layer level greater or less than the node itself and raise an exception if they're equal. I admit that it's possible that in Django "interjecting" the setting of fields of a model instance is more complicated than overriding the __setattr__ method, but that's beyond the scope of this answer.
The point is that you can set up a model that your desired structure but with less restrictions and then enforce the restrictions on creation/update, rather than making them implicit in the model structure. The latter would be a better solution, but also one that is likely not possible with relational databases and/or Django's ORM.

Related

What is the most Django-appropriate way to combine multiple database columns into one model field?

I have several times come across a want to have a Django model field that comprises multiple database columns, and am wondering what the most Django way to do it would be.
Three use cases come specifically to mind.
I want to provide a field that wraps another field, keeping record of whether the wrapped field has been set or not. A use case for this particular field would be for dynamic configuration. A new configuration value is introduced, and a view marks itself as dependent upon a configuration value, redirecting if the value isn't set. Storing whether it's been set yet or not allows for easy indefinite caching of the state. This also lets the configuration value itself be not-nullable, and the application can ignore any value it might have when unset.
I want to provide a money field that combines a decimal (or integer) value, and a currency.
I want to provide a file field with a link to some manner of access rule to determine whether the request should include it/a request for it should succeed.
For each of the use cases, there exists a workaround, that in each case seems less elegant.
Define the configuration fields as nullable. This is undesirable for a few reasons: it removes the validity of NULL as a value for the configuration itself, so tristates and other use valid cases for NULL have to become a pair of fields or a different data type, or an edge case; null=True on the fields allows them to be set back to None in modelforms and the admin without writing a custom FormField for them every time; and every nullable column in a database is arguably bad design.
Define the field as a subclass of DecimalField with an argument accepting a string, and use that to contribute another field to the model. (This is what django-money does). Again, this is undesirable: fields are appearing "as if by magic" on the model; and configuring the currency field becomes not obvious.
Define the combined file+rule field instead as an entire model, and one-to-one to it from the model where you want to have the field. This is a solution to all use cases, but again comes with downsides: there's an extra JOIN required for every instance of the field - one can imagine a User with profile_picture, cv, passport, private_key etc.; there's an implicit requirement to .select_related(*fields) on every query that would ever want to access the fields; and the layout of the related model is going to have cold data interleaved with hot data all over the place given that it's reused everywhere.
In addition to solution 3., there's also the option to define a mixin factory that produces the multiple fields with matching names and whatever desired properties and methods. Again this isn't perfect because the user ends up with fields being defined in the model body, but also above that in the inheritance list.
I think the main reason this keeps sending me in circles is because custom Django model fields are always defined in terms of a single base field, because it's done by inheritance.
What is the accepted way to achieve this end?

Stop infinite loop in self-referencing models

I am writing a little utility which allows me to populate data models with a number of records.
I used python faker to set the values for each field based on their field-type.
What I do next, is that I use model._meta.get_fields to extract all the fields, remove all Rel types, and then populate non-relational fields with the correct values. For relational fields (where .re_relation = True) I follow the relation to the related model, then do the same for that model as well until I reach a model where there is no more relations to other models. Then create instances for each model.
Basically a recursive process.
My problem is with self-referencing models which cause an infinite loop. I thought of setting these instances to null but what about instances where null is set to False?
Is there any clean way to handle situations like this? I couldn't find anything on the net or stackoverflow.
ps: the code is pretty long so I didn't post anything. But I can if it's necessary.
Often when there's the possibility of an infinite loop, you can prevent that by setting a counter which if is reached, breaks out of the loop.
In your case, you can explicitly check if the relation references the same model and then, prevent it from following the relation.
Moreover, a model that is referencing itself, should allow for the relationship to be null.

Synchronized Model instances in Django

I'm building a model for a Django project (my first Django project) and noticed
that instances of a Django model are not synchronized.
a_note = Notes.objects.create(message="Hello") # pk=1
same_note = Notes.objects.get(pk=1)
same_note.message = "Good day"
same_note.save()
a_note.message # Still is "Hello"
a_note is same_note # False
Is there a built-in way to make model instances with the same primary key to be
the same object? If yes, (how) does this maintain a globally consistent state of all
model objects, even in the case of bulk updates or changing foreign keys
and thus making items enter/exit related sets?
I can imagine some sort of registry in the model class, which could at least handle simple cases (i.e. it would fail in cases of bulk updates or a change in foreign keys). However, the static registry makes testing more difficult.
I intend to build the (domain) model with high-level functions to do complex
operations which go beyond the simple CRUD
actions of Django's Model class. (Some classes of my model have an instance
of a Django Model subclass, as opposed to being an instance of subclass. This
is by design to prevent direct access to the database which might break consistencies and to separate the business logic from the purely data access related Django Model.) A complex operation might touch and modify several components. As a developer
using the model API, it's impossible to know which components are out of date after
calling a complex operation. Automatically synchronized instances would mitigate this issue. Are there other ways to overcome this?
TL;DR "Is there a built-in way to make model instances with the same primary key to be the same object?" No.
A python object in memory isn't the same thing as a row in your database. So when you create a_note and then fetch same_note from the db, those are two different objects in memory, even though they are the same representation of the underlying row in your database. When you fetch same_note, in fact, you instantiate a new Notes object and initialise it with the values fetched from the database.
Then you change and save same_note, but the a_note object in memory isn't changed. If you did a_note.refresh_from_db() you would see that a_note.message was changed.
Now a_note is same_note will always be False because the location in memory of these two objects will always be different. Two variables are the same (is is True) if they point to the same object in memory.
But a_note == same_note will return True at any time, since Django defines two model instances to be equal if their pk is the same.
Note that if the complexity you're talking about is that in the case of multiple requests one request might change underlying values that are being used by another request, then use F to avoid race conditions.
Within one request, since everything is sequential and single threaded, there's not risk of variables going out of sync: You know the order in which things are done and therefore can always call refresh_from_db() when you know a previous method call might have changed the database value.
Note also: Having two variables holding the same row means you'll have performed two queries to your db, which is the one thing you want to avoid at all cost. So you should think why you have this situation in the first place.

Django, multi-table inheritance is that bad?

This isn't really specific to django.
One can model
Place (with location, name, and other common attributes)
- Restaurant (menu..)
- ConcertHall (hall size..)
in two separate tables and let each one hold all the fields they need. (in django world, this is called abstract inheritance)
in three tables, where one holds the common fields and the other two has their own unique fields. (multi-table inheritance in django)
The authors of book Two scoops of Django 1.8 strongly advise against using multi-table inheritance.
Say you want to query places based on it's location and paginate the results (It doesn't have to be a location, can be any other common attribute we want to filter on)
I can see how I can achieve it using Multi-table inheritance.
select place.id from place LEFT OUTER JOIN "restaurant" on (
restuarant.id=place.id) LEFT OUTER JOIN "concerthall" on (
concerthall.id=place.id) where ... order by distance
Is it feasible to do it with abstract inheritance?
According to Django documentation: Model inheritance:
The only decision you have to make is whether you want the parent models to be models in their own right (with their own database tables), or if the parents are just holders of common information that will only be visible through the child models.
I think both possibilities are just tools, equally good tools and it just depends on your use case for their appropriateness. Surely there are specific things to consider for both approaches, and conceptually sometimes multi-table inheritance may be more difficult to comprehend, but other than that this topic just turns to become opinionated.
If you need a single queryset for both models, then it is logical that you consider multi-table inheritance rather than abstract models, because otherwise you would need to get into combining two querysets into one, most probably by using lists as this relevant answer suggests, but you would definitely lose ORM functionality.
It depends on your usecases, but Django ihave a good Database ORM for Database Normalized table structure.
Keeping the base fields in a model and keeping the specifics on another is the best approach in Database Normalization logic because you may have query on different tables and that is not a desired situation. Django relations and reverse relations offers you what you need at this point.
An Example based on yours considering you are using Multi Table Inheritance:
Place.objects.filter(location=x)
Place.objects.filter(location=x, Q(Q(concerthall__hallsize__gt=y)| Q(restaurant__menu=z)))
Place.objects.filter(location=x, concerthall__id__isnull=True)
First will return you all Restaurants and Concert Halls in x.
Second will return you All places which are Concert Halls with hall sizes greater than y or Restaurants with menu z.
Last one is a super magic query that will return you all places in location x which is not a Concert Hall. That is useful when you have many Models inheriting from Place. You can use <model_name>__id for including/excluding tables according to your needs.
You can built great JOINS including many tables and do stick to Database Normalization rules while doing this. You will keep your related data in one place and avoid possible data integrity problems.

How to display two Qt models using external data in a single tree view

I'm working on a C++/Qt project. I have two business models (one is a hierarchical tree-like structure, i.e. film categories/sub-categories, and the other one is a simple vector, i.e. film titles which can belong only to a subcategory) and I want to display both in a unique tree-view, where leaf nodes can belong to both models and non-leaf nodes belong to the first model. In addition to this view, I also want to display in model specific views, a tree-view for the first model and a list view for the second one.
I've considered 3 approaches:
1) Create one QAbstractItemModel for each business model and another one to represent the mixed model. Thus, each view is associated with only one model.
2) Create only two QAbstractItemModel for each business model and implement a special view that deals with that information.
3) Use a QStandardItem model and implement subclasses of QStandardItem for both my business model elements.
Because I'm working with external data, I don't want to duplicate any information if possible.
What do you think is the best/proper approach to follow? Any implementation advices?
QDataWidgetMapper is your best bet in that one.
Make one model of your data. I would make one tree model, which is option c of your choices, but could be implementing your own tree model.
For the list view, see if you can't set the tree model on it as well, and use setRootIndex to only show the list of items you want to see. I know it works on table and tree views, so I assume it would also work on a list view.