The pages made of existing php are being changed to python and Django.
Existing Query
Select
l.lawyer_idx,
l.lawyer_email,
lp.lawyer_profile_path,
lp.lawyer_profile_name,
lc.lawyer_company_name,
lc.lawyer_company_address,
lc.lawyer_detail_address,
l.lawyer_agent
from lawyer l
left join lawyer_profile lp on l.lawyer_idx = lp.lawyer_idx
left join lawyer_company lc on l.lawyer_idx = lc.lawyer_idx
order by l.register_date desc;
I made each table at models.py
models.py
class Lawyer(models.Model):
lawyer_idx = models.AutoField('ID', primary_key=True)
lawyer_email = models.CharField('E-mail', unique=True, max_length=200)
lawyer_agent = models.CharField(max_length=1, blank=True, null=True)
class Meta:
managed = False
db_table = 'lawyer'
class LawyerProfile(models.Model):
lawyer_idx = models.AutoField('ID', primary_key=True)
lawyer_profile_path = models.CharField(max_length=200, blank=True, null=True)
lawyer_profile_name = models.CharField(max_length=100, blank=True, null=True)
.................
class LawyerCompany(models.Model):
lawyer_idx = models.AutoField('ID', primary_key=True)
lawyer_company_name = models.CharField(max_length=100)
...............
We would like to place the following query into the
list_display portion of Django Admin.py Is there any way to show the data that did join in sql?
Admin.py
from django.contrib import admin
from .models import Lawyer, LawyerCompany, LawyerProfile
#admin.register(Lawyer)
class LawyerAdmin(admin.ModelAdmin):
list_per_page = 100
**list_display = ['lawyer_idx', 'lawyer_email',
'lawyer_agent', 'lawyer_profile_path', 'lawyer_profile_name', 'lawyer_company_name']**
You could add the query as a raw sql query, but that wouldnt make much use of Django's ORM then.
You are not explicitly defining any relationships on your models, so Django doesn't know about how your models relate.
If lawyer_idx references the lawyer you could change the field to a OneToOneField/ForeignKey (an AutoField is probably the wrong choice here anyways, as the values should correspond to those in the Lawyer model and not be auto-generated). Also have a look at the documentation for one-to-one and many-to-one relationships.
class LawyerProfile(models.Model):
lawyer = models.OneToOneField(Lawyer, primary_key=True,
db_column="lawyer_idx", related_name="profile")
Django should perform the joins automatically when accessing the related data; on a Lawyer instance you can then access the profile via its related_name .profile. In the list_display option you can use the double underscore syntax to access related data:
list_display = ['lawyer_idx','lawyer_agent', 'profile__lawyer_profile_path']
list_select_related = ['profile']
If you add the list_select_related option Django will already join the specified table beforehand, so no additional queries are performed when accessing the related data.
Related
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.
I have two django models as follows:
The first one is a user profile, which has a FK to User model:
class Profile(models.Model):
PRF_user = models.OneToOneField(User, related_name='related_PRF_user', on_delete=models.CASCADE)
PRF_Priority_Support = models.BooleanField(default=False)
and the second is ticket model which has a FK to User model:
class ticket(models.Model):
ticket_status_options = [
('open', 'open'),
('wait_customer_reply', 'wait_customer_reply'),
('replied_by_staff', 'replied_by_staff'),
('replied_by_customer', 'replied_by_customer'),
('solved', 'solved'),
]
TKT_USER = models.ForeignKey(User, related_name='TKT_USER', on_delete=models.CASCADE)
TKT_DEB = models.ForeignKey('Site_departments', related_name='related_ticket_department', on_delete=models.CASCADE)
TKT_SUB = models.CharField(max_length=50, db_index=True, verbose_name="ticket subject")
TKT_BOD = models.TextField(verbose_name="ticket body")
TKT_image_attachment = models.ImageField(upload_to='TKT_img_attachment', blank=True, null=True , default=None)
TKT_CREATED_DATE = models.DateTimeField(auto_now_add=True)
TKT_UPDATED_DATE = models.DateTimeField(auto_now=True)
I want to sort the tickets based on user profile Priority_Support:
If the user profile PRF_Priority_Support is True, I want to sort it first inside my views QuerySet, otherwise (if PRF_Priority_Support is False) I want to sort it normally.
How can I do this?
You should name your model starting with a capital letter.
And for ordering the tickets, you can use something like this:
' queryset_list = ticket.objects.order_by('-TKT_USER__related_PRF_user__PRF_Priority_Support')
In filtering, when you want to span relationships, you use double underscore __ .
More on this here:
https://docs.djangoproject.com/en/3.1/topics/db/queries/#lookups-that-span-relationships
Another way is adding ordering to your model's Meta class.
For Example:
MyModel(models.Model):
class Meta:
ordering = ('-my_boolean_field ',)
Hi you should filter as follow:
Model.objects.filter(field=True) or False depending on what you need
Regards
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.
I am struggling to understand how one-to-many and many-to-many relation works in Django model. My schema looks something like this so far, I am open for suggestions to make it better.
A many-to-many relation between users and team. Also, there will be schedules that belong to a particular user of a team.
This is how my model looks like so far,
class Team(models.Model):
tid = models.AutoField(primary_key=True)
team_name = models.CharField(max_length=30)
manager_name = models.CharField(max_length=30)
class Schedule(models.Model):
sid = models.AutoField(primary_key=True)
user = models.OneToOneField(User)
date = models.DateField()
start_time = models.TimeField()
end_time = models.TimeField()
pay_rate = models.CharField(max_length=30)
location = models.CharField(max_length=50)
class BelongsTo(models.Model):
bid = models.AutoField(primary_key=True)
user = models.OneToOneField(User)
team = models.ForeignKey(Team, on_delete=models.CASCADE)
schedule = models.ForeignKey(Schedule, on_delete=models.CASCADE)
Question: I want to get the information of each user, what are their schedules and which team each schedule belongs to. How would I to do it? I have tried BelongsTo.objects.select_related().all(), but it is not working for me.
Note: I am open for suggestions, if something is wrong with my schema or model or the approach, please let me know.
BelongsTo is seems like utility table.So
BelongsTo.objects.all().values('user', 'team__team_name', 'schedule')
Your schema looks almost right, but I would modify it a little bit. In particular, I will change how Schedule is implemented. Instead of having a sid in the User Belongs To join-table, I would include the user and team in the Schedule table as foreign keys.
This is how the Django models should then look like:
class User(models.Model):
username = models.CharField(max_length = 200)
# put other fields like password etc. here
class Team(models.Model):
team_name = models.CharField(max_length=30)
manager_name = models.CharField(max_length=30)
user = models.ManyToManyField("User")
class Schedule(models.Model):
user = models.ForeignKey("User")
team = models.ForeignKey("Team")
date = models.DateField()
start_time = models.TimeField()
end_time = models.TimeField()
pay_rate = models.CharField(max_length=30)
location = models.CharField(max_length=50)
Note the following:
You don't need to have a primary key field in the models because Django adds a primary key field called pk or id automatically.
Note the absence of the User Belongs To model. Django implements join-tables like User Belongs To automatically when you use a ManyToManyField. See the Django docs on many-to-many relationships.
You also don't need on_delete = models.CASCADE on ForeignKey fields, because this is the default behavior.
To see how to get information about users, teams and schedule from this configuration of models, consult the Django documentation on making db queries. It's quite easy.
I am defining some models for an inventory / work order application I am developing and I've run into a slight sticking point.
Here are some of the models that I'm currently having some difficulty with.
#models.py
from django.db import models
class Staff(models.Model):
ROLE = (
('M', 'Mechanic'),
('W', 'Warehouse'),
)
first_name = models.CharField(max_length=25)
last_name = models.CharField(max_length=25)
staff_role = models.CharField(max_length=1, choices=ROLE)
class WorkOrder(models.Model):
item_number = models.ForeignKey(Item)
date_started = models.DateField()
date_ended = models.DateField()
mechanic = models.ForeignKey(Staff)
What I would like is for a work order to only be associated with a staff member whose role is set as "Mechanic". Is there a way to restrict this within the model specification based on the models that I have here, or should I deal with this downstream when I set up the views and the forms?
Use the limit_choices_to parameter to ForeignKey:
mechanic = models.ForeignKey(Staff, limit_choices_to={'staff_role': 'M'})