Structure of models in Django - django-models

I've got for things that I want to model: vaccines, countries, diseases and medicines.
A disease is in N countries
A medicine cures N diseases
A vaccine prevents N diseases
My primary search method will be by country, listing vaccines and medicines through the disease connection.
I thought I'd do this by this model:
class Country(models.Model):
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class Disease(models.Model):
name = models.CharField(max_length=100)
country = models.ManyToManyField(Country)
def __unicode__(self):
return self.name
class Vaccine(models.Model):
name = models.CharField(max_length=100)
diseases = models.ManyToManyField(Disease, blank=True)
def __unicode__(self):
return self.name
class Medicine(models.Model):
name = models.CharField(max_length=100, blank=True)
diseases = models.ManyToManyField(Disease, blank=True)
def __unicode__(self):
return self.name
And I search like this:
def vacc_for_country(request, country_id):
diseases = Disease.objects.filter(countries__pk=country_id)
vaccines = Vaccine.objects.filter(id__in=[d.id for d in [v.diseases for v in Vaccine.objects.all()]])
return serialize(vaccines)
but that doesn't work, I get: AttributeError at /vaccines/seek/countryId/3
'ManyRelatedManager' object has no attribute 'id'.
So how do I go from country_id to a list of vaccines?

I have no clue what you were going for there.
Vaccine.objects.filter(diseases__country__id=country_id)

Related

How to make it by list comprehension

I need to get the child list under the parent list as a group.
class ServiceSerializer(serializers.ModelSerializer):
cleaning_type = serializers.CharField(source='cleaning_type.cleaning_type_name')
class Meta:
model = Service
fields = ('id', 'cleaning_type','service_name')
class ServiceTypeViewSet(ModelViewSet):
serializer_class = ServiceSerializer
http_method_names = ["get"]
queryset = Service.objects.all()
def get_queryset(self):
"""
This view should return a list of all the service types.
"""
servicename_list = Service.objects.all()
return servicename_list
It shows:
[
{
"id": 1,
"cleaning_type": "Lite service",
"service_name": "Floors",
},
{
"id": 2,
"cleaning_type": "Lite service",
"service_name": "Bathrooms",
},
{
"id": 3,
"cleaning_type": "Lite service",
"service_name": "Kitchen",
}
]
I want this to be in the following format:
[
{
id: 1,
cleaning_type: 'Lite service',
service_name: ['Floors', 'bathroom', 'kitchen'],
},
{
id: 2,
cleaning_type: 'Moving cleaning',
service_name: ['Kitchen Including All Appliances And Cabinets'],
},
]
That means all child elements will be under a separate parent list. Not separate by separate.
models.py is here:
Cleaning Type Model:
class CleaningType(models.Model):
cleaning_type_name = models.CharField(
_("Select Cleaning Type"), blank=True, null=True, max_length=255)
price = models.DecimalField(default=0,max_digits=6, decimal_places=2)
def __str__(self):
return self.cleaning_type_name
Service Model:
class Service(models.Model):
cleaning_type = models.ForeignKey(
CleaningType, on_delete=models.CASCADE)
service_name = models.CharField(
_("Service Name"), blank=True, null=True, max_length=255)
#string type added
def __str__(self):
return str(self.service_name)
I want sub categories under parent caterories. Here cleaning_type is the parent category and service is the child category of cleaning_type. i.e : cleaning_type >> service_type
First you need to move the cleaningtype field into the ServiceType model.
And I think it's better to set the related_name from the view of the target model.
class ServiceType(models.Model):
cleaningtype = models.ForeignKey(
CleaningType, related_name='service_types', on_delete=models.CASCADE)
...
class Service(models.Model):
servicetype = models.ForeignKey(
ServiceType, related_name='services', on_delete=models.CASCADE)
service_name = models.CharField(
_("Service Name"), blank=True, null=True, max_length=255)
#string type added
def __str__(self):
return str(self.service_name)
And in CleaningTypeSerializer
class CleaningTypeSerializer(serializers.ModelSerializer):
service_objects = ServiceTypeSerializer(many = True, read_only = True)
service_types = serializers.SerializerMethodField()
class Meta:
Model = CleaningType
fields = ('id', 'cleaning_type', 'service_types',)
def get_service_types(self, obj):
return list(obj.service_types.values_list('service_type').distinct())
Finally in views.py,
class CleaningTypesViewSet(ModelViewSet):
serializer_class = CleaningTypeSerializer
queryset = CleaningType.objects.all()
You can get the list of CleaningType data from this CleaningTypesViewSet.

how to get foreignkey fields in serializer

In serializer, class I am trying to get the category details such as "name" but the following code gives me the foreignkey id
models.py
class Category(MP_Node, Timestamps):
name = models.CharField(_('Name'), max_length=255, db_index=True)
class VideoCategory(Category):
image = models.ImageField(upload_to='video_categories', blank=True, null=True, max_length=255)
class VideoCategoryVideo(BaseModel, Timestamps, SoftDelete):
video = models.ForeignKey(Video, on_delete=models.CASCADE)
category = models.ForeignKey(VideoCategory, on_delete=models.CASCADE, null=True)
serializers.py
class VideoCategoryVideoSerializer(serializers.ModelSerializer):
class Meta:
model = VideoCategoryVideo
fields = ('category', )
class VideosDetailsListSerializer(serializers.ModelSerializer):
category = serializers.SerializerMethodField()
class Meta:
model = Video
fields = ('id', 'create_date', 'category')
def get_category(self, data):
cate = VideoCategoryVideo.objects.filter(video=data.id)
category = VideoCategoryVideoSerializer(cate, many=True)
return category.data
result is:
"category": [
{
"category": 1
}]
but the expected result is
"category": [
{
"name": "cate_name"
}]
You can add a CharField to VideoCategoryVideoSerializer and specify the source of the value like this:
class VideoCategoryVideoSerializer(serializers.ModelSerializer):
name = serializers.CharField(source='category.name', read_only=True)
class Meta:
model = VideoCategoryVideo
fields = ('category', 'name')
This will tell the serializer to get the value for name from the related category.

Filtering the fields listed by the CreateModelMixin based on ForeignKey in Django Rest Framework

Hello, I am starting to learn Django Rest Framework, i have come across a problem, that i couldn't solve, that is described below:
I have defined three models in models.py:
Endpoint Model
class Endpoint(models.Model):
name = models.CharField(max_length=128)
created_by = models.CharField(max_length=128)
created_at = models.DateTimeField(auto_now_add=True, blank=True)
def __str__(self) -> str:
return self.name
MLAlgorithm model:
class MLAlgorithm(models.Model):
name = models.CharField(max_length=128)
created_by = models.CharField(max_length=128)
created_at = models.DateTimeField(auto_now_add=True, blank=True)
parent_endpoint = models.ForeignKey('Endpoint', on_delete=models.CASCADE, related_name="mlalgorithms")
def __str__(self) -> str:
return self.name
ABTest model:
class ABTest(models.Model):
title = models.CharField(max_length=1000)
created_by = models.CharField(max_length=128)
created_at = models.DateTimeField(auto_now_add=True, blank=True)
parent_endpoint = models.ForeignKey('Endpoint', on_delete=models.CASCADE, related_name="abtests")
parent_mlalgorithm_1 = models.ForeignKey('MLAlgorithm', on_delete=models.CASCADE, related_name="parent_mlalgorithm_1")
parent_mlalgorithm_2 = models.ForeignKey('MLAlgorithm', on_delete=models.CASCADE, related_name="parent_mlalgorithm_2")
def __str__(self) -> str:
return self.title
and defined their serializers:
Endpoint Serializer:
class EndpointSerializer(serializers.ModelSerializer):
class Meta:
model = Endpoint
read_only_fields = ("id", "name", "created_by", "created_at")
fields = read_only_fields
MLAlgorithm Serializer:
class MLAlgorithmSerializer(serializers.ModelSerializer):
class Meta:
model = MLAlgorithm
read_only_fields = (
"id", "name", "created_by", "created_at", "parent_endpoint")
fields = read_only_fields
ABTest Serializer:
class ABTestSerializer(serializers.ModelSerializer):
class Meta:
model = ABTest
read_only_fields = ("id", "created_at")
fields = (
"id", "title", "created_by", "created_at", "parent_endpoint", "parent_mlalgorithm_1", "parent_mlalgorithm_2")
Then i created a viewset for the ABTest:
class ABTestViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin, mixins.RetrieveModelMixin):
serializer_class = ABTestSerializer
queryset = ABTest.objects.all()
My problem is in the ABTestView:
for example, i have created two endpoints, and each endpoint has two algorithms:
endpoint_1:
algorithm_1
algorithm_2
endpoint_2:
algorithm_3
algorithm_4
but when i select a specific endpoint in the view, i want only the specific algorithms to be shown not all the algorithms available in the database
enter image description here
i don't know how to force algorithm filtering in the view, should i filter the algorithms by their endpoints in the view or before serialization, unfortunately i am struggling to implement it.
Thank you in advance.

How to count deep relationship fields with Django?

How could I count the relationship of the models below?
class Client(models.Model):
name = models.CharField(max_length=150)
class Pet(models.Model):
client = models.ForeignKey(Client, related_name='pet')
name = models.CharField(max_length=150)
class Photo(models.Model):
pet = models.ForeignKey(Pet, related_name='photo')
photo = models.ImageField(storage=DIR)
I would like to return the total pet and total photos taken of all pets dr to a single customer client, with the following answer:
[
{
"name": "john",
"totalPet": 3, // imagine 10 photos were taken of each pet
"totalPhoto": 30,
},
{
"name": "Mary",
"totalPet": 2, // imagine that 10 photos were taken of one and 5
// of another pet
"totalPhoto": 15,
},
]
My serializer is as follows:
class ClientSerializer(ModelSerializer):
totalPet = serializers.SerializerMethodField()
def get_totalPet(self, obj):
return obj.pet.count()
class Meta:
model = Client
fields = ('name', 'totalPet')
As can be observed, I can total the amount of pets for each customer, but I can't find a way to total the photos of all pets of a customer.
What would be the best way to do this photo count?
You can perform a filter on Photo model with your client.pet queryset, using the __in lookup.
At first, I would define a custom QuerySet for our Photo model:
from django.db import models
class PhotoQuerySet(models.QuerySet):
def for_client(self, client):
# Get all related pets to the current client
client_pets = client.pet.all()
# Filter Photos that are linked with these pets
return self.filter(pet__in=client_pets)
And then inside the model:
class Photo(models.Model):
...
objects = PhotoQuerySet.as_manager()
This will allow you to do the following: Photo.objects.for_client(client=...)
After that, you can use this method in the serializer:
class ClientSerializer(ModelSerializer):
total_pets = serializers.SerializerMethodField()
total_photos = serializers.SerializerMethodField()
def get_total_pets(self, obj):
return obj.pet.count()
def get_total_photos(self, obj):
# Calling our newly created method and aggregating count
return Photo.objects.for_client(client=obj).count()
class Meta:
model = Client
fields = ('name', 'total_pets', 'total_photos')

Joining two tables in ORM Django

There are three models Person, Author and Singer.
class Person(models.Model):
name = models.CharField(max_length=256, null=True)
class Meta:
db_table = "Person"
class Author(models.Model):
person = models.ForeignKey(Person)
rating = models.InegerField(null=True)
class Meta:
db_table = "Author"
class Singer(models.Model):
person = models.ForeignKey(Person)
rating = models.IntegerField(null=True)
class Meta:
db_table = "Singer"
I have to perform joining between Author and Singer in ORM
MySQL will be like
select S.* from Singer as S join Author as A on S.person_id=P.person_id;
The simpler solution according to your database model would be
author_objects = Author.objects.filter(person=singer_object.person) # where singer_object
# now do something with the author_objects

Resources