How to create one to many generic relation between objects in Django - django

I have these two models:
How do I correctly set the relationship so I can do backward queries?
class Client(models.Model):
city = models.CharField(max_length=16)
worker = models.ForeignKey(
"Worker",
null=True,
default="1",
on_delete=models.SET_DEFAULT,
related_name="assigned_workers",
)
class Meta:
abstract = True
And:
class Worker(models.Model):
first_name = models.CharField(max_length=16)
last_name = models.CharField(max_length=16)
gender = models.CharField(max_length=1)
What I want to do is set up the models in a way I can do the following queries:
Query the clients assigned to a worker using the worker object. Something like this:
Worker.objects.assigned_workers.all()

Related

Django models dependencies and transfer ownership

What I am trying to build is a app that can deal with honey production management.
There are number of producers that produce honey pots and they can give their pots to a variety of stores that have their customers. One producer can give his production to many stores, and a store can have honey pots from many producers. Honey pots can be tracked by pot_id. The models.py looks like this:
class Produser(models.Model):
name = models.CharField(max_length=255)
address = models.CharField(max_length=255)
class Store(models.Model):
name = models.CharField(max_length=255)
address = models.CharField(max_length=255)
produser= models.ManyToManyField(Produser)
class Customer(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
store = = models.ForeignKey(Store, on_delete=models.CASCADE)
class HoneyPot(models.Model):
produced_date = models.DateField(auto_now=False)
pot_id = models.CharField(max_length=25, blank=False)
produser= models.ForeignKey(Produser, on_delete=models.CASCADE)
store= models.ForeignKey(Store, on_delete=models.CASCADE)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
I'm struggling to find how to modify the models in the way that one pot to be owned or by producer or a shop or a customer. As right now when a new pot is created store and customers are required fields.
You can say that Produser, Store and Customer all have something in common, i.e. they can own a HoneyPot. Meaning they are specializations of let's say an entity that can own a HoneyPot. To model this we would simply add an extra model which Produser, Store and Customer all will either inherit from or have a one to one relationship with.
Using a OneToOneField [Django docs]:
We can simply make the relationship by using a OneToOneField:
class HoneyPotOwner(models.Model):
PRODUCER = 'P'
STORE = 'S'
CONSUMER = 'C'
TYPE_CHOICES = [
(PRODUCER, 'Producer'),
(STORE, 'Store'),
(CONSUMER, 'Consumer'),
]
owner_type = models.CharField(max_length=1, choices=TYPE_CHOICES)
class Produser(models.Model):
honey_pot_owner = models.OneToOneField(HoneyPotOwner, on_delete=models.CASCADE)
...
class Store(models.Model):
honey_pot_owner = models.OneToOneField(HoneyPotOwner, on_delete=models.CASCADE)
...
class Customer(models.Model):
honey_pot_owner = models.OneToOneField(HoneyPotOwner, on_delete=models.CASCADE)
...
class HoneyPot(models.Model):
produced_date = models.DateField(auto_now=False)
pot_id = models.CharField(max_length=25, blank=False)
owner = models.ForeignKey(HoneyPotOwner, on_delete=models.CASCADE)
Using Multi-table inheritance:
We can have Produser, Store and Customer inherit from HoneyPotOwner this is called Multi-table inheritance. This implicitly makes the OneToOneField, but has a few advantage that accessing the related fields becomes a little easier:
class HoneyPotOwner(models.Model):
PRODUCER = 'P'
STORE = 'S'
CONSUMER = 'C'
TYPE_CHOICES = [
(PRODUCER, 'Producer'),
(STORE, 'Store'),
(CONSUMER, 'Consumer'),
]
owner_type = models.CharField(max_length=1, choices=TYPE_CHOICES)
class Produser(HoneyPotOwner):
...
class Store(HoneyPotOwner):
...
class Customer(HoneyPotOwner):
...
class HoneyPot(models.Model):
produced_date = models.DateField(auto_now=False)
pot_id = models.CharField(max_length=25, blank=False)
owner = models.ForeignKey(HoneyPotOwner, on_delete=models.CASCADE)

Filtering Django query filtering

I'm doing some querying currently and I was wondering if I would be able to query something from these 3 models where the return would give me all the projects the users are working on. I know about the basic filtering however thats not really enough in this case, how would one go about querying through 2 foreign keys.
class User(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.EmailField()
class ProjectUser(models.Model):
project = models.ForeignKey("Project", on_delete=models.CASCADE)
user = models.ForeignKey("User", on_delete=models.CASCADE)
is_lead = models.BooleanField(default=False)
class Meta:
unique_together = (("project", "user"),)
class Project(models.Model):
name = models.CharField(max_length=255)
client = models.CharField(max_length=255)
complete = models.BooleanField(default=False)
You can obtain the Projects a user is working on with:
Project.objects.filter(
projectuser__user=user
)
The double underscores are used to look "through" relations. Furthermore the default related_query_name=… parameter [Django-doc] is, if not specified, the name of the model in lowercase.

Django Many-To-One

I'm trying to create a simple to-do app in Django. I have some trouble to understand the idea of foreign keys. Each project suppose to get multiple apartments, and each apartment should get multiple tasks.
models:
# Project model
class Project(models.Model):
name = models.CharField(_("Name"), max_length=30)
city = models.CharField(_("City"), max_length=30)
street = models.CharField(_("Street"), max_length=30)
number = models.IntegerField(_("Number"), max_length=4)
ZIP = models.ImageField(_("ZIP"), max_length=10)
manager = models.CharField(_("Manager"), choices=managers, default='ariel')
# Apartments
apartment = models.ForeignKey(_("Apartment"), Apartment, on_delete=models.CASCADE)
def __repr__(self):
return "{}".format(self.name)
# Apartment model
class Apartment(models.Model):
building = models.CharField(_("Building"), max_length=4)
floor = models.CharField(_("Floor"), max_length=4)
number = models.CharField(_("Number"), max_length=4)
type = models.CharField(_("Type"), max_length=4)
upgraded = models.BooleanField(_("Upgraded"), default=False)
drawing = models.FileField(_("Drawing"), upload_to=None)
notes = models.TextField(_("Notes"), max_length=500)
status = models.BooleanField(_("Completed"), default=False)
# Tasks
airTunnels = models.ForeignKey(_("Air Tunnels"), Task, on_delete=models.CASCADE)
gasPipelines = models.ForeignKey(_("Gas Pipelines"), Task, on_delete=models.CASCADE)
def __repr__(self):
return "{} - {}".format(self.number, self.status)
# Task model
class Task(models.Model):
title = models.CharField(_("Task"), max_length=30)
doneBy = models.CharField(_("Done By"), choices=workers, default='daniel')
date = models.DateTimeField(_("Date"), default=timezone.now())
def __repr__(self):
return "{}".format(self.title)
If you use apartment = models.ForeignKey(_("Apartment"), Apartment, on_delete=models.CASCADE), it means that each project has onyl one apartment. So you must define different project for each apartment. If your each apartment can has only one project, you must define foreignkey inside your apartment model like that:
class Apartment(models.Model):
#...your other fields
project = models.ForeignKey(Project, on_delete=models.CASCADE)
For apartment tasks, If I understood correctly, your apartment model can has multiple tasks.So, you can use ManyToMany field for this.With this definition, your each apartment can has multiple tasks. But your each task can belong to multiple apartment objects. If you don't want to each task can belongs to different apartment objects, you must set OneToMany relation.You can do that with adding foreignkeyfield to task model like that:
class Task(models.Model):
#...your other fields
apartment = models.ForeignKey(Apartment, on_delete=models.CASCADE)

How to serialize a self recursive many-to-many model using a through table in django rest_framework?

i am developing a rest API using django rest framework and i am stuck at a serializer the idea is to serialize a self recursive many to many model using a through table my code is:
model.py:
class Patient(models.Model):
class Meta:
db_table = 'patients'
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True)
id_card = models.CharField(max_length=45)
dob = models.DateField()
gender = EnumChoiceField(enum_class=Gender)
patientscol = models.CharField(max_length=45)
fk_user = models.ForeignKey(Users, related_name='user_patient', on_delete=models.CASCADE)
relative = models.ManyToManyField("self", through='PatientHasRelative')
class PatientHasRelative(models.Model):
class Meta:
db_table = 'patients_has_relatives'
fk_patient = models.ForeignKey(Patient, related_name='patient_has', on_delete=models.CASCADE)
fk_relative_patient = models.ForeignKey(Patient, related_name='patient_relative', on_delete=models.CASCADE)
relationship = EnumChoiceField(enum_class=Relationship)
my serializer.py is:
class PatientSerializer(serializers.ModelSerializer):
class Meta:
model = Patient
fields = ('__all__')
id = serializers.UUIDField(read_only=True)
id_card = serializers.CharField(required=True, max_length=45)
dob = serializers.DateField(required=True)
gender = EnumChoiceField(enum_class=Gender)
fk_user = serializers.PrimaryKeyRelatedField(required=True, queryset=Users.objects.all())
relative = PatientSerializer(read_only=True, required=True)#problem is here i cant use PatientSerializer here
class PatientHasRelativeSerializer(serializers.ModelSerializer):
class Meta:
model = PatientHasRelative
fields = ('__all__')
fk_patient = serializers.PrimaryKeyRelatedField(required=True, queryset=Patient.objects.all())
fk_relative_patient = serializers.PrimaryKeyRelatedField(required=True, queryset=Patient.objects.all())
relationship = EnumChoiceField(enum_class=Relationship)
a little help would be appreciated
To accomplish this you need to define related_name in the source model on the source field ie add
class Patient(models.Model):
relatives = models.ManyToManyField(
"self", through='PatientHasRelative', related_name='patients')
with this related_name you can easily access -- add/delete/set relatives/patients on either side of the relationships in the serializers
You can either do this using intermediary model
relative = Patient(**key_value_fields)
patient = Patient(**key_value_field)
PatientHasRelative.objects.create(
relative=relative, patient=patient, through_defaults=(relationship ='value',))
or you can do this
relative.patients.add(patient, through_defaults=relationship ='value')
or this
patient.relatives.add(relative, through_defaults=relationship ='value')
example retrieving
patient.relatives.all()

don't want inner joins on django models

i've migrated an existing database that i would like to work with django. i have the following models:
class Device(models.Model):
class Meta:
db_table = u'DEVICES'
managed=False
id = models.CharField(primary_key=True, max_length=22, db_column='DEVICE_ID')
name = models.CharField(max_length=40, db_column='DEVICE_NAME')
status = models.CharField(max_length=10, db_column='STATUS')
class DevicePort(models.Model):
class Meta:
db_table = u'DEVICE_PORT'
managed=False
id = models.CharField( primary_key=True, max_length=22, db_column='DEVICE_PORT_ID')
device = models.OneToOneField(Device, db_column='DEVICE_ID')
type = models.CharField( max_length=22, db_column='PORT_TYPE_ID')
port_num = models.CharField( max_length=30, db_column='DEVICE_PORT_NUM')
class IP(models.Model):
class Meta:
db_table = u'IP_NODE'
managed=False
ip_address = models.CharField(primary_key=True, max_length=15, db_column='IP_NODE_NO')
hostname = models.CharField(max_length=40, db_column='IP_HOST')
port = models.OneToOneField(DevicePort, db_column='DEVICE_PORT_ID')
status = models.CharField(max_length=50, db_column='IP_NODE_STATUS')
i want a list of Devices and their relational IP.ip_address and IP.hostnames. In SQL, i would do something like:
SELECT UNIQUE
d.device_name device
FROM
IP_NODE c,
DEVICES d,
DEVICE_PORT e
WHERE
c.ip_node_no = b.ip_node_no
AND c.device_port_id = e.device_port_id
AND e.device_id = d.device_id
AND d.device_name LIKE 'something';
How do i do this with my django models?
So instead of an inner join you want...and implicit join? Is there something I'm missing here because an implicit join is slower than an explicit one most all cases.
[http://postgresql.1045698.n5.nabble.com/explicit-JOIN-faster-than-implicit-td1920335.html][1]
I can't see any reason you would want to do this, but as stated above you can certainty get this by writing your own queries with raw, or even connection.cursor. Maybe even could pull it off with extra(tables=[...]), though I'm not positive as I've never used tables like this.