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

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.

Related

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.

Is it mandatory to specify intermediate model to describe 'level' of many-to-many relationship?

Being new to Django and relatively new to python, I am writing a knowledge reporting webpage.
I have 2 models with a defined MtM relationship:
Class Student:
level_of_knowledge = model.ManyToMany(Topic)
...
Class Topic:
...
Intended usage:
Every Student has a level of understanding of every topic (the list of topics is exactly the same for everyone), starting with, say, "Basic". The level of understanding may be increased to "Intermediate" and further to "Advanced".
Question:
Is it necessary to implement an intermediate "through" model with the determined list of levels of undestanding, or can it be done in the level_of_knowledge field in Student model directly?
Personally, I would create an intermediate model in this case, but if you want more ideas of what you could do then something like this would work too:
Class Student:
advanced_knowledge = model.ManyToMany(Topic)
intermediate_knowledge = model.ManyToMany(Topic)
basic_knowledge = model.ManyToMany(Topic)
...
Class Topic:
...
So this is neat because you can easily access knowledge of a certain level by using student.basic_knowledge.all()
But here's the problem:
What if you want a list of all Topic objects related to a Student? Do you combine all three of these queries?
What if you want to add a few more knowledge levels? Maybe later students will have beginner knowledge or expert knowledge. How many other ManyToMany fields will you end up adding?
Using an intermediate model solves both of these problems, and its not hard to use the django through option and filter by levels if you want. Just make properties or methods on Student for the knowledge levels you filter by most often.
Class Student:
level_of_knowledge = model.ManyToMany(Topic, through=MyIntermediteModel)
def advanced_knowledge(self):
return self.level_of_knowledge.filter(...) # filter by intermedite model where level = 'advanced'

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

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

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.