Multi-Table Inheritance in Django. I'm not sure I understand - django

Im not sure I understand the advantage/purpose of multi-table inheritance… but it may be what I'm looking for. Im dealing with Restaurants. My current logic is that I have a Company model which is likely (but not always) a Restaurant. Sometimes a Company can be a "parent" company, in-which case the Company model has a one-to-many with a Branch model. Both the Company and Branch models would have common fields, such as street address, contact info. If the Company has only one "branch" I can assume it's the Restaurant itself and so I don't need to attach a Branch object to the Company. Does this make sense? I know im repeating myself with with the street address [...] but it seems like an elegant way to store the data if I were to read the db directly.
Im not sure if multi-table inheritance is what I need. I just can't wrap my head around it by only looking at https://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance.
edit: also open to taking any suggestions on a better db layout if im doing it wrong.

Model inheritance is useful in general because you do queries like Company.objects.all() to return all companies (including restaurants) and also Restaurant.objects.all() to return only restaurant companies. Just like 'regular' inheritance, it might be helpful to include common fields in a parent (Company) model on all the children models (Restaurant). For example, all Companies might have an address field, but only Restaurants might have a food_type field.
I've documented links to a few snippets that implement a "subclassing queryset" which basically lets you do a query like Company.objects.all() and have it return to you results like [<Company> < Restaurant>, <Company>, <Company>, < Restaurant> ]. Check out the link:
http://jazstudios.blogspot.com/2009/10/django-model-inheritance-with.html
The downside of this multi-table approach is that it introduces an extra join in your query between the Company parent table and the child Restaurant table.
An alternatieve would be to create an abstract model. This creates a separate table for Company and for Restaurant with redundant fileds. With multi-table inheritance, if we wanted to look up the address field on a Restaurant instance, we would be referencing (behind the scenes) the related Company model. With abstract inheritance, there would actually be an address field on the Restaurant table. Also, using the abstract inheritance, I don't think you can do Company.objects.all() and expect that it will return instances that were added as Restaurants, nor can you use the subclassing querysets from the snippits linked above.
Hope this helps,
Joe

Related

Why Many to Many relationship with self can't be symmetrical

I'm trying to make a model with many to many relationship to itself and this relationship will also have a specific table that will store some information about the relationship, but I'm running into some problems.
I tried to make a many to many relationship with diferent models like the Django docs say, and it's worked fine in some other point of my application. But now I tried to do something like this:
Let's say that I want a model that represents an object (called Item) that is made by other items and also is used to make some other items. For instance, an object Door is made by wood and lock, but Door will also be used to make a House. I thought in something like this for my models
class Item(models.Model):
name = models.CharField(max_length=100)
items = models.ManyToManyField("self",through='IsMadeBy')
class IsMadeBy(models.Model):
itemResult = models.ForeignKey('Item', related_name='itemResult')
itemPart = models.ForeignKey('Item', related_name='itemPart')
amountUsed = models.PositiveIntegerField()
I'm getting the error message:
Many-to-many fields with intermediate tables must not be symmetrical.
So, adding the argument
symmetrical=False
to my relationship the error stops.
With that being said, I want to know how this really works under the hood. For intance, what the symmetrical means in this context in a database level? I would appreciate if anyone could give examples maybe using SQL statements, since right now my brain can't see the overall situation and really learn this concept of symmetrical relationship in a many to many relationship with self.
Look at the Django docs:
https://docs.djangoproject.com/en/1.10/ref/models/fields/#django.db.models.ManyToManyField.symmetrical
With symmetric relationship if i'm your friend then you my friend too - in Django terms, you have one relation.
With non-symmetric direct and reverse relations can be different, you have related_set. For example, if i'm you manager, you not my manager at the same time, but manager via employee_set can have many employees.

django: how to make two models share one unique primary key

In my case, I have two models: Equipment and Asset, they both have their own fields but they should share one unique field: asset_number. By sharing, I mean that when creating a equipment, the asset_number user inputted would be check against both Equipment and Asset database. If it already exist in any, then there is going to be prompt telling the user that this is not unique.
For only one model, this is easily done by setting unique = True. However if I would like to do for two models, how should I proceed?
TIA
This doesn't sound like a good idea at all. If Asset and Equipment have different fields, then they should be different classes.
If you subclass to make them share a key, you will end up with a database that doesn't reflect reality, at all.
It would be better to enforce uniqueness in your view than to corrupt your schema.
I think the best solution would be to make a parent class and make both Asset and Equipment inherit from it.
For example, you could make a BaseAsset class with an asset_id unique field. As both classes will share the same table for asset_id, there's no way they will collide.
class BaseAsset(models.Model):
asset_id = models.IntegerField(unique=True)
class Asset(BaseAsset):
.
.
.
class Equipment(BaseAsset):
.
.
.

Can I make a dynamc number of foreign keys to a single (self) django model?

I'm currently creating an equipment management database and need to allow equipment to be associated with other equipment.
Thanks to this stackoverflow question I currently have something akin to the following (vastly simplified):
class Equipment(models.Model):
equipment_title = models.CharField()
relates_to = models.ForeignKey('self')
However, to relate a dynamic number of equipment to other equipment I think I need something like a one-to-many field that doesn't exist natively within Django, e.g. a filter housing may be associated with many filter units, and several filter housings may be associated with a machine tool.
How can I get around this? I'm not sure that it's the right place for a many-to-many field...
A ForeignKey is a one-to-many relationship, defined on the "many" side. Since your relationship is pointing to self anyway, it already does what you want.

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.

What are the advantages of using ForeignKey in Django?

This is an extremely naive question. As you can tell, it comes from someone who doesn't know much about either databases or Django.
What are the advantages of using ForeignKeys in Django?
Maybe an example will help me understand better. I have tables like this already:
City:
id = IntegerField() # e.g. 15
name = CharField() # e.g. 'Rome'
Country:
name = CharField() e.g. 'Italy'
capital = IntegerField() # e.g 15
Should I bother changing capital to ForeignKey(City), and if so, why? Do certain things become quicker, more convenient, or otherwise better?
thanks!
Foreign keys are constraints on your data model that allow you to ensure consistency. Basically, in your example, if you didn't have capital as a ForeignKey to a City it could potentially contain an id of a City that didn't exist! When you use ForeignKey instead, it places a constraint on the database so that you cannot remove things that are currently referenced by other things. So if you tried to delete the City named "Rome" before deleting the Country named "Italy" who has that city as its capital, it wouldn't allow you to.
Using ForeignKey instead would make sure you never had to worry about whether or not the "thing" on the other end of the relationship was still there or not.
Using ForeignKeys enables Django to "know" about the relations. So you can follow the relations without taking care about how they are stored, eg you can do the following without having to care how the relation is stored:
country = Country.objects.get(pk=1)
print country.capital.name
italy = Country.objects.get(capital__name="Rome")
Also for keeping constraints Django will follow the relations when deleting objects that are referenced by a ForeignKey. Django also keeps track of the reverse relationships (without needing to explicitly define them), so you can do something like countries = rome.country_set.all() (which makes not so much sense in this example, since it would make more sense to use a OneToOneField here...
Referential integrity. OTOH it is quite possible to have a database that neither knows nor cares about FKs - in fact I work with a legacy db like this at work.