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')
Related
With the following models.py ...
from django.db import models
class Notebook(models.Model):
name = models.CharField(max_length=255)
class Entry(models.Model):
notebook = models.ForeignKey(Notebook, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
How would I write a filter to only return Notebook that have no Entry?
You can .filter(…) the Notebooks with:
Notebook.objects.filter(entry=None)
This works because Django makes a LEFT OUTER JOIN, and thus we only retain the records for which the entry primary key is NULL/None.
I am testing a method that requires me to create a fake record in my model. The model has over 40 fields. Is it possible to create a record with only the relevant model fields for the test so I don't have to populate the other fields? If so how would I apply it to this test case example.
models.py
class Contract():
company = models.CharField(max_length=255),
commission_rate = models.DecimalField(max_digits=100, decimal_places=2)
type = models.CharField(max_length=255)
offer = models.ForeignKey('Offer', on_delete=models.PROTECT)
notary = models.ForeignKey('Notary', on_delete=models.PROTECT)
jurisdiction = models.ForeignKey('Jurisdiction', on_delete=models.PROTECT)
active = models.BooleanField()
...
test.py
import pytest
from app.models import Contract
def calculate_commission(company, value):
contract = Contract.objects.get(company='Apple')
return value * contract.commission_rate
#pytest.mark.django_db
def test_calculate_commission():
#The only two model fields I need for the test
Contract.objects.create(company='Apple', commission_rate=0.2)
assert calculate_commission('Apple', 100) == 20
Try to use model_bakery to make an object record. Just populate fields you want and leave another blank, model_bakery will handle it. For the Detail, you can check this out model_bakery
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']
]
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.
I'm trying to be able to alias a column name from a model's foreign key. I want to be able to change 'owner__username' to just 'username' when passing a JSON response.
query_n = Example.objects.values('owner__username','name')
print(query_n[0])
Which prints
{'name': 'e_adam', 'owner__username': 'adam'}
The only renaming of a column I have seen was via annotate() however, that isn't even truly a column (AVG, SUM, ...)
The Example model has a foreign key owner, which is 'auth.User' model.
Any thoughts?
I'm not too sure about this but if you are using django >= 1.7, sounds like you could use annotate to create alias for named arguments in values(). I found a related django ticket, to quote from the latest response:
Just quickly, with the changes to annotate that have landed, it is now
possible to create aliases yourself, and reference them from the
values call:
from django.db.models import F
Model.objects.annotate(my_alias=F('some__long__name__to__alias')) \
.values('my_alias')
aliasName = models.ForeignKey(modelName, to_field='fieldName', on_delete=models.CASCADE)
This is the format for aliasing in Django Foreign Key
Here is full Models page
from django.db import models
# Create your models here.
class Farm(models.Model):
srFarm = models.AutoField(primary_key=True)
name = models.CharField(max_length = 264, unique =True)
address = models.CharField(max_length = 264)
def __str__(self):
temp = '{0.name},{0.address}'
return temp.format(self)
class Batch(models.Model):
srBatch = models.AutoField(primary_key=True)
farmName = models.ForeignKey(Farm, to_field='name', on_delete=models.CASCADE)
def __str__(self):
temp = '{0.farmName}'
return temp.format(self)