django custom model field - django

If I have 2 interlinked models:
class Person(models.Model)
name = models.CharField()
class Project(models.Model):
person = models.ForeignKey(Person)
title = models.CharField()
I frequently find myself trying to find the number of Projects associated with each Person:
person = Person.objects.get(id=1)
no_projects = Project.objects.filter(person=person).count()
Is there a way of adding this as a custom field to the Person model, such that I may just call person.no_projects?

This can be done by adding a property to the Person class.
class Person(models.Model)
name = models.CharField()
#property
def no_projects(self):
return Project.objects.filter(person=self).count()
This can be called now like this
person = Person.objects.get(id=1)
person.no_projects

In fact, that functionality is (almost) built-in. Instead of querying Projects, you can just do person.project_set.count() to get that person's count of projects (and .all() to get the actual list).

You can use the property() to generate the dynamical field.
class Project(models.Model):
person = models.ForeignKey(Person)
title = models.CharField()
def _get_no_projects(self):
return Projects.objects.filter(person=self).count()
no_projects = property(_get_no_projects)
But the dynamical fields can not be used in querying, because the they don't really store data into the database.
FYI: http://www.b-list.org/weblog/2006/aug/18/django-tips-using-properties-models-and-managers/

Related

how to filter data from parant model based on if there relationship with child model

I have these models
class Tree(models.Model):
field = models.TextField()
class TaskProgress(models.Model):
base_task = models.ForeignKey(BaseTask, on_delete=models.CASCADE)
tree = models.ForeignKey(Tree, on_delete=models.CASCADE)
class BaseTask(models.Model):
trees=models.ManyToManyField(Tree, through='TaskProgress')
class TaskType1(BaseTask):
child1_field = models.TextField()
class TaskType2(BaseTask):
child2_field = models.TextField()
how to get all taskprogress when related to TaskType2 ,
TaskProgress.objects.filter(???)
I added extra field on BaseTask class
TASK_TYPE =[('I','Irrigation'),('C','Care'),('A','Assessment'),('O','Other')]
class BaseTask(models.Model):
trees=models.ManyToManyField(Tree, through='TaskProgress')
worker = models.ManyToManyField(User)
task_type = models.CharField(max_length=1,choices=TASK_TYPE,null=True)
And the filter will be like this
TaskProgress.objects.filter(base_task__task = "I")
I do not think what you are asking is possible, if the models are designed like described. The base_task ForeignKey is specifically pointing at a BaseTask. Even though TaskType1 and TaskType2 inherit from BaseTask, they have no relation in the database. They only look similar.
Option 1: Look into Generic Relations in Django. Basically it allows you to have a ForeignKey relation with more than one type of model. I would not recommend it though. Generic relations are a mess if you don't know want you are doing.
Option 2: Rethink your layout. Maybe you can move the relation to the two TaskTypes instead and adress them via related_name.
class TaskProgress(models.Model):
# base_task = models.ForeignKey(BaseTask, on_delete=models.CASCADE)
tree = models.ForeignKey(Tree, on_delete=models.CASCADE)
class TaskType1(BaseTask):
task_progress = models.OneToOneField(TaskProgress, related_name='task_type_1'
child1_field = models.TextField()
class TaskType2(BaseTask):
task_progress = models.OneToOneField(TaskProgress, related_name='task_type_2'
child2_field = models.TextField()
This way you create a one-to-one-relation between the TaskProgress and the TaskType. You should be able to query one or the other by checking whether a relation exists, e.g. all TaskProgress instances with a relation to a TaskType1 instance.
# Query all TaskProgress instances, that have a TaskType1
TaskProgress.objects.filter(task_type_1__isnull=False)

use manytomany field in both the models Django

I have two models named Profile and Controversy. My requirement is many people can be involved in a controversy and a single person can have multiple Controversies. With that said, I feel like I should a ManyToMany field in both the models but I'm guessing that violates ManyToMany fields documentation as it should be used in only model.
my models are as follows :
class Profile(models.model):
name = models.CharField(max_length=200)
Controversy = models.ManyToManyField(Controversy) # As one person can have multiple controveries
class Controversy(models.Model):
year = models.Datefield()
other_people_involved = models.ManytoManyField(profile) # As multiple people can be involved in a controversy
description = models.TextField()
This obviously will throw error.
I'm not able to understand as to how to tackle such a scenario
You can try this way:
Create another model to store the person and controvery connection.
class Profile(models.model):
name = models.CharField(max_length=200)
class Controversy(models.Model):
year = models.Datefield()
description = models.TextField()
class PeopleInvolved(models.Model):
controversy = models.ManyToManyField(Controversy)
person = models.ManytoManyField(profile)
So to list the controversies of a person do this:
controversies = [i.controversy for i in PeopleInvolved.objects.filter(person=[profile_id])] #pass the profile id of the person.
And to list the people involved in a controversy do this:
peoples = [i.person for i in PeopleInvolved.objects.filter(controversy=[controversy_id])] #pass the controversy id.

How to call a a field of one model A into another model B so that b can work as a view

I have created a model called Department, Course. Models are as follow
This is the model for departments and course
class Departments(models.Model):
Department_Id = models.IntegerField(primary_key=True)
Department_Name = models.CharField(max_length=200)
Department_Code = models.CharField(max_length=200)
class Course(models.Model):
Course_Id = models.IntegerField(primary_key=True)
Department_Id = models.ForeignKey(Departments, on_delete=models.CASCADE)
Course_Name = models.CharField(max_length=200)
Course_Code = models.CharField(max_length=200)
I want to create a model called view which can be later on called for search. I want a view model in a such a way that it consit of the data in concat form i.e. name= Department_name+ Course_Name
class View (models.model):
view_id= models.IntegerField(primary_key=True)
Name= Department_name(I want this from Departments table)
+ Course_Name(I want this from Course table)
I try using one to one relation . I would really appricate the help
It's not clear why you'd want to do that. It's never a good idea to duplicate data from one model into another one, as it can lead to inconsistencies.
You can add a ForeignKey in View to your Course model and then when you do f"{view.course.name} {view.course.department.name}" you already have your string:
class View(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE)
def name(self):
return f"{self.course.name} {self.course.department.name}"
Notes:
Don't call your foreign key Department_id because it's not referring to the id but to the object itself in the Django ORM: department = models.ForeignKey(Department, on_delete=models.CASCADE). As you can see, this makes reading the code much simpler: self.course.Department_id is a Department object not an integer, so self.course.department makes more sense.
Don't prefix your field names with the class, it just makes the code so much less readable: Do you prefer department.name or department.Department_name?
The View model is still a mystery to me, as you can search without it. You can search for example for courses with a matching department name like this:
Course.objects.filter(department__name__icontains="maths")
which will return all courses with "maths" in their department name.
Remove all the ids from your models, they are created automatically by Django anyway (and called id). Again, department.id is much easier to read than department.Department_id. Also in your code, you have to generate the ids yourself since you don't set them to auto-populate.

In Django, how could you serialize the count of ForeignKeys a model instance has?

models.py
class City(models.Model):
name = models.CharField()
class Place(models.Model):
name = models.CharField()
city = models.ForeignKey()
Say an instance of a city has 50 places. What would be the simplest approach to serializing those city objects and including the place count as property in the serialization
json = serialize('json', City.objects.all())
I've tried multiple things but they all start getting really messy at one point or another and I've yet to get one to work

Can I add a manager to a manytomany relationship?

I have two models that has a manytomany relationship with a 'through' table in some way?
class Bike(models.Model):
nickname = models.CharField(max_length=40)
users = models.ManyToManyField(User, through='bike.BikeUser')
The BikeUser class
class BikeUser(models.Model):
bike = models.ForeignKey(Bike)
user = models.ForeignKey(User)
comment = models.CharField(max_length=140)
I would like to add functionality to the Bike class for working with users, is there a best practice way of doing this. I would like to avoid adding too many methods to the Bike class and rather have some kind of manager to work through
Something like:
bike.bikeusers_set.commonMethod()
or
bike.bikeusers.commonMethod()
What would be the best way to accomplish this?
Once you have the BikeUser model, you can add a custom manager to the model.
Something like:
class BikeUserManager(models.Manager):
def commonMethod():
pass
class BikeUser(models.Model):
bike = models.ForeignKey(Bike)
user = models.ForeignKey(User)
comment = models.CharField(max_length=140)
objects = BikeUserManager()
But you can only use it from the BikeUser Model:
BikeUser.objects.commonMethod()
What you want is to use this manager as a related manager:
http://docs.djangoproject.com/en/dev/topics/db/managers/#controlling-automatic-manager-types
Add the use_for_related_fields=True to the manager class.
class MyManager(models.Manager):
use_for_related_fields = True
use_for_related_fields is deprecated from django 2.0. Use for related fields is possible via base manager.
old:
class CustomManager(models.Model):
use_for_related_fields = True
class Model(models.Model):
custom_manager = CustomManager()
new:
class Model(models.Model):
custom_manager = CustomManager()
class Meta:
base_manager_name = 'custom_manager'
source of example
Remember about restrictions for get_queryset() method.
Code
def m2m_with_manager(related_manager, model_manager_name: str):
"""Replaces the default model manager tied to related manager with defined"""
model_manager = getattr(related_manager.model, model_manager_name)
return model_manager.filter(**related_manager.core_filters)
Example
for class Author and Books, where one Author can have multiple books
class Book:
author = FK(Author, related_name='books')
best = models.Manager(...)
Usage
wanted_qs = m2m_with_manager(author.books, model_manager_name='best')