django queryset between two tables without foreign key - django

I am trying to fetch results from two tables which does n't have a foreign key relation, Just want to know approach I'm using is right or not.
django.db import models
django.contrib.auth.user import User
class UserWorkExperience(models.Model):
user = models.ForeignKey(UserProfile)
job_title = models.CharField(max_length=255)
salary = models.IntegerField(null=True,default='0')
class UserSkills(models.Model):
user = models.ForeignKey(UserProfile)
skill_name = models.CharField(max_length=255)
So What I want is all records for
skills of all user which have job-title 'software engineer' and salary greater than '100000'

user_ids = UserWorkExperience.objects.filter(job_title='software engineer', salary__gt=100000).values_list('user', flat=True)
skills = UserSkills.objects.filter(user__in=user_ids)
It is recommended to use a ForeignKey for job_title and also skill_name

Related

django select records from multiple tables with same foreign key

I would like to execute a single query in Django which retrieves related data, by foreign key, in multiple tables. At present I have to run a query on each table e.g. (House, Furniture, People) using the House number as a filter.
In SQL I can do this in one query like this:
SELECT house.number, house.number_of_rooms, furniture.type, people.name
FROM (house INNER JOIN furniture ON house.number = furniture.house_number)
INNER JOIN people ON house.number = people.house_number
WHERE (((house.number)="21"));
Can this be done in Django?
See example models below:
class House(models.Model):
number = models.CharField('House Number', max_length=10, blank=True, unique=True, primary_key=True)
number_of_rooms = models.IntegerField(default=1, null=True)
class Furniture(models.Model):
house_number = models.ForeignKey(House, on_delete=models.CASCADE, null=True)
type = models.CharField('Furniture Type', max_length=50)
class People(models.Model):
house_number = models.ForeignKey(House, on_delete=models.CASCADE, null=True)
first_name = models.CharField('First Name', max_length=50)
In your models add related_name arguments for foreign keys, so that you can retrieve the objects related to the House() instance.
class Furniture(models.Model):
house_number = models.ForeignKey(House, related_name='house_furniture', on_delete=models.CASCADE, null=True)
type = models.CharField('Furniture Type', max_length=50)
class People(models.Model):
house_number = models.ForeignKey(House, related_name='house_people', on_delete=models.CASCADE, null=True)
first_name = models.CharField('First Name', max_length=50)
Then run the migration using following commands.
python manage.py makemigrations
python manage.py migrate
Then create a new serializers.py module in the same app.
#import models Furniture, People, house
from rest_framework import serializers
class FurnitureSerializer(serializer.ModelSerializer):
class Meta:
model = Furniture
fields = ['type'] # if you want all the fields of model than user '__all__'.
class PeopleSerializer(serializer.ModelSerializer):
class Meta:
model = People
fields = ['first_name'] # if you want all the fields of model than user '__all__'.
class HouseSerializer(serializer.ModelSerializer):
house_furniture = FurnitureSerializer(many=True)
house_people = PeopleSerializer(many=True)
class Meta:
model = Furniture
fields = ['number', 'number_of_rooms', 'house_furniture', 'house_people']
Now, in your views.py you can simply query on model House and serializer the result with HouseSerializer().
#import models from models.py
#import serializer from serializers.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.generics import ListAPIView
class ListHouseView(ListAPIView):
serializer_class = HouseSerializer
queryset = House.objects.filter() #here you can apply filters on the fields of house model and user using related_name you can filter on other related models as well.
Now, simply call ad this in your app's urls.py
url_pattern = [
path('list-house/', ListHouseView.as_view()),
]
Make sure that have a path in your project's urls.py to reach this app's urls.py.
The usual Django way of dealing with this is Queryset.prefetch_related() and iterating through Python (unless you're using Postgres, which has its own solution of ArrayAgg). Given your models, it'll cost three queries, but you won't have to deal with de-normalized row results.
h = House.objects.prefetch_related('furniture_set', 'people_set').get(number='21')
for furniture in house.furniture_set.all():
print(furniture)
for person in house.people_set.all():
print(people)
prefetch_related() caches the results and does the "joining" in Python once the queryset is evaluated, so iterating through the reverse relationships won't incur additional queries, and you're free to structure/serialize the data however you like. The raw SQL from this is something like:
SELECT house.number, house.number_of_rooms FROM house WHERE house.number = '1'
SELECT furniture.id, furniture.house_number_id, furniture.type FROM furniture WHERE furniture.house_number_id IN ('1')
SELECT people.id, people.house_number_id, people.first_name FROM people WHERE people.house_number_id IN ('1')
But Django does that behind-the-scenes so that you can just deal with a model instance in Python.

How to force field mappings with a ManyToMany relationship on same model

I have a fairly simple model representing users:
class Person(AbstractUser):
students = models.ManyToManyField("web.Person", through="Supervision")
...
with a many-to-many relationship to itself...
class Supervision(models.Model):
student = models.ForeignKey('web.Person', on_delete=models.CASCADE, related_name="supervisor")
supervisor = models.ForeignKey('web.Person', on_delete=models.CASCADE, related_name="student")
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
class Meta:
unique_together = [['student', 'supervisor']]
def __str__(self):
return "{supervisor} supervises {student} ({id})".format(
supervisor=self.supervisor, student=self.student, id=self.pk
)
The problem comes when I create a relation between 2 persons:
>>> prof = Person.objects.get(last_name="prof")
>>> student = Person.objects.get(last_name="student")
>>> prof.students.add(student)
>>> prof.save()
>>> Supervision.objects.all()
<QuerySet [<Supervision: student, student (1130) supervises prof, prof (97) (2)>]>
It seems that Django swaps the relation by default.
I tried to swap the related names in the class definition of the Supervision:
class Supervision(models.Model):
student = models.ForeignKey('web.Person', on_delete=models.CASCADE, related_name="student")
supervisor = models.ForeignKey('web.Person', on_delete=models.CASCADE, related_name="supervisor")
But it does not help. How can I get Django to put the fields in the correct order?
It is not that Django is swapping the relation as you say. The thing is Django simply doesn't know which foreign key is for what part of the relation. You can specify the through_fields [Django docs] in your ManyToManyField so that Django may know which field is for the source and which is for the target:
class Person(AbstractUser):
students = models.ManyToManyField("self", through="Supervision", through_fields=('supervisor', 'student'), symmetrical=False)
Note: I changed web.Person to self since that is a better way to specify a foreign key / m2m to the same model.

Django - Sqlite Database

Any help is greatly appreciated.
I am using Django and SQLite, I am trying to join the auto generated auth_user table with an input table that I have created using a model.
Models.py;
class Input(models.Model):
height = models.IntegerField(default=0)
waist = models.IntegerField(default=0)
bust = models.IntegerField(default=0)
hips = models.IntegerField(default=0)
class Meta:
db_table = "Project_input"
The purpose of joining the tables is so that when a user logs in the information they enter into my input table is only associated with them.
I understand that I have to add a foreign key to this model! But how do I reference the auth_user table?
Just add a ForeignKey field to the model.
class Input(...):
user = models.ForeignKey('auth.User') # (or `settings.AUTH_USER_MODEL`)
# ...
See the Django docs about foreign keys and other many-to-one relations.
I think, All you need that to edit your model to this
Models.py
from django.contrib.auth.models import User
class Input(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='inpute')
height = models.IntegerField(default=0)
waist = models.IntegerField(default=0)
bust = models.IntegerField(default=0)
hips = models.IntegerField(default=0)
class Meta:
db_table = "Project_input"
With this, you make one to one relationship with the class user which Django provides.

How to create custom relation table for ForeignKey or OnetoOne field?

What I want to do is create a model than can be used to store data about a relation between two elements. With ManytoMany fields, I can use the parameter "through" and specify a model which stores two elements foreign keys as below.
def MyModel(models.Model):
relation = models.ManyToManyField('AnotherModel', through='RelationModel')
def RelationModel(models.Model):
model1 = models.ForeignKey('MyModel')
model2 = models.ForeignKey('AnotherModel')
slug = models.CharField()
What would be the equivalent for a OnetoOne relation or a ForeignKey relation ? I've read the docs about custom managers and some posts on SO so in the end I'm quite confused and I dont know what is the solution. Thanks in advance for any help.
you can do like this
from products.models import VendorDetails
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='profile', on_delete=models.CASCADE)
user_location = models.CharField(max_length=50, null=True)
vendor_category = models.ManyToManyField(VendorDetails, through="UserProfileVendorCategory")
class UserProfileVendorCategory(models.Model):
user_profile = models.ForeignKey(UserProfile)
vendor_category = models.ForeignKey(VendorDetails)
location = models.CharField(max_length=256)

how to set django model field value based on value of other field in the different model

I am extremely new to django. I want to add field values based on other field value of other class. How can do this? can I do it with django custom actions?
please help
Sorry for my bad english
In model.py
from django.db import models
# Create your models here.
class Teachers(models.Model):
teacher_name = models.CharField(max_length=255)
def __str__(self):
return self.teacher_name
class Students(models.Model):
teacher = models.ForeignKey(Teachers,related_name="students_teachers")
student_rollno = models.IntegerField()
student_name = models.CharField(max_length=255)
student_last_name = models.CharField(max_length=255)
def __str__(self):
return self.student_name
class Subjects(models.Model):
teacher = models.ForeignKey(Teachers,related_name="subjects_teachers")
student = models.ForeignKey(Students,related_name="subjects_students")
book_name = models.CharField(max_length=255)
book_description = models.CharField(max_length=255)
book_author = models.CharField(max_length=255)
def __str__(self):
return self.book_name
Here, i create three models ('Teachers, Students, Subjects')
In Students class i use Teachers class as foreign key.
and in Subjects i use Teachers and Students as foreign key.
In admin section :
in Subjects section Teachers, and Studetns dropdown is shown.
Hope its help you :-)
Something like this below..
from App1 import Model1
from App2 import Model2
q1 = Model1.objects.filter(pk=something)
if q1:
field1 = q1[0].field1
q2 = Model1.objects.filter(pk=something)
if field1 =='something':
if q2:
q2[0].field2 == 'something'
q2[0].save()
Note: (pk - primary key)
Model1.objects.get(somefield=something) will throw error if there is no results or more than one results
Model1.objects.filter(somefield=something) will not throw errors if there is no results