Let say, there is object Foo and it has properties Bar.
The properties Bar are unique for an object Foo (each object has its very own properties).
what would be the most efficient way to define such relationship? define foreign key in Foo's model referring to Bar's model? or define one-to-one relation from Bar to Foo (or visa verse)?
django manual says:
A one-to-one relationship. Conceptually, this is similar to a
ForeignKey with unique=True, but the “reverse” side of the relation
will directly return a single object.
this is confusing statement. which relationship to choose for which job? what about efficiency (# of queries)?
thank you.
If you have only one Bar object per Foo then use OneToOne relation. If it can be more than one Bar for single Foo then use ForeignKey.
As for "reverse" statement:
# access to Bar property of Foo in OneToOne relation
foo.bar
# access to first Bar property of Foo in ForeignKeyRelation
foo.bar_set.all().first()
In both cases it will be one SQL query, but OneToOne version looks better :-)
Related
I have:
Foo <=> FooGroup <=> Bar
relation, where <=> stands for ManyToManyField.
How do I retrieve all the Foos for a specific Bar instance?
You can .filter(…) [Django-doc] with:
Foo.objects.filter(foogroup__bar=mybar)
with mybar the Bar object for which you want to retrieve the Foos. It is possible that Foo is linked to the same Bar through multiple FooGroups, then it will occur multiple times in the queryset as well. You can use .distinct() [Django-doc] to prevent this:
Foo.objects.filter(foogroup__bar=mybar).distinct()
Suppose I have two models -
class A(models.Model):
a_id=models.CharField(max_length=255,primary_key=True)
a_name=models.CharField(max_length=255)
class B(models.Model):
a=models.ForeignKey(A)
b_name=models.CharField(max_length=255)
I want to filter B objects which belong to a particular a_id. I can either do this -
B.objects.filter(a=a_id)
or
B.objects.filter(a__a_id=a_id)
Is there any difference between the two, in terms of efficiency, speed or functionality?
B.objects.filter(a=a_id) is much more efficient because it simply filters the values of B.a and avoids joining table A altogether, while B.objects.filter(a__a_id=a_id) requires joining table A by a_id and then filtering a_id with a.
For example:
class Contact(models.Model):
contacts = models.ManyToManyField('self', through='ContactRelationship', symmetrical=False)
What does the symmetrical=False parameter do?
When should it be left as True, and when should it be set as False?
How does this settings affect the database (does it create extra columns etc)?
Let's say you have two instances of Contact, John and Judy. You may decide to make John a contact of Judy. Should this action also make Judy a contact of John? If so, symmetrical=True. If not, symmetrical=False
Here is what is says in the documentation:
Only used in the definition of ManyToManyFields on self. Consider the following model:
from django.db import models
class Person(models.Model):
friends = models.ManyToManyField("self")
When Django processes this model, it identifies that it has a ManyToManyField on itself, and as a result, it doesn’t add a person_set attribute to the Person class. Instead, the ManyToManyField is assumed to be symmetrical – that is, if I am your friend, then you are my friend.
By default, the value of symmetrical is True for Many to Many Field which is a bi-directional relationship.
Using a through table (symmetrical=False):
But you can also imagine a situation where you don't need this type of relationship so you can add symmetrical=False. And, this can be achieved by using a through table because by default symmetrical is False if you use a through table:
Recursive relationships using an intermediary model are always defined as non-symmetrical – that is, with symmetrical=False – therefore, there is the concept of a “source” and a “target”. In that case 'field1' will be treated as the “source” of the relationship and 'field2' as the “target”.
So you can imagine a situation where you do need the direction i.e. let's say there is a Node model and it has a relationship with itself using a through table. If we didn't have the requirement of direction here we could go with the example shown earlier. But now we also need a direction from one node to another where one being source and another one being target and due to nature of this relationship it cannot be symmetrical.
I am designing a contact relationship application that needs to store contacts in groups. Basically I have 7 "group types" (simplified it to 3 for my image), each group type shares the same fields so I thought that it would make sense to use an abstract "group", and let all group types inherit the methods from this abstract group.
So this is basically the idea:
However, this approach results in a couple of unexpected difficulties. For example:
I am not able to use a foreignkey of an abstract class, so if I would want to model a relationship between a group and a contact, I have to use the following approach:
limit = (models.Q(app_label='groups', model="Group type A") |
models.Q(app_label='groups', model="Group type B") |
models.Q(app_label='groups', model="Group type C")
)
group_type = models.ForeignKey(ContentType, limit_choices_to=limit)
group_id = models.PositiveIntegerField()
group = GenericForeignKey('group_type', 'group_id')
This seems quite hacky, and with this approach I am forced to do some hard coding as well. I am not able to call all groups with a simple query, maybe a new group will be added in the future.
Is there a better approach to model a relationship like this? Am I using the abstract class completely wrong?
Edit: some extra explanation in response to the questions.
A user is connected to a group with another object called "WorkRelation", because there is some extra data that is relevant when assigning a user to a group (for example his function).
I initially went for an abstract class because I thought that this would give me the flexibility to get all Group types be just calling Group.objects.all(). If I would use a base model, the groups aren't connected and I will also have to hard-code all group names.
Since your child models do not have additional fields, you can make them proxy models of the base group model. Proxy models do not create new database tables, they just allow having different programmatic interfaces over the same table.
You could then define your ForeignKey to the base group model:
group = ForeignKey(BaseGroup)
Use django-polymodels or a similar app to have the groups casted to the right type when queried.
More on model inheritance in the doc.
Why don't use solid base model instead of abstract model? Then you just put contacts as either ForeignKey or ManyToMany to the base model.
The Django docs recommend copying a model instance thus:
original.pk = None
original.save()
But if you "use inheritance" -- apparently meaning if the model's class is a subclass of a subclass of models.Model -- you need to do it slightly differently.
Specifically, the doc says:
Due to how inheritance works, you have to set both pk and id to None:
and gives an example analogous to this:
original.pk = None
original.id = None
original.save()
This seems kludgey. In any case, I'd like to understand what's going on. Why does using inheritance require you to set the id field to None also? Don't all Django models inherit from models.Model in any case?
(NOTE: I'm omitting the bit from the doc about copying m2m fields, which incidentally seems even more kludgey.)
It's because MTI (Multiple Table Inheritance), the type you're talking about here, stores the object across multiple tables. Take this example:
class Animal(models.Model):
...
class Dog(Animal):
...
When you create a Dog, all the fields on Animal are saved into the table for Animal, and just the fields directly on Dog are saved to the table for Dog. When you lookup the Dog later, Django queries both tables and stitches them together.
Both tables, however need primary keys, and Django uses AutoFields for that, which are simply positive integer fields. So Dog has an id and Animal has an id. The pk is filled with the id for the Animal part because this is the main piece, and Dog's id doesn't matter. However, if you're going to make a copy, you need to copy both pieces. Otherwise, the Animal part will of the copy will not get it's own Dog part of the copy.