How can I filter manytomany models? - django

I would like to filter my plots objects on the fruit ex.pear. The Inputs are linked via a manytomany to the plots. This is the structure:
This is the data I get out of it:
What i would like to have:
result:
I tried the following:
plots = Plot.objects.filter(fruittype__fruit="Pear")
inputs = Input.objects.filter(plot__in=plots).distinct()
This gives me already a close solution for my problem but not what I want.
Now I only would like to filter out the other plots that still show up with apple.
models inputs:
class Product (models.Model):
type = models.ForeignKey(Type, on_delete=models.CASCADE)
product = models.CharField(max_length=70)
standaard_dosis = models.FloatField()
def __str__(self):
return self.product
class Input (models.Model):
datum = models.DateField()
plot = models.ManyToManyField(Plot)
def __str__(self):
return str(self.datum)
class ProductInputs (models.Model):
input = models.ForeignKey(Inputs, on_delete=models.CASCADE, default="")
product = models.ForeignKey(Product, on_delete=models.CASCADE, default="")
dosis = models.FloatField()
def __str__(self):
string = str(self.product)
return string
models plots:
class Fruit(models.Model):
fruit = models.CharField(max_length=30, primary_key=True)
def __str__(self):
return self.fruit
class Meta:
verbose_name_plural = "fruits"
class Fruittype(models.Model):
fruit = models.ForeignKey(Fruit, on_delete=models.CASCADE)
fruittype = models.CharField(max_length=30, primary_key=True)
def __str__(self):
return self.fruittype
class Meta:
verbose_name_plural = "fruitypes"
class Plot(models.Model):
name = models.CharField(max_length=30)
fruittype = models.ForeignKey(Fruittype, on_delete=models.CASCADE)
def __str__(self):
return str(self.fruittype.fruit) + " | " + self.name
class Meta:
verbose_name_plural = "plots"

Your Plot queryset is not going as deep as it should. I think you should change to something like this (although this is it's a bit of overkill)
plot_ids = Plot.objects.filter(fruittype__fruit__fruit="Pear").values_list('pk', flat=True)
or
plot_ids = Plot.objects.filter(fruittype__fruittype="Pear").values_list('pk', flat=True) # I don't know what fruittype is but I guess this would help you
Then your "inputs"
inputs = Input.objects.filter(plot__pk__in=plot_ids).distinct()
You might wanna try this as well:
from django.db.models import Prefetch
Input.objects.prefetch_related(
Prefetch('plot', queryset=Plot.objects.filter(fruittype__fruit__fruit="Pear"))
)

It worked with:
all_inputs=Input.objects.filter(plot__pk__in=plot_ids).distinct().prefetch_related(Prefetch('plot', queryset=Plot.objects.filter(fruittype__fruit__fruit="Pear")))

Related

Django ORM Count Without Duplicate Column

I have a table called Reading History. I want to find the average number of reads in this table. I wrote the following method for this, but I can't get the right result. Records are made in the table once (student-book records with the same values). When the same record comes, the counter value is increased by one.
For example, suppose that two different students read two different books. I expect total reads / 2 but the result I get is total reads / 4 because there are 4 rows in the table. How can I calculate this? For example, if a student reads 4 different books once, the average will be 1, but the average should be 4.
I tried to use distinct and values but I couldn't get the result I wanted. Maybe I didn't manage to use it correctly. Also I tried to use Avg. When avg didn't give the correct result, I tried to break it down and get the values myself. Normally, Avg was written in Sum.
Serializer
class ClassReadingHistoryReportSerializer(ModelSerializer):
instructor = InstructorForClassSerializer(source="instructor.user")
students = StudenListReadingHistoryReportSerializer(many=True,
source="student_list_class")
avg_read_book = serializers.SerializerMethodField()
class Meta:
model = Class
exclude = [
"created_at",
"updated_at",
"school",
]
def get_avg_read_book(self, obj):
sum_read_book = Class.objects.filter(id = obj.id).aggregate(sum_read=Sum('student_list_class__child__child_reading_history__counter'))
count_child_record = Class.objects.filter(id = obj.id).aggregate(count_child=Count('student_list_class__child__child_reading_history'))
return None
Models
class ChildProfile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
primary_key=True,
verbose_name=AccountStrings.ChildProfileStrings.user_verbose_name,
related_name="user_child")
city = models.ForeignKey(
"country.City",
on_delete=models.SET_NULL,
null=True,
blank=True,
verbose_name=AccountStrings.ChildProfileStrings.city_verbose_name,
related_name="city_child_profiles")
hobbies = models.CharField(
max_length=500,
null=True,
blank=True,
verbose_name=AccountStrings.ChildProfileStrings.hobbies_verbose_name)
class Meta:
verbose_name = AccountStrings.ChildProfileStrings.meta_verbose_name
verbose_name_plural = AccountStrings.ChildProfileStrings.meta_verbose_name_plural
#property
def get_full_name(self):
return f"{self.user.first_name} {self.user.last_name}"
def __str__(self):
return self.get_full_name
def clean(self) -> None:
"""
This method will check if the user type is a child during creation.
"""
if self.user.user_type != 2:
raise ValidationError(AccountStrings.ChildProfileStrings.user_type_error)
class School(AbstractSchoolBaseModel):
city = models.ForeignKey(
"country.City",
on_delete=models.DO_NOTHING,
related_name="city_schools",
verbose_name=SchoolStrings.SchoolStrings.city_verbose_name)
name = models.CharField(
max_length=250,
verbose_name=SchoolStrings.SchoolStrings.name_verbose_name)
address = models.CharField(
max_length=250,
verbose_name=SchoolStrings.SchoolStrings.address_verbose_name)
website = models.CharField(
max_length=250,
verbose_name=SchoolStrings.SchoolStrings.website_verbose_name)
class Meta:
verbose_name = SchoolStrings.SchoolStrings.meta_verbose_name
verbose_name_plural = SchoolStrings.SchoolStrings.meta_verbose_name_plural
def __str__(self):
return self.name
class Class(AbstractSchoolBaseModel):
school = models.ForeignKey(
"school.School",
on_delete=models.CASCADE,
related_name="classes_school",
verbose_name=SchoolStrings.ClassStrings.school_verbose_name)
instructor = models.ForeignKey(
"account.InstructorProfile",
on_delete=models.CASCADE,
related_name="instructors_school",
verbose_name=SchoolStrings.ClassStrings.instructor_verbose_name)
name = models.CharField(
max_length=50,
verbose_name=SchoolStrings.ClassStrings.name_verbose_name)
grade = models.IntegerField(
verbose_name=SchoolStrings.ClassStrings.grade_verbose_name)
class Meta:
verbose_name = SchoolStrings.ClassStrings.meta_verbose_name
verbose_name_plural = SchoolStrings.ClassStrings.meta_verbose_name_plural
ordering = ["name", "grade"]
def __str__(self):
return f"{self.school.name} - {self.name} - Grade: {self.grade}"
def clean(self) -> None:
"""
This method checks whether the teacher trying to be assigned to the class is working in that school.
"""
if self.instructor.school != self.school:
raise ValidationError(SchoolStrings.ClassStrings.instructor_not_working_at_this_school_error)
class StudentList(AbstractSchoolBaseModel):
school_class = models.ForeignKey(
"school.Class",
on_delete=models.CASCADE,
related_name="student_list_class",
verbose_name=SchoolStrings.StudentListStrings.school_class_verbose_name
)
child = models.ForeignKey(
"account.ChildProfile",
on_delete=models.CASCADE,
related_name="student_list_children",
verbose_name=SchoolStrings.StudentListStrings.child_verbose_name)
class Meta:
verbose_name = SchoolStrings.StudentListStrings.meta_verbose_name
verbose_name_plural = SchoolStrings.StudentListStrings.meta_verbose_name_plural
def __str__(self):
return f"{self.school_class.name} : {self.child.user.first_name} {self.child.user.last_name}"
def clean(self) -> None:
result = StudentList.objects.filter(school_class = self.school_class, child = self.child)
if not self.pk and result.exists():
raise ValidationError(SchoolStrings.StudentListStrings.child_already_added_to_this_class_error)
class ReadingHistory(AbstractBookBaseModel):
IS_FINISHED = ((False,
BookStrings.ReadingHistoryStrings.is_finished_false),
(True, BookStrings.ReadingHistoryStrings.is_finished_true))
book = models.ForeignKey(
"book.Book",
on_delete=models.CASCADE,
related_name="book_reading_history",
verbose_name=BookStrings.ReadingHistoryStrings.book_verbose_name)
child = models.ForeignKey(
"account.ChildProfile",
on_delete=models.CASCADE,
related_name="child_reading_history",
verbose_name=BookStrings.ReadingHistoryStrings.child_verbose_name)
is_finished = models.BooleanField(
choices=IS_FINISHED,
verbose_name=BookStrings.ReadingHistoryStrings.is_finished_verbose_name
)
counter = models.PositiveIntegerField(
verbose_name=BookStrings.ReadingHistoryStrings.counter_verbose_name,
default=0)
class Meta:
verbose_name = BookStrings.ReadingHistoryStrings.meta_verbose_name
verbose_name_plural = BookStrings.ReadingHistoryStrings.meta_verbose_name_plural
def __str__(self):
return f"{self.child.user.first_name} {self.child.user.last_name} - \"{self.book.name}\" "
def clean(self) -> None:
result = ReadingHistory.objects.filter(child=self.child,
book=self.book)
if not self.pk and result.exists():
raise ValidationError(
BookStrings.ReadingHistoryStrings.exists_error)
I forgot to add the counter column in the BookReadingHistory table to the diagram. Diagram and Table data are shown in the images below.
Table
Diagram

checking if a certain many to many foreign key is present on django-polymorphic models

So in order to create an object model, I have to first see if a supplier has a relation of type many to many from BusinessModel, WarehouseModel or StoreModel to in a django-polymorphic
My main idea is to check if BusinessModel, which is connected to Order through BusinessOrderModel, StoreModel, which is connected to Order through StoreOrderModel or WarehouseModel which is connected directly to Order, have FKs on a many to many relationship going to the article that we want to order through a POST request.
class ArticleModel(models.Model):
id = models.AutoField(primary_key=True)
code = models.IntegerField(unique=True)
description = models.TextField()
def __str__(self):
return str(self.code)
class OrderModel(models.Model):
id = models.AutoField(primary_key=True)
order_to = models.ForeignKey('OrderToModel', on_delete=models.CASCADE)
article = models.ForeignKey('ArticleModel', on_delete=models.CASCADE)
quantity= models.IntegerField()
class OrderToModel(PolymorphicModel):
id = models.AutoField(primary_key=True)
class WarehouseModel(OrderToModel):
warehouse_num = models.IntegerField(unique=True)
name = models.CharField(max_length=100)
address = models.TextField()
articles = models.ManyToManyField(ArticleModel)
def __str__(self):
return "Warehouse"+ str(self.warehouse_num)
class StoreOrderModel(OrderToModel):
reference = models.IntegerField(unique=True)
store_num = models.ForeignKey('StoreModel', on_delete=models.CASCADE)
def __str__(self):
return str(self.reference)
class StoreModel(models.Model):
store_num = models.IntegerField(primary_key=True)
name = models.CharField(max_length=100)
address = models.TextField()
articles = models.ManyToManyField(ArticleModel)
def __str__(self):
return str(self.store_num)
class BusinessOrderModel(OrderToModel):
reference = models.IntegerField(unique=True)
business_num = models.ForeignKey('BusinessModel', on_delete=models.CASCADE)
def __str__(self):
return str(self.reference)
class BusinessModel(models.Model):
Business_num = models.IntegerField(primary_key=True)
name = models.CharField(max_length=100)
address = models.TextField()
articles = models.ManyToManyField(ArticleModel)
def __str__(self):
return str(self.Business_num)
Here's my serializers:
class WarehouseSerializer(serializers.ModelSerializer):
class Meta:
model = WarehouseModel
fields = ('id', 'warehouse_num')
class StoreOrderSerializer(serializers.ModelSerializer):
class Meta:
model = StoreOrderModel
fields = ('id', 'reference', 'store_num')
class DetailSerializer(serializers.ModelSerializer):
class Meta:
model = DetailModel
fields = ('id', 'detail')
class BusinessOrderSerializer(serializers.ModelSerializer):
details = DetailSerializer(many=True, read_only=True)
class Meta:
model = BusinessOrderModel
fields = ('reference', 'business_num','details')
class OrderToPolymorphicSerializer(PolymorphicSerializer):
model_serializer_mapping = {
WarehouseModel: WarehouseSerializer,
StoreOrderModel: StoreOrderSerializer,
BusinessOrderModel: BusinessOrderSerializer
}
and here's my view:
class OrderCreateView(generics.CreateAPIView):
queryset = OrderModel.objects.all()
serializer_class = OrderCreateSerializer

Django - search a text field for a word or phrase contained in another model

What would be the best method for setting up a keyword finder as below?
class scene(models.Model):
fk_type = models.ForeignKey(scene_types, on_delete=models.CASCADE)
text = models.CharField(max_length=250, default='')
order = models.PositiveSmallIntegerField()
def __str__(self):
return self.text
class Meta:
ordering = ('order', )
class AI_keywords(models.Model):
fk_user = models.ForeignKey(User, default='1', on_delete=models.CASCADE)
keyword = models.CharField(max_length=250)
response = models.ForeignKey(AI_responses, default='1', on_delete=models.CASCADE)
def __str__(self):
return self.keyword
class Meta:
ordering = ('keyword', )
views
class v_scene(LoginRequiredMixin, ListView):
model = scene
template_name = 'storiesapp/scene.html'
context_object_name = 'scene'
The idea is when a keyword in the AI_keywords model is detected in the scene.text field, it displays the AI_keywords.response field

Modify database in django

I am a beginner in django. Following is my Attendance Management App.
This is my models.py.
from django.db import models
class Subject(models.Model):
subject_name = models.CharField(max_length=20)
#attendance = models.ForeignKey(Attendance, on_delete =
models.DO_NOTHING)
attendance = models.IntegerField(default=0)
def __str__(self):
return self.subject_name
class Section(models.Model):
section_name = models.CharField(max_length=20)
subject = models.ManyToManyField(Subject)
def __str__(self):
return self.section_name
class Student(models.Model):
rollno = models.IntegerField()
name = models.CharField(max_length=20)
section = models.ForeignKey(Section, on_delete = models.DO_NOTHING,
default=0)
def __str__(self):
return str(self.rollno) + self.name
class Teacher(models.Model):
#teacher_name = models.CharField(max_length=20)
section = models.ForeignKey(Section, on_delete=models.CASCADE)
subject = models.ForeignKey(Subject, on_delete=models.CASCADE)
#section_name = models.CharField(max_length=10)
#subject_name = models.CharField(max_length=30)
def __str__(self):
return self.section.section_name+' '+self.subject.subject_name
class TeacherList(models.Model):
teacher_name = models.CharField(max_length=20)
teacher = models.ManyToManyField(Teacher)
def __str__(self):
return self.teacher_name
The line below is not working in views.py
student = models.Student.objects.get(rollno = sroll)
student.section.subject.get(subject_name = 'java').attendance += 1
student.save()
This view is called from a template when a button is clicked to add attendance of a student.
The attendance in above code is not modified. Please help me out.
You're saving the student, instead of the subject.
student = models.Student.objects.get(rollno = sroll)
subject = student.section.subject.get(subject_name='java')
subject.attendance += 1
subject.save()
Or, better, do the update directly in one go:
student.section.subject.filter(subject_name='java').update(attendance=F('attendance')+1)
and there's no need to save at all.

QuerySet in Django - returns exception

I am trying to understand how exactly query works on Django, i followed the tutorials it´s not working I am not sure what i am doing wrong.
When I run
BeneficientePagar.objects.filter(nome__contains="Joao Pedro")
it returns
"Choices are %s" %s (name, ",".join(available))) django.core.exceptions.FieldError: Cannot resolve keyword "nome into field. Choices are: ID, beneficiente, beneficiente_id,join, join_id, moeda
from django.db import models
# Create your models here.
class Moeda(models.Model):
moeda_ficticia = models.FloatField()
class Join(models.Model):
nome = models.CharField(max_length=150)
nascimento = models.DateField()
cpf = models.IntegerField(primary_key=True)
endereco = models.CharField(max_length=150)
email = models.EmailField()
def __str__(self):
return self.nome
class Beneficiente(models.Model):
ID = models.AutoField(primary_key=True)
nome = models.CharField(max_length=150)
CNPJ = models.IntegerField(max_length = 10)
def __str__(self):
return self.nome
class Favores(models.Model):
ID = models.AutoField(primary_key=True)
favor = models.CharField(max_length=150)
dataInserido = models.DateField()
usuarios = models.ForeignKey(Join)
def __str__(self):
return self.favor
class BeneficientePagar(models.Model):
ID = models.AutoField(primary_key=True)
moeda = models.IntegerField()
beneficiente = models.ForeignKey(Beneficiente)
join = models.ForeignKey(Join)
def __str__(self):
return self.ID
Thanks in advance
If using BeneficientPager, you need to do
BeneficientePagar.objects.filter(beneficient__nome__contains="Joao Pedro")
You are getting the error because nome is a field on Beneficiente, not BeneficientePagar.
You can either do
Beneficiente.objects.filter(nome__contains="Joao Pedro")
which will return a queryset of Beneficientes. Or if you need BeneficientePagar you can query through the foreign key.
BeneficientePagar.objects.filter(beneficiente__nome__contains="Joao Pedro")