I have 3 models
class Person(models.Model):
name = models.CharField(max_length=128)
class Company(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField (Person, through = 'Membership', related_name = 'companies')
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
is_admin = models.BooleanField()
I can then call person.companies.all() to get the list of companies associated with person.
How do I create a manager to have the list of companies associated with person, but whose person is admin (is_admin = True)?
You can create a manager like the following:
managers.py:
from django.db import models
class AdminCompaniesManager(models.Manager):
def get_queryset(self):
return super().get_queryset().companies.filter(membership__is_admin=True)
and then in your Person model (please remind the objects manager):
class Person(models.Model):
name = models.CharField(max_length=128)
objects = models.Manager()
administered_companies = AdminCompaniesManager()
Now you can easily call the following (e.g. in your views):
my_person.administered_companies.all()
PS: a very efficient option (e.g. if you are in a view and you need the list of company ids by a given person) is to query the membership model directly, so you can optimize the query for data retrieval from DB avoiding the joins:
Membership.objects.filter(is_admin=True, person=person).values_list('company_id')
You can filter with:
person.companies.filter(membership__is_admin=True)
This will filter the junction table Membership, such that it will only retrieve Companys for which the Membership has is_admin set to True.
Another option is to retrieve this with:
Company.objects.filter(membership__is_admin=True, members=person)
You can attach this to the Person model with:
class Person(models.Model):
name = models.CharField(max_length=128)
#property
def admin_companies(self):
return self.companies.filter(membership__is_admin=True)
Related
class Patient(models.Model):
user = models.OneToOneField(User, related_name='patient', on_delete=models.CASCADE)
id_type = models.CharField(max_length=300)
id_number = models.CharField(max_length=300)
creation_date = models.DateField(default=datetime.date.today)
class Allergie(models.Model):
name = models.CharField(max_length=300, default="X")
class PatientAllergies(models.Model):
patient = models.ForeignKey(Patient, related_name="patient_allergies", on_delete=models.CASCADE)
allergie = models.ForeignKey(Allergie, on_delete=models.CASCADE, null=True)
professional_contract = models.ForeignKey(ProfessionalContract, null=True ,on_delete=models.CASCADE)
Is it possible to retrieve a patient objecto with a property that is a list of all his allergies, including name and id with these models?
you have the PatientAllergies as a chain,
so
patientAllergies = PatientAllergies.objects.get(patient.id_number='0000')
patientAllergies.allergie #you get the single allergie model connect with it, take care it is a foreignKey so it is singolar and not many
patientAlleriges.patient.user #will give you access to all the data of the user
You can achieve this with prefetch_related and Prefetch like so:
Patient.objects.prefetch_related(
Prefetch('patient_allergies__allergie', to_attr='allergies')
)
EDIT: Just learned that to_attr will not work on multiple levels of prefetch. Another approach I can think of is use a model property for Patient that returns its related allergies like this:
class Patient(models.Model):
#property
def allergies(self):
return Allergie.objects.filter(patientallergies_set__patient=self)
Then in your serializer, the allergies field can use the Allergies serializer
The requirement is "I want to insert person with the person groups selection and also at the time of Creating person group I can choose persons for that particular group".
I've added two models in my models.py and manage many to many relationship between.
models.py
from django.db import models
class PersonGroup(models.Model):
id = models.AutoField(primary_key=True)
groupName = models.CharField(max_length=30)
detail = models.CharField(max_length=200)
class Person(models.Model):
id = models.AutoField(primary_key=True)
personId = models.CharField(max_length=20)
personName = models.CharField(max_length=20)
state = models.IntegerField()
personGroup = models.ManyToManyField(PersonGroup, related_name="person_list", blank=True)
serializers.py
class PersonSerializer(serializers.ModelSerializer):
personGroup = serializers.PrimaryKeyRelatedField(queryset=PersonGroup.objects.all(), many=True)
class Meta:
model = Person
fields = '__all__'
class PersonGroupSerializer(serializers.ModelSerializer):
person_list = PersonSerializer(many=True, read_only=True)
class Meta:
model = PersonGroup
fields = '__all__'
The above code help me to create person with personGroup selection
But, I also want to add persons selection at the time of create personGroup. Currently at the time of creating personGroup I'm not allowed to enter persons.
Please let me know if there any solution by which I can also select available persons at the time of person group creation.
Your person_list field in the PersonGroupSerializer is on read only, so you can't modify it using the API.
person_list = serializers.PrimaryKeyRelatedField(queryset=Person.objects.all(), many=True)
Try removing this arg.
You might also want to switch to a ForeignKey field instead of slugged.
Hello guys I have one query in my Django project.
First of all, You can see that I have two Django models named BookSeller and Book
Bookseller model
class BookSeller(models.Model):
user_name = models.CharField(max_length=200)
user_email = models.CharField(max_length=200)
user_password = models.CharField(max_length=200)
user_phone = models.CharField(max_length=100)
user_photo = models.ImageField(upload_to='book/seller_photos/%Y/%m/%d/', blank=True)
user_address = models.CharField(max_length=300)
user_state = models.CharField(max_length=100)
user_city = models.CharField(max_length=100)
def __str__(self):
return self.user_name
Book Model
class Book(models.Model):
book_owner = models.ForeignKey(BookSeller, related_name='book_seller', on_delete=models.CASCADE)
book_category = models.CharField(max_length=200)
book_title = models.CharField(max_length=200)
book_price = models.IntegerField()
book_edition = models.CharField(max_length=200)
book_author = models.CharField(max_length=200)
book_old = models.IntegerField()
book_page = models.IntegerField()
book_description = models.TextField(max_length=200)
book_image_1 = models.ImageField(upload_to='book/book_photos/%Y/%m/%d', blank=True)
book_image_2 = models.ImageField(upload_to='book/book_photos/%Y/%m/%d', blank=True)
book_image_3 = models.ImageField(upload_to='book/book_photos/%Y/%m/%d', blank=True)
book_image_4 = models.ImageField(upload_to='book/book_photos/%Y/%m/%d', blank=True)
def __str__(self):
return self.book_title
Want to DO: In my project I want to find books by that book seller's city.
For example, if I write city name 'Silicon Valley' in my search field then it should show me all "Books" that's Sellers(BookSeller) belonging to Silicon Valley.
Query: So my query is how can I do that Django Query set, because I can't find out any query which can do this task.
If you guys have any other solution then please suggest me!!!
For finding the books by some book seller's city you can simly filter the Book instances like so:
Book.objects.filter(book_owner__user_city="Silicon Valley")
One other problem I noticed is that I think you misunderstand related_name attribute in ForeignKey.
The related_name attribute specifies the name of the reverse relation from the BookSeller model back to Book model.
If you don't specify a related_name, Django automatically creates one using the name of your model with the suffix _set.
For instance more appropriate related name in your FK would be books, and without defining it would default to book_set.
book_owner = models.ForeignKey(BookSeller, related_name='books', on_delete=models.CASCADE)
Here is an example, lets assume you have 1 instance of BookSeller and 2 isntances of Book with FK to that instance of BookSeller.
my_book_seller = BookSeller(...)
my_book_1 = Book(book_owner=my_book_seller, ...)
my_book_2 = Book(book_owner=my_book_seller, ...)
Now in your case doing the my_book_seller.book_seller.all() (since you defined the related_name to be book_seller) would return you the two Book instances belonging to my_book_seller. This doesn't make much sense.
On the other hand having the related_name='books' you would get the same books by doing my_book_seller.books.all().
You can find more info in docs.
You can do that like this
Book.objects.filter(book_owner__user_city="Silicon Valley")
and you learn more about various kinds of joining at
this link
You can get the desired results doing something like
books_by_seller_city = Book.objects.filter(book_owner__user_city='Silicon Valley')
Note the use of __ which tells the ORM to look at the referenced model attribute.
You can do with q look ups also, in that case you can add more fields in your query.
queryset = Book.objects.filter(Q(book_owner__user_city__icontains=query)|
.................)
I have a model in a Django application that is being referenced by multiple other models as a ForeignKey.
What I am looking for is for a way to create a single queryset for all objects of this class that are being referenced as ForeignKey by the rest of the classes based on some criteria.
I am not even sure if this is possible, but I thought about asking anyway.
class Person(models.Model):
pass
class Book(models.Model):
year_published = models.PositiveIntegerField()
author = models.ForeignKey(Person)
class MusicAlbum(models.Model):
year_published = models.PositiveIntegerField()
producer = models.ForeignKey(Person)
recent_books = Book.objects.filter(year_published__gte=2018)
recent_music_albums = MusicAlbum.objects.filter(year_published__gte=2018)
# How can I create a **single** queryset of the Person objects that are being referenced as `author` in `recent_books` and as `producer` in `recent_music_albums`?
Thanks for your time.
I don't have Django in front of me at the moment, but what about something like:
class Person(models.Model):
pass
class Book(models.Model):
year_published = models.PositiveIntegerField()
author = models.ForeignKey(Person, related_name='books')
class MusicAlbum(models.Model):
year_published = models.PositiveIntegerField()
producer = models.ForeignKey(Person, related_name='albums')
Person.objects.filter(books__year_published__gte=2018, albums__year_published__gte=2018)
Or, if you have to do those first two queries anyway,
Person.objects.filter(books__in=recent_books, albums__in=recent_music_albums)
You will have on Person model instances a RelatedManager for Books and MusicAlbums. Probably they will still have the default names book_set and musicalbum_set since you didn't override them.
You can use these to find the books/music albums associated with one person instance:
persons_books = person.book_set.all()
persons_musicalbums = person.musicalbum_set.all()
And similarly you can generate the relevant queryset from the model manager:
qs = Person.objects.exclude(book=None).exclude(musicalbum=None)
Same can be achieved by this :
person = Person.objects.latest('book__year_published', 'musicalbum__year_published')
or
personList = Person.objects.all().order_by('-book__year_published', '-musicalbum__year_published')
I am currently having trouble with filtering data.
Model
class Member(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
team_id = models.UUIDField(null=True)
username = models.CharField('', max_length=30)
is_active = models.BooleanField(default=False)
#property
def organization_id(self):
"""This is to get the organization Id
"""
team = Team.objects.get(pk=self.team_id)
return team.organization_id
and now I am planning to filter all the members with the organation_id = 1.
This is what I need:
memberList = Member.objects.filter(organization_id='1')
So I got this error:
Cannot resolve keyword 'organization_id' into field. Choices are: id, is_active, team_id, username
How can I filter the members using organization_id?
You don't have any field named organization_id in you model Member, that's why the error.
Intead you might want this :
result_list = []
memberList = Member.objects.all()
for item in memberList :
if item.organization_id() == '1' :
result_list.append(item)
print result_list
The resultant list result_list will contain all the required objects of model Member.
Thanks.
According to what I understood from your questions, I assumeed that you have Two Model class.
Lets make example
class Organization(models.Model):
name = models.CharField(max_length=30)
class Member(models.Model):
username = models.CharField(blank=True, max_length=30)
team = models.ForeignKey(Organization)
You use UUIDField as Primary Key. I omitted it. Django make primary key field automatically. I am curious what was your purpose to use UUID Field in the first place.
Anyway, if you create Organization first time. PK number will be 1.
Lets say you are testing in python shell
python manage.py shell
>> import your models
>> Organization.objects.create(name="test1")
then you can connect this Organization with Foreign Key relationship.
>> organization = Organization.objects.get(name="test1")
>> Member.objects.create(username="bob", team=organization)
Next time if you want to get members who in test1 organization.
>> organization = Organization.objects.get(name="test1")
>> Member.objects.filter(team=organization)
or just put PK number of organization 'test1'. Let's say it's 1
>> Member.objects.filter(team=1)
If fixed that you only want to get members who have organization '1', you can add custom manager in model.
class OrganizationManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(team=1)
class Organization(models.Model):
name = models.CharField(max_length=30)
class Member(models.Model):
username = models.CharField(blank=True, max_length=30)
team = models.ForeignKey(Organization)
objects = models.Manager()
organization = OrganizationManager()
you can get members like below
>> Member.organization.all()
it will return members who are in organization pk 1.
memberList = Member.objects.all().annotate(org_id=F('calculate organization id over other model fields')).filter(org_id='1')
in my case this helps, there F is
from django.db.models import F