Django - get linked models in many to many - django

I have two different models:
A group model
class Group(models.Model):
(...)
users=models.ManyToManyField(users.User, related_name='trainings')
And a very standard user model.
I'm trying to write a function where it returns all of the linked groups for a given User object.
What would solve my problem is something like this:
def get_groups(user):
connected_groups = Group.objects.filter(user in users)
But that throws an error. It the thing that I am trying possible? Or should I instead create a 'linked_groups' variable within the User model?

Check the documentation here: https://docs.djangoproject.com/en/1.11/topics/db/queries/#many-to-many-relationships
Both ends of a many-to-many relationship get automatic API access to the other end. The API works just as a “backward” one-to-many relationship, above.
The only difference is in the attribute naming: The model that defines the ManyToManyField uses the attribute name of that field itself, whereas the “reverse” model uses the lowercased model name of the original model, plus '_set' (just like reverse one-to-many relationships).
For any User called u in your application, u.group_set.all() will be a queryset of all Groups with a many-to-many relationship to that user. Since you have defined a related_name you can use the more readable syntax u.trainings.all().

Related

is this a Django bug?

I created a project and within the project an app call myusers. I then created a model with the class name AllUsers. I then populated the model with data from faker.
When I go to 127.0.0.1/admin under authorization I have groups and users. Under myusers I have ‘All userss’ which is a link to http://127.0.0.1:8000/admin/myusers/allusers/
so, I’m just wondering if this is a minor bug. Shouldn’t it say ‘AllUsers’ and not ‘All userss’? Or did I corrupt something along the way?
No, a model normally has a singular name, so AllUser, not AllUsers.
Django will, based on the name add a suffix …s for the plural. Indeed, for a model you can check the verbose name with:
>>> from django.contrib.auth.models import User
>>> User.Meta.verbose_name_plural
'users'
For your model you can specify the singluar and plural name yourself with:
class AllUsers(models.Model):
# …
class Meta:
verbose_name = 'all user'
verbose_name_plural = 'all users'
But nevertheless, it is better to give the class a singular name. Especially since other parts, like the default for related_name=… [Django-doc] is modelname_set, so for a ForeignKey of your AllUser model, that would look like allusers_set, which does not look very pleasant.
You should not create a model that represents a set of entities. A model should represent a single entity. Since a model should only represent a single entity, Django adds an "s" to the end in the admin to pluralize it (i.e, a model named "Car" will be "Cars" in the admin).
Of course you can change the verbose_plural_name (https://docs.djangoproject.com/en/3.1/ref/models/options/#verbose-name-plural), but the best way forward is to not continue using this technique to represent all users at all.
To represent all users you should be using a QuerySet.

Get all related objects of an object in Django?

Let us say I have a model which contains related (foreign key) fields. Likewise, those Foreign Key fields may refer to models which may or may not contain related fields. Note that relational fields in Django may be one-to-one, many-to-one, or many-to-many.
Now, given an instance of a model, I want to recursively and dynamically get all instances of the models related to it, either directly or indirectly down the line. Conceptually, i want to perform a traversal of the related objects and return them.
Example:
class Model1{
rfield1 = models.ForeignKey("Model2")
rfield2 = models.ManyToManyField("Model3")
normalfield1 = models.Charfield(max_length=50)
}
class Model2{
sfield = models.ForeignKey("Model3")
normalfield = models.CharField(max_length=50)
}
class Model3{
normalfield = models.CharField(max_length=50)
}
Let's say, I have an instance of model Model1 model1, and I want to get objects directly related to it i.e. all Model2 and Model3 objects, and also those which are indirectly related i.e. all Model3 objects related to the Model2 objects retrieved previously. I also want to consider the case of a One-to-One field where the related field is defined on the OTHER MODEL.
Also, note that it might not be the case that I know the model of an instance I'm currently working on. Let's say in the previous example, I may not now that model1 is an instance of Model1 model. So I want to perform all these dynamically.
In order to this, I think I need a way to get all related fields of an object.
How to get all the related fields of an object?
And how should I use them to get the actual related objects?
Or is there a way to better to do this? Thank you very much!
UPDATE:
I already know how to perform 1, and 2 basically follows directly from 1. :) Update later.
If you have model1 getting all it's many to many field names (etc) is easy since this is well know and these are all stored in the meta's 'local_many_to_many' list:
[field.name for field in model1._meta.local_many_to_many]
The foreign keys are a bit more tricky since they are stored with all other fields in the meta's 'local_fields' list. Hence we need to make sure that it has a relation of sorts. This can be done as follows:
[field.name for field in model1._meta.local_fields if field.rel]
This method has requires no knowledge of your models. Also further interrogation can be done on the field object if the name is not enough.

Django Two Way relationship

I am building a blog site and have models in respect of Category and Posts. Posts have a Many to Many relationship for Category.
class Post(models.Model):
categories = models.ManyToManyField(Category)
Everything is working fine aside from the fact that in the Category list in the template I only want to load categories that actually have posts.
If a category is empty I don't want to display it, I have tried to define a relationship in Category to Post to allow me to use something like {{ if category.posts }}. At the moment using another Many to Many field in Category is presently giving me an extra field in admin which I don't really want or feel that's needed.
How is best to navigate this relationship, or create one that's suitable?
Cheers
Kev
Django automatically creates a field on the related model of any ForeignKey or ManyToMany relationship. You can control the name of the field on the related model via the related_name option like that:
class Post(models.Model):
categories = models.ManyToManyField(Category,related_name='posts')
This way, your approach works without any additional fields. Btw, if you leave out the related_name argument, Django will create by default one with [field_name]_set.
You can use reverse relations on ManyToMany fields. In the reverse filter, you must use the related model name (if you did not use related_name attribute). So in your question you can use model name as the reverse name like:
{% if category.post %}
You can also use this in your filtering functions in views:
Category.objects.filter(post__isnull=False)
Reverse relation name must be lowercase.
Check the documentation here

Do a query through a foreignkey in Django

How do I travel through multiple foreign keys in Django? I've tried everything I can think of from the django docs, but I'm obviously missed something (extreme newbie). I have models for scientists, experiments, and theories.
If I want to look at a particular Theory (let's call it 'relativity') and get a list of all of the emails of scientists working on it (kept in the normal django user model), how do I do this?
class Experiment(models.Model)
experimenter = models.ForeignKey(Scientist)
theory = models.ForeignKey(Theory)
class Theory(models.Model)
name = models.CharField(max_length=100)
class Scientist(models.Model)
user = models.ForeignKey(User, unique=True)
institution = models.CharField(max_length=20, null=True, blank=True)
These are simplified versions of my models that I rewrote, so there are probably some errors in it, but the relationships are correct.
I've tried every kind of combinations of select_related(), get(), filter() but can't figure it out. Thanks in advance for your help!
User.objects.filter(scientist__experiment__theory__name=u'relativity')
Take a look at the Django documentation section about Lookups that span relationships. The net takeaway is:
To span a relationship, just use the field name of related fields across models, separated by double underscores, until you get to the field you want.
Ignacio's answer shows an example of using the double underscores on field names to span a relationship.
The other relevant portion of Django's documentation would be the Related objects section. Relationships in Django are asymmetrical in the way they are accessed. Forward/normal relationships are accessed as attributes of the models. Backward relationships are accessed:
Django also creates API accessors for the "other" side of the relationship -- the link from the related model to the model that defines the relationship. For example, a Blog object b has access to a list of all related Entry objects via the entry_set attribute: b.entry_set.all().

Django model with 2 foreign keys from the same table

I wanted a Django model with 2 foreign keys from the same table. It's an event table which has 2 columns for employees: the 'actor' and the 'receiver'. But I get this error:
Error: One or more models did not validate: tasks.task: Intermediary
model TaskEvent has more than one foreign key to Employee, which is
ambiguous and is not permitted.
Is there a better way to model this?
I think I'm going to add a TaskEvent_to_Employee table. There will be two records in it, one for each of the two employees related to each TaskEvent. Does anyone know an easier workaround?
I haven't done this yet, but I used inspectdb to generate the models.py file from an existing DB that does exactly that - this is what inspectdb threw back, so it should work:
creator = models.ForeignKey(Users, null=True, related_name='creator')
assignee = models.ForeignKey(Users, null=True, related_name='assignee')
Hope that works for you - if it doesn't I am going to have a problem too.
I think what you're looking for is the related_name property on ForeignKeyFields. This will allow you to reference the same table, but give django special names for the relationship.
More Info:
https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name
https://docs.djangoproject.com/en/dev/topics/db/queries/#backwards-related-objects
https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_one/
From the error message, it sounds like you're trying to put two foreign keys to the same object on an intermediary table used via the through argument to ManyToManyField, the documentation for which states:
When you set up the intermediary
model, you explicitly specify foreign
keys to the models that are involved
in the ManyToMany relation. This
explicit declaration defines how the
two models are related.
There are a few restrictions on the
intermediate model:
Your intermediate model must contain one - and only one - foreign key to
the target model (this would be Person
in our example). If you have more than
one foreign key, a validation error
will be raised.
Your intermediate model must contain one - and only one - foreign key to
the source model (this would be Group
in our example). If you have more than
one foreign key, a validation error
will be raised.
Using related_name was my solution:
class Sample(models.model):
...
class Mymodel(models.model):
example1 = models.ForeignKey(Sample, related_name='sample1')
example2 = models.ForeignKey(Sample, related_name='sample2')
The fact that two columns are part of one table implies that the two fields are related, therefor to reference them individually is not ideal. The ForeignKey of your model should be the primary key of the table you are referencing:
event = models.ForeignKey('event')
You would then reference the columns as such:
foo.event.actor
foo.event.receiver
If you wish you could also change the way your class/model references the foreign attributes with properties. In your class you would do the following:
#property
def actor(self):
return self.event.actor
#property
def receiver(self):
return self.event.receiver
This would allow you to then call foo.actor and foo.receiver but I believe the longer, foo.event.actor would be more pythonic