Django Rest Framework: Handle Many-to-Many relationship - python

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.

Related

How to use model's field's distinct values as select field's choices

My model looks like this.
class Student(models.Model):
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
roll_no = models.CharField(max_length=32)
course = models.CharField(max_length=120)
Now I want to make a filter form using django_filters and want to use distinct values of course field as choices of select input but it requires each value to be associated with unique id and this field doesn't have any unique id.
I tried this:
class StudentFilter(django_filters.FilterSet):
course = django_filters.ModelChoiceFilter(queryset=Student.objects.values("course",flat = True).distinct(),empty_label=('Course'))
class Meta:
model = Student
fields = []
but it didn't work.
Note I do not want to make separate model for course.
The AllValuesFilter does exactly what you are asking for I believe
class StudentFilter(django_filters.FilterSet):
course = django_filters.AllValuesFilter(field_name="course")
class Meta:
model = Student
fields = []

Django - manager on ManyToMany relationship

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)

Foreign keys and serializers in django rest

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

How do I join two tables in Django ORM?

I am a beginner in Django and I know this question has alredy been asked, but I've tried every possible solution from previous answers and it still doesn't work. I can't figure out what I'm doing wrong.
The thing is my view currently returns all the fields of the Grade table, but I need it to return all of those fields plus the "name" field which is in the Student table, by joining the two tables.
I read that Django should do it automatically as long as I use ForeignKey, which I did, but it actually doesn't work.
What am I doing wrong? I'm sorry if it's a noob question and if the solution is really obvious, I'm still trying to learn how Django works.
app/models.py
class Student(models.Model):
id = models.IntegerField(primary_key=True, default=0)
name = models.CharField(max_length=50)
class Grade(models.Model):
subject = models.CharField(max_length=50)
grade = models.IntegerField(default=0)
student = models.ForeignKey(Student, on_delete=models.CASCADE)
app/serializers.py
class StudentSerializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = ('id', 'name')
class GradeSerializer(serializers.ModelSerializer):
class Meta:
model = Grade
fields = ('subject', 'grade', 'student')
app/views.py
class StudentView(viewsets.ModelViewSet):
serializer_class = StudentSerializer
queryset = Student.objects.all()
class GradeView(viewsets.ModelViewSet):
serializer_class = GradeSerializer
queryset = Grade.objects.all().select_related("student")
filterset_fields = ('student')
For the student you can use the `StudentsSerializer, like:
class GradeSerializer(serializers.ModelSerializer):
student = StudentSerializer()
class Meta:
model = Grade
fields = ('subject', 'grade', 'student')

How to select same object twice in Django ManyToMany Field

I have two models
class Food(models.Model):
name = models.CharField(max_length=200 ,null=False)
class Profile(models.Model):
food_selected_today = models.ManyToManyField(Food,related_name = 'inventory')
Now in profile model I want to have one food with same id for example Apple more than one time in food_selected_today. If I now add same food twice it only shows one Item. How can I add one food many times here.
Any kind of help would be really appreciated
Generally this is not possible natively with the built in relationship fields, but you can use your own through-model to give you the opportunity to have a count attribute for each relation:
class Food(models.Model):
name = models.CharField(max_length=200, null=False)
class Profile(models.Model):
food_selected_today = models.ManyToManyField(Food,
related_name='inventory',
through='ProfileFood')
class ProfileFood(models.Model):
food = models.ForeignKey(Food)
profile = models.ForeignKey(Profile)
count = models.IntegerField()

Categories

Resources