django rest framework an always sorting field - django

I want to have a fixed sorting field applied to all custom sortings. To be more specific imagine we have a list of employees, if user choose this form be sorted by hire_date, I want the result be sorted by hire_date and employee_id together. I mean each ordering should be ordered by employee_id inside! For example if we have 5 employees hired today, if hire_date is the sorting field, these 5 be sorted by employee_id and for the other days the same story.
using the following is not the cure. It only sorts them on employee_id when no ordering is set:
queryset = models.Employee.objects.order_by('id')
And this one's result is same as previous:
filter_backends = (CustomFilterSetBackend, filters.OrderingFilter)
custom_filters = (
........
)
ordering_fields = (............)
ordering = ('id',)
tnx a million

In model add this:
class Employee(models.Model):
......
......
class Meta:
ordering = ['-hire_date','employee_id']
It will order by hire_date and if dates are same then employee_id.

Same problem i had got back while working so , there are few solutions you can adopt ,
In your Employee model class you can do these ,
from __future__ import unicode_literals
from django.db import models
class Employee(models.Model):
....
....
class Meta:
# Latest by hire_date ascending, employee_id ascending.
ordering = ['hire_date', 'employee_id']
And also you can do some thing like these at query end ,
from your_app.models import Employee
queryset = models.Employee.objects.order_by('employee_id')
Third solution can be combined form of first two solutions as i mentioned and as you described in comment that can be like ,
from __future__ import unicode_literals
from django.db import models
class Employee(models.Model):
....
....
class Meta:
# Latest by hire_date ascending, employee_id ascending.
ordering = ['employee_id']
Now when you fetch employee you should do these ,
(i am assuming these from views.py file)
from your_app.models import Employee
queryset = models.Employee.objects.order_by('hire_date')
Let me know if any problem in third approach.

Related

Order queryset using the number of related objects in Django

Let's say I have the following in models.py:
class A(models.Model):
...
class B(models.Model):
a = models.ForeignKey(A, on_delete=models.CASCADE)
What I want to do is sort a queryset for A based on how many B objects they have, in descending order. What is the best approach to this issue? Thanks for any help.
You can work with a .annotate(…) [Django-doc] and then .order_by(…) [Django-doc]:
from django.db.models import Count
A.objects.annotate(
nb=Count('b')
).order_by('-nb')
Since django-3.2 you can work with .alias(…) [Django-doc] to prevent calculating this both as column and in the ORDER BY clause:
from django.db.models import A
A.objects.alias(
nb=Count('b')
).order_by('-nb')
This is:
queryset = A.objects.filter().order_by('B_A')
Here 'B_A' you have to put the related name
class A(models.Model):
...
class B(models.Model):
a = models.ForeignKey(A, on_delete=models.CASCADE, related_name = 'B_A')

I want add two annotation for two foreign keys using Django. How do I do this?

# models.py
from django.db import models
class Elephant(models.Model):
location = models.ForeignKey(Location, on_delete=models.CASCADE)
families = models.ForeignKey(Families, on_delete=models.CASCADE)
def add_families_and_locations_counts(elephants):
return elephants.annotate(
families_number=Count('families'),
location_number=Count('location')
)
# Run
output = add_families_and_locations_counts(elephants)
In the above, the counts are incorrect. How do I get the correct counts?
You want to count the distinct foreign key model instances.
Update your annotations function to the below:
def add_families_and_locations_counts(elephants):
return elephants.annotate(
families_number=Count('families', distinct=True),
location_number=Count('location', distinct=True)
)

How to query by joining a Django Model with other, on a non unique column?

I have the following models in my models.py file in my django project
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.conf import settings
class CustomUser(AbstractUser):
pass
# add additional fields in here
class PDFForm(models.Model):
pdf_type=models.IntegerField(default=0)
pdf_name=models.CharField(max_length=100,default='')
file_path=models.FileField(default='')
class FormField(models.Model):
fk_pdf_id=models.ForeignKey('PDFForm', on_delete=models.CASCADE,default=0)
field_type=models.IntegerField(default=0)
field_page_number=models.IntegerField(default=0)
field_x=models.DecimalField(max_digits=6,decimal_places=2,default=0)
field_y=models.DecimalField(max_digits=6,decimal_places=2,default=0)
field_x_increment=models.DecimalField(max_digits=6,decimal_places=2,default=0)
class Meta:
ordering= ("field_page_number", "field_type")
class UserData(models.Model):
fk_user_id=models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,default=0)
field_type=models.IntegerField(default=0)
field_text=models.CharField(max_length=200,default='')
field_date=models.DateField()
Here is how the models are related
1) a pdfform contains a pdf form and path for it on the file system
2) A pdfform has multiple FormFields in it. Each field has attributes, and the specific one under discussion is field_type
3)The UserData model has user's data, so one User can have multiple rows in this table. This model also has the field_type column.
What I am trying to query is to find out all rows present in the Userdata Model which are present in the FormField Model ( matched with field_type) and that are of a specific PDFForm.
Given that the Many to Many relationship in django models cannot happen between no unique fields, how would one go about making a query like below
select a.*, b.* from FormField a, UserData b where b.fk_user_id=1 and a.fk_pdf_id=3 and a.field_type=b.field_type
I have been going through the documentation with a fine toothed comb, but obviously have been missing how django creates joins. what is the way to make the above sql statement happen, so I get the required dataset?
I think UserData is missing a relation to FormField, but if you had this relation you could do:
UserData.objects.filter(
fk_user_id=1, # Rename this to user, Django wilt automicly create a user_id column
form_field__in=FormField.objects.filter(
fk_pdf_id=<your pdfid> # same as fk_user_id
)
)
Edit updated models
When you use a ForeignKey you don't have to specify the _id or default=0, if you don't always want to fill the field its better to set null=True and blank=True
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.conf import settings
class CustomUser(AbstractUser):
pass
# add additional fields in here
class FieldTypeMixin:
TYPE_TEXT = 10
TYPE_DATE = 20
TYPE_CHOISES = [
(TYPE_TEXT, 'Text'),
(TYPE_DATE, 'Date'),
]
field_type=models.IntegerField(default=TYPE_TEXT, choises=TYPE_CHOISES)
class PDFForm(models.Model):
pdf_type = models.IntegerField(default=0)
pdf_name = models.CharField(max_length=100,default='')
file_path = models.FileField(default='')
class FormField(models.Model, FieldTypeMixin):
pdf_form = models.ForeignKey('PDFForm', on_delete=models.CASCADE)
field_page_number = models.IntegerField(default=0)
field_x = models.DecimalField(max_digits=6,decimal_places=2,default=0)
field_y = models.DecimalField(max_digits=6,decimal_places=2,default=0)
field_x_increment = models.DecimalField(max_digits=6,decimal_places=2,default=0)
class Meta:
ordering = ("field_page_number", "field_type")
class SubmittedForm(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE)
pdf_form = models.ForeignKey(PDFForm, models.CASCADE)
class SubmittedFormField(models.Model, FieldTypeMixin):
submitted_form = models.ForeignKey(SubmittedForm, models.CASCADE)
form_field = models.ForeignKey(FormField, models.CASCADE, related_name='fields')
field_text = models.CharField(max_length=200,default='')
field_date = models.DateField()
class Meta:
unique_together = [
['submitted_form', 'form_field']
]

Can conditions apply on filtering results using django-filters?

How can I apply conditions of filtering results using django-filters
For example I have a field say 'Bookscount' having integer values and if user opts for value > 5 then django-filter displays all those books having 'Bookscount' > 5
import django_filters as df
from .models import Books
class BooksListFilter(df.FilterSet):
class Meta:
model = Books
fields = ['Bookscount']
You either need to declare the filter, or generate it with Meta.fields
class BooksListFilter(df.FilterSet):
min_books = df.NumberFilter(field_name='Bookscount', lookup_expr='gte')
# or
class BooksListFilter(df.FilterSet):
class Meta:
model = Books
fields = {'Bookscount': ['gt']}

Django date query from newest to oldest

I am building my first Django program from scratch and am running into troubles trying to print out items to the screen from newest to oldest.
My model has an auto date time field populated in the DB as so:
Model
from django.db import models
from django.contrib.auth.models import User
from django.conf import settings
from django.utils import timezone
class TaskItem(models.Model):
taskn = models.CharField(max_length = 400)
usern = models.ForeignKey(User)
#Created field will add a time-stamp to sort the tasks from recently added to oldest
created_date = models.DateTimeField('date created', default=timezone.now)
def __str__(self):
return self.taskn
What is the line of code that would be abel to sort or print this information in order from newest creation to oldest?
Want to implement it into this call:
taskitems2 = request.user.taskitem_set.all().latest()[:3]
ordered_tasks = TaskItem.objects.order_by('-created_date')
The order_by() method is used to order a queryset. It takes one argument, the attribute by which the queryset will be ordered. Prefixing this key with a - sorts in reverse order.
By the way you also have Django's created_at field at your disposal:
ordered_tasks = TaskItem.objects.order_by('-created_at')
You can set your ordering in model Meta class. This will be the default ordering for the object,for use when obtaining lists of objects.
class TestModel(models.Model):
...
created_at = models.DateField()
....
class Meta:
ordering = ['-created_at']
Or you can apply ordering to specific queryset.
TestModel.objects.order_by('-created_at')