How to get the relation between user in my app? - django

Suppose there is family, each family member can login to my app, when the user login, I want to show the relation between him and the other family member instead of just the family member name.
the real challenge is the relation is dynamic according to the login user, for example:
A is the father of B
C is the wife of B
B and C have a child D
if D login the relation will be
A = granddad
B = father
C = mother
D = me
but if A log in , the relation will be
A = me
B = son
C = daughter in law
D = grandson
the example is fairly simple but the real world situation is much more complicated, like borther and sister, aunt,uncle etc.
Am using django and this is how my model is defined:
class UserProfile(models.Model):
user = models.OneToOneField(User)
family = models.ManyToManyField(FamilyProfile,related_name='family_members')
realname = models.CharField(max_length=100)
date_of_birth = models.DateField(
'user born date', null=True, blank=True)
is_male = models.BooleanField(default=False) # True male
relation_level = models.IntegerField(null=False,blank=False,default=9999)
is_foreign = models.BooleanField(default=False) # True foreign
is_host = models.BooleanField(default=False) # Ture host,
objects = profileManager()
because the relation ship is dynamic , I can't save it to the database, instead, I use the profileManager to calculate the relation ship and add it to the member: member.relation_name, but this is too complicated for me, right now I'm using a lot of if...else statement and its really long, and really stupid, so please help me with this problem .

If you look at it from a DB point-of-view the correct way to do this is to add an 'id' field to the UserProfile model, and also add another class like:
class Relations(models.Model):
relation_id = models.IntegerField()
relation_name = models.CharField()
which would be filled with the relations (like: (1, "son of"), (2, "father of"), etc..) (you might also need to make one string for male and one for female. That's the least interesting point here.
After you've created this list of Relations you need to assign the relations to users, and therefore we make another model:
class UserToRelations(models.Model):
user_a_id = models.IntegerField()
user_b_id = models.IntegerField()
relation_id = models.IntegerField()
[You might just do that with the keys, I really don't remember django that well]
So now you need to populate the UserToRelations table just each time you add a member to the DB. You calculate the relationships there.
The selecting part is where you see the profit of this. Every time a member logs in, you just need to get all the relevant rows from the UserToRelations model and you just present them.

Related

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.

How to filter joined models in Django?

I have the following models:
class Street(models.Model):
name = models.CharField(max_length=40)
class House(models.Model):
street = models.ForeignKey(Street, models.PROTECT)
number = models.CharField(max_length=10)
class Meta:
unique_together = ('street', 'number')
class Room(models.Model):
house = models.ForeignKey(House, models.PROTECT)
number = models.CharField(max_length=10)
class Meta:
unique_together = ('house', 'number')
I already know the ID of a Street and would like to get all the rooms of all the houses in that street. In SQL that is easy:
SELECT *
FROM room JOIN house ON house.id = room.house_id
WHERE house.street_id = xyz;
Now how do I do this in Django? I tried
Room.objects.select_related('house').filter(street=xyz)
But I get an exception saying I can't access this field:
django.core.exceptions.FieldError: Cannot resolve keyword 'street' into field. Choices are: house, house_id, id, number
Because of the amounts of data I am facing, I would really like to be able to join and filter using a single query! When giving up one or the other, I would have to resort to either making multiple queries or filtering in Python, both of which are inherently inefficient. An alternative would be raw queries, I guess...
You can get access to related object's field with __ syntax:
Room.objects.select_related('house').filter(house__street=xyz)
This can be done as much time as you need, to select rooms by street name you can do this:
Room.objects.select_related('house').filter(house__street__name=xyz)
Chech details here.

How to retrieve a set of objects, filtered and ordered by fields of other objects, for which the desired object is a foreign key?

To rephrase the title to the context of my problem: How to retrieve a set of foods, filtered and ordered by fields of other objects, for which the food object is a foreign key?
I have the following models:
class Food(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
description = models.CharField(max_length=200, blank=True)
class DayOfFood(models.Model):
user = models.ForeignKey(User)
date = models.DateField()
unique_together = ("user", "date")
class FoodEaten(models.Model):
day = models.ForeignKey(DayOfFood, on_delete=models.CASCADE)
food = models.ForeignKey(Food, on_delete=models.CASCADE)
servings = models.FloatField(default=1)
I want to be able to retrieve the foods that a given user ate most recently. This collection of foods will be passed to a template so it must be a QuerySet to allow the template to loop over the food objects.
This is how far I got
days = DayOfFood.objects.filter(user=request.user)
foodeatens = FoodEaten.objects.filter(day__in=days)
foodeatens = foodeatens.order_by('day__date')
Now it feels like I am almost there, all the foods I want are contained in the FoodEaten objects in the resulting QuerySet. I do not know how to use "for ... in:" to get the food objects and still have them stored in a QuerySet. Is there a way to perform foreach or map to a QuerySet?
I do not want to rewrite the template to accept FoodEaten objects instead because the template is used by other views which do simply pass food objects to the template.
The solution
The answer from Shang Wang helped me write code that solves my problem:
days = DayOfFood.objects.filter(user=request.user)
foods = Food.objects.filter(
foodeaten__day__in=days,
foodeaten__day__user=request.user) \
.order_by('-foodeaten__day__date')
That could be done using chain of relations:
Food.objects.filter(foodeaten__day__in=days,
foodeaten__day__user=request.user) \
.order_by('foodeaten__day__date')
By the way, I'm not sure why do you have user on multiple models Food and DayOfFood. If you really need user relations on both of them, maybe make the field name more explicit with the user's role in each model, otherwise you will get confused very quickly.

Django many-to-many lookup from different models

I have some models that represents some companies and their structure. Also all models can generate some Notifications (Notes). User can see own Notes, and, of course, can't see others.
class Note(models.Model):
text = models.CharField(...)
class Company(models.Model):
user = models.ForeignKey(User)
note = models.ManyToManyField(Note, blank='True', null='True')
class Department(models.Model):
company = models.ForeignKey(Company)
note = models.ManyToManyField(Note, blank='True', null='True')
class Worker(models.Model):
department = models.ForeignKey(Department)
note = models.ManyToManyField(Note, blank='True', null='True')
class Document(models.Model)
company = models.ForeignKey(Company)
note = models.ManyToManyField(Note, blank='True', null='True')
The question is how I can collect all Notes for particular user to show them?
I can do:
Note.objects.filter(worker__company__user=2)
But its only for Notes that was generated by Workers. What about another? I can try hardcoded all existing models, but if do so dozen of kittens will die!
I also tried to use backward lookups but got "do not support nested lookups". May be I did something wrong.
EDIT:
As I mentioned above I know how to do this by enumerating all models (Company, Worker, etc. ). But if I will create a new model (in another App for example) that also can generate Notes, I have to change code in the View in another App, and that's not good.
You can get the Notes of a user by using the following query:
For example let us think that a user's id is 1 and we want to keep it in variable x so that we can use it in query. So the code will be like this:
>>x = 1
>>Note.objects.filter(Q(**{'%s_id' % 'worker__department__company__user' : x})|Q(**{'%s_id' % 'document__company__user' : x})|Q(**{'%s_id' % 'company__user' : x})|Q(**{'%s_id' % 'department__company__user' : x})).distinct()
Here I am running OR operation using Q and distinct() at the end of the query to remove duplicates.
EDIT:
As I mentioned above I know how to do this by enumerating all models
(Company, Worker, etc. ). But if I will create a new model (in another
App for example) that also can generate Notes, I have to change code
in the View in another App, and that's not good.
In my opinion, if you write another model, how are you suppose to get the notes from that model without adding new query? Here each class (ie. Department, Worker) are separately connected to Company and each of the classes has its own m2m relation with Note and there is no straight connection to User with Note's of other classes(except Company). Another way could be using through but for that you have change the existing model definitions.
Another Solution:
As you have mentioned in comments, you are willing to change the model structure if it makes your query easier, then you can try the following solution:
class BaseModel(models.Model):
user = models.Foreignkey(User)
note = models.ManyToManyField(Note)
reports_to = models.ForeignKey('self', null=True, default=None)
class Company(BaseModel):
class Meta:
proxy = True
class Document(BaseModel):
class Meta:
proxy = True
#And so on.....
Advantages: No need to create separate table for document/company etc.
object creation:
>>c= Company.objects.create(user_id=1)
>>c.note.add(Note.objects.create(text='Hello'))
>>d = Document.objects.create(user_id=1, related_to=c)
>>d.note.add(Note.objects.create(text='Hello World'))

Manytomany django using existing key

I hope this is not a duplicate question. I am trying to setup models in django.
In model 1 I have one kind items (parts), these can together form item type 2 (car).
I get the prices for all of these from outside interface to a model prices.
How can I setup the relationship between price - > part and price - > car.
I do not know when I get the prices if the ident belongs to car och part.
class parts(models.Model):
ident = models.CharField("IDENT", max_length = 12, unique = True, primary_key = True)
name = models.CharField(max_length=30)
class car(models.Model):
ident = models.CharField("IDENT", max_length = 12, unique = True)
start_date = models.DateField()
end_date = models.DateField()
parts= models.ManyToManyField(parts)
class Prices(models.Model):
ident= models.CharField(max_length=12)
price = models.DecimalField(max_digits=10, decimal_places= 4)
date = models.DateField()
def __unicode__(self):
return self.ident
class Meta:
unique_together = (("ident", "date"),)
I would imagine you would not store price in your model since you need this to be 100% real time. So you have;
car models.py
from parts.models import parts
name = models.CharField(max_length=100)
parts = models.ManyToManyField(parts)
Hopefully you're not trying to develop like a full scale autozone type deal, but if it's simply a car model object that is comprised of many parts than this is the basic setup you would want. having the many to many relationship to parts allows one car to have many parts. parts can belong to many cars. You don't have to specify a manytomany relationship in the parts model as the two way communication will already be handled in your cars model.
As far as price is concerned you could have a price database field in your parts model, but once again if this needs to be real time, you probably want to request that price via an api and display it directly in your webpage.