I need to write a single django query such that I'm able to display the "status, date, time, job_name, sol_name and dept_name"
so that a rest api is created.
Model classes
class Job_Report(models.Model):
id:models.BigAutoField(primary_key=True)
job_id: models.ForeignKey(Job, models.DO_NOTHING)
status:models.CharField(max_length=7)
date: models.DateField()
time: models.TimeField()
duration = models.BigIntegerField(blank=True, null=True)
class Job(models.Model):
id:models.BigAutoField(primary_key=True)
name:models.CharField(max_length=500)
folder_id:models.ForeignKey(Job_folder, models.DO_NOTHING)
class Job_folder(models.Model):
id:models.BigAutoField(primary_key=True)
repo_id:models.ForeignKey(Sol_folder, models.DO_NOTHING)
class Sol_folder(models.Model):
id:models.BigAutoField(primary_key=True)
sol_id:models.ForeignKey(Solution, models.DO_NOTHING)
class Solution(models.Model):
id:models.BigAutoField(primary_key=True)
name:models.CharField(max_length=500)
dep_id:models.ForeignKey(Department, models.DO_NOTHING)
class Department(models.Model):
id:models.BigAutoField(primary_key=True)
dept_name:models.CharField(max_length=500)
I tried using
query_set=Job_Folder.objects.raw('select Job_Folder.status,Job_Folder.date,Job_Folder.time,Job.name,Department.name,Solution.name from Job_Folder,Job,Solution')`
but resulted in error.
Any help would be appreciated.
If you are using Django Rest Framework, then it is easy to define the computed values in serializer:
No need to make a query in SQL
Just follow the steps:
Create Serializer of Job_Report model.
class Job_ReportSerializer(serializers.ModelSerializer):
job = serializers.SerializerMethodField()
sol = serializers.SerializerMethodField()
dept = serializers.SerializerMethodField()
class Meta:
model = Job_Report
fields = '__all__'
def get_job(self, obj):
# 'get_' + 'attribute-name' to give definition
return obj.job.job_name
def get_sol(self, obj):
return obj.job.folder.sol.sol_name
.
.
.
# Define for all SerializerMethodField
Follow this for more info about DRF (Django REST Framework) https://www.django-rest-framework.org/tutorial/quickstart/
You'll take hardly 2 hours to complete the tutorial, but trust me it'll save your days of work.
Let me know if you want a solution without DRF.
models.py
All your models as you defined,
Just make one change:
- Do not use ids. Just use foreign keys.
class Job_Report(models.Model):
job: models.ForeignKey(Job, models.DO_NOTHING)
status:models.CharField(max_length=7)
date: models.DateField()
time: models.TimeField()
duration = models.BigIntegerField(blank=True, null=True)
class Job(models.Model):
name:models.CharField(max_length=500)
folder:models.ForeignKey(Job_folder, models.DO_NOTHING)
class Job_folder(models.Model):
name:models.CharField()
repo:models.ForeignKey(Sol_folder, models.DO_NOTHING)
class Sol_folder(models.Model):
name:models.CharField(max_length=500)
sol:models.ForeignKey(Solution, models.DO_NOTHING)
class Solution(models.Model):
name:models.CharField(max_length=500)
dept:models.ForeignKey(Department, models.DO_NOTHING)
class Department(models.Model):
name:models.CharField(max_length=500)
Serializers.py
class Job_ReportSerializer(serializers.ModelSerializer):
job = serializers.SerializerMethodField()
sol = serializers.SerializerMethodField()
dept = serializers.SerializerMethodField()
class Meta:
model = Job_Report
fields = '__all__'
def get_job(self, obj):
# 'get_' + 'attribute-name' to give definition
return obj.job.name
def get_sol(self, obj):
return obj.job.folder.sol.name
.
.
.
# Define for all SerializerMethodField
views.py
#api_view(['GET'])
def list_reports(request):
job_reports = Job_Report.objects.all()
data = JobReportSerializer(job_reports, many=True, context={'request':request}).data
return Response(data)
#api_view(['GET'])
def detail_report(request, pk):
job_report = Job_Report.objects.get(id=pk)
data = JobReportSerializer(job_report,context={'request':request}).data
return Response(data)
urls.py
Add Urls to the functional views
Boom!!! API is ready, don't forget to add 'rest_framework' in INSTALLED_APPS in settings.py
Related
Good day,
I would like to ask, if there's a possibility to gain additional data inside my serializers?
These are my models...
models.py
class Chair(models.Model):
name = models.CharField(max_length=100, null=False, blank=False, unique=True)
bookable = models.BooleanField(default=False)
user_created = models.CharField(max_length=100)
date_created = models.DateField(auto_now_add=True)
class Booking(models.Model):
chair = models.ForeignKey(Chair, on_delete=models.CASCADE)
day = models.DateField()
user_name = models.CharField(max_length=100)
user_created = models.CharField(max_length=100)
date_created = models.DateField(auto_now_add=True)
and these my serializers...
serializers.py
class BookingSerializer(serializers.ModelSerializer):
class Meta:
model = Booking
fields = '__all__'
class ChairSerializer(serializers.ModelSerializer):
class Meta:
model = Chair
fields = '__all__'
When making a request inside js like this...
views.py
#api_view(['GET'])
def bookings_by_date(request, pk):
bookings = Booking.objects.filter(day=pk)
serializer = BookingSerializer(bookings, many=True)
return Response(serializer.data)
script.js
let url = '...here's my url for Booking...';
fetch(url)
.then((resp) => resp.json())
.then(function(data) {
// do something here
});
...I would like to get not only the id of the Chair (models.Foreignkey), but also it's name. My first thought was doing something like this...
class ChairSerializer(serializers.ModelSerializer):
class Meta:
model = Chair
fields = [
...
'chair',
'chair__name',
...
]
...but this doesn't seem to work! Does anyone know a solution for my problem? Thanks for all your help and have a great weekend!
You can use one of this two ways:
1-) Using SerializerMethodField. You can add readonly fields with this way. You should add get_<field_name> method or give a method name that you want to run for this field with name keyword. You can look the document for more details.
class BookingSerializer(serializers.ModelSerializer):
chair__name = serializers.SerializerMethodField()
class Meta:
model = Booking
fields = '__all__'
def get_chair_name(self, obj):
return obj.chair.name
2-) Using CharField with source attribute:
You can define basically this field fill from where.
class BookingSerializer(serializers.ModelSerializer):
chair__name = serializers.CharField(source='chair__name')
class Meta:
model = Booking
fields = '__all__'
I just started to play with Django trying to make an API REST, for some reason that i don't understand i'm getting this error 'Workout' object has no attribute 'exercises' when i do GET - /workouts.
I'm using Django REST framework to make this thing.
This is part of my code that I think you need to help me:
serializers.py
class WorkoutSerializer(serializers.ModelSerializer):
exercises = serializers.StringRelatedField(many=True)
class Meta:
model = Workout
fields = ['id', 'name', 'creation_date', 'exercises']
class ExerciseSerializer(serializers.ModelSerializer):
class Meta:
model = Exercise
fields = ['url', 'video_url', 'workout']
models.py
class Workout(models.Model):
name = models.CharField(max_length=30)
creation_date = models.DateField(auto_now_add=True)
def __str__(self):
return self.name
class Exercise(models.Model):
video_url = models.URLField(max_length=200)
workout = models.ForeignKey(Workout, related_name='workout', on_delete=models.CASCADE)
def __str__(self):
return str(self.video_url)
views.py
class WorkoutViewSet(viewsets.ModelViewSet):
queryset = Workout.objects.all()
serializer_class = WorkoutSerializer
class ExerciseViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows exercises to be viewed or edited.
"""
queryset = Exercise.objects.all()
serializer_class = ExerciseSerializer
here is my models.py:
class Post(models.Model):
id = models.AutoField(primary_key=True)
body = models.TextField(max_length=10000)
date = models.DateTimeField(auto_now_add=True, blank=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
liked_by = models.ManyToManyField(User, blank=True, related_name='liked_by')
class Meta:
ordering = ['-date']
serializers.py:
class PostSerializer(serializers.ModelSerializer):
user = UserSerializers()
total_likes = serializers.SerializerMethodField()
total_comments = serializers.SerializerMethodField()
class Meta:
model = Post
fields = ('id','body','date','user','total_likes','total_comments')
def get_total_likes(self, instance):
return instance.liked_by.count()
def get_total_comments(self, instance):
return instance.comment_set.count()
Q1: how do i check if a user exists in ManyToManyField of a single post?
Q2: shouldn't i use ManyToManyField in drf? then which would be better?
I don't have enough reps to comment, but if you have a post instance and a user instance, you could do something like:
post.liked_by.filter(id=user.id).exists()
Does that help you or are you asking where you should be implementing this? e.g. in your view or serializer etc...
I have two models Tender and Status joined in a M2M relationship by a bridge table TenderStatus. The bridge table has an extra date field in it. I'm using an inline for the admin form. But I want to be able to display the date from the intermediary table in the admin view. I can access the name of the Status, so I can easily show a comma-separated list of statuses for example, but I cannot figure out how to access the date field. I've tried using a callable in the admin class to no avail (I think I just don't know how to access the date field from the callable). I also created a custom str function for TenderStatus, but it doesn't seem to pay attention to that. Here's the code I have so far:
models.py
class Tender(models.Model):
name = models.CharField(max_length=255)
tender_status = models.ManyToManyField(
'Status',
through='TenderStatus',
related_name='tender_status'
)
class Meta:
managed = False
db_table = 'tender'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def __str__(self):
return self.name
class TenderStatus(models.Model):
tender = models.ForeignKey('Tender', on_delete=models.DO_NOTHING, blank=True, null=False)
status = models.ForeignKey('Status', on_delete=models.DO_NOTHING, null=False,)
date = models.DateField(blank=True, null=False)
def __str__(self):
return str(self.date) + ': ' + str(self.status)
class Meta:
managed = False
db_table = 'tender_status'
class Status(models.Model):
status = models.CharField(max_length=50)
short_name = models.CharField(max_length=5)
class Meta:
managed = False
db_table = 'status'
def __str__(self):
return str(self.status)
admin.py
class TenderAdmin(admin.ModelAdmin, ExportCsvMixin):
list_display = ['name', 'status_list']
def status_list(self, obj):
# I BELIEVE THIS IS THE ELEMENT I NEED HELP WITH, HOW TO CALL THE DATE HERE
# THE FOLLOWING DOES NOT WORK
return [str(x.date) + ': ' + x.status for x in obj.tender_status.all()]
class Meta:
model = 'Tender'
Note: My app does not use custom views, it only uses the admin models. I do not have the option to add custom views, as the organization will not permit it.
Edit: To clarify, I'm looking for a way to list out the statuses + dates in a string formatted way in the list_display, using only what is available in django-admin.
I want to get all customer data and responses and also remarks.
This is model.py
class Customer(models.Model):
name = models.CharField(max_length=200)
email_address = models.CharField(max_length=200)
phone_number = models.CharField(max_length=20)
age = models.SmallIntegerField(default=14)
remarks = models.ManyToManyField(Remark,null=True,blank=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.id)
class Response(models.Model):
question = models.ForeignKey(Question)
customer = models.ForeignKey(Customer)
response_text = models.CharField(max_length=100, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
uuid = models.UUIDField()
def __str__(self):
return str(self.id)
This is serializers.py
class ResponseSerializer(ModelSerializer):
class Meta:
model = Response
fields = '__all__'
class RemarksSerializer(ModelSerializer):
class Meta:
model = Remark
fields = '__all__'
class CustomerInformationSerializer(ModelSerializer):
remarks = RemarksSerializer(many=True)
responses = serializers.SerializerMethodField()
def get_responses(self, obj):
responses = Response.objects.filter(customer=obj)
return ResponseSerializer(responses, many=True)
class Meta:
model = Customer
fields = ('name', 'email_address', 'phone_number', 'age', 'remarks', 'responses')
This is services.py
def customer_information(company_id=1):
cus = Customer.objects.filter(remarks__company_id=company_id)
return CustomerInformationSerializer(cus, many=True).data
This is views.py
class CustomerInformationView(APIView):
def get(self, request):
company_id = request.GET.get('company_id', 1)
resp = {'data': customer_information(company_id)}
return Response(data=resp, status=status.HTTP_200_OK)
This is url.py
url(r'^customer/$', CustomerInformationView.as_view()),
I'm having this problem. How can I solve this. Kindly guide me.
get function in your view should return responses.data, insted of responsed.
SIDE NOTE
First, let me point you to a resource that I think is GREAT for anything dealing with Django REST Framework:
Classy Django REST Framework. It is a fantastic resource because you can easily dig right into the source code to see how you may or may not need to override default operations.
MY ANSWER
What I suggest is that instead of using the APIView, you use ListAPIView.
It would look something like this:
from rest_framework.generics import ListAPIView
class Customer(models.Model):
name = models.CharField(max_length=200)
email_address = models.CharField(max_length=200)
phone_number = models.CharField(max_length=20)
age = models.SmallIntegerField(default=14)
remarks = models.ManyToManyField(Remark,null=True,blank=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.id)
class Response(models.Model):
question = models.ForeignKey(Question)
customer = models.ForeignKey(Customer, related_name='responses')
response_text = models.CharField(max_length=100, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
uuid = models.UUIDField()
def __str__(self):
return str(self.id)
class ResponseSerializer(ModelSerializer):
class Meta:
model = Response
fields = '__all__'
class RemarksSerializer(ModelSerializer):
class Meta:
model = Remark
fields = '__all__'
class CustomerInformationSerializer(ModelSerializer):
remarks = RemarksSerializer(many=True)
responses = ResponseSerializer(many=True)
class Meta:
model = Customer
fields = ('name', 'email_address', 'phone_number', 'age', 'remarks', 'responses')
class CustomerInformationView(ListAPIView):
queryset = Customer.objects.all()
serializer_class = CustomerInformationSerializer
lookup_field = 'remarks__company'
Note the change that I made by adding related_name to the customer field on your Response model. See Django documentation for more information on related_name. In short, it adds responses as a field name on your Customer model so that you can travel backwards through that relationship.
This is not tested, but this should be a better strategy to do what you want without having to have a get_responses method, or a services.py.
Some there might be error because of missing "/" at the end of path like "event-api"=incorrect and "event-api/" correct. That worked for me. Hope you also have same problem.
Incorrect: path('event-api',views.event_view,name="event-view")
Correct: path('event-api/',views.event_view,name="event-view")