Let's say there is a model with default ordering described in Meta class
class People(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
middle_name = models.CharField(max_length=100)
class Meta:
ordering = (last_name, first_name)
Is there are a way to get unordered queryset
You can just override by simply adding .order_by()
for example:
People.objects.all().order_by()
This will make sure that Meta ordering is overridden.
Using an empty order_by() worked for queries with filters.
BUT asking for the .first() element was problematic and always resulted in ORDER BY.
To overcome this what I did was a little bit ugly:
People.objects.all().order_by()[:1].values_list(...)[0]
This effectively removes the ORDER BY, and avoids the problem that asking for [:1][0] where it would get optimized and add it anyway. At the moment I don't know about other workarounds, but I'd love to hear them. I tried doing the above code without the values_list, but in that case Django always tried to perform the Order By.
Related
i am using Django along with DRF, and I am using many tables and complex relationships,
using soft delete (that is only marked deleted_at and not actually deleting anything) on my models from the begging didn't hurt much, but now we are making some new changes and deleted instances are growing.
so unique db constraints started giving errors, I know and implemented two possible solutions, one is unique_together in metaclass, with deleted at and every other unique value,
the other is:
class Meta:
constraints = [UniqueConstraint(fields=["name"], condition=Q(deleted_at != True))]
yet what I want is quite different, I want to avoid repeating all this and create a flag of uniqueness like this:
something_id = models.CharField(null=False, blank=False,
max_length=256, unique_undeleted=True)
notice the unique_undeleted parameter,
i know doing this directly requires changes in the library which is obviously bad,
but i have a parent model that i use in all others,
i thought of making a customized Constructor that will check every unique value, and make the unique on condition addition, or i could use this also
class MySpecialModel(parentModel):
somethingboolean= models.BooleanField(default=True, null=False)
something_id = models.CharField(null=False, blank=False,
max_length=256)
something_unique_too = models.CharField(null=False, blank=False,
max_length=256)
unique_undeleted_fields = ["something_id", "something_unique_too""]
and iterate in the parent model and create the UniqueConstraint for each field,
yet that does not feel right!
any guidance will be appreciated.
I have following model:
class Completion(models.Model):
date_completed = models.DateTimeField(auto_now=False, auto_now_add=False)
related_task = models.ForeignKey(Task, on_delete=models.CASCADE)
I need to check that each Completion have unique date (not datetime - only the date) for each Task (which is Completion's related field). In other words, I need something like this:
class Meta:
unique_together = [
'date_completed__date',
'related_task'
]
I know it does not work this way (and should not), so I would like to ask, how can I achieve the desired result (if it is possible altogether).
One way would be to add a new attribute to hold just a DateField and use it for the constraint. I recognize that doesn't do exactly what you ask, and would require allowing nulls first, converting current datetime values for the date only field but depending where you are with this process it may be feasible. As I understand, the uniqueness is enforced at the database level and a function to strip off the time probably isn't going to work.
In the unique_together section
the appropriate UNIQUE statements are included in the CREATE TABLE
statement
As a side note, the documentation suggests using UniqueConstraint as
Use UniqueConstraint with the constraints option instead.
UniqueConstraint provides more functionality than unique_together.
unique_together may be deprecated in the future.
I've looked through Tastypie's documentation and searched for a while, but can't seem to find an answer to this.
Let's say that we've got two models: Student and Assignment, with a one-to-many relationship between them. The Assignment model includes an assignment_date field. Basically, I'd like to build an API using Tastypie that returns Student objects sorted by most recent assignment date. Whether the sorting is done on the server or in the client side doesn't matter - but wherever the sorting is done, the assignment_date is needed to sort by.
Idea #1: just return the assignments along with the students.
class StudentResource(ModelResource):
assignments = fields.OneToManyField(
AssignmentResource, 'assignments', full=True)
class Meta:
queryset = models.Student.objects.all()
resource_name = 'student'
Unfortunately, each student may have tens or hundreds of assignments, so this is bloated and unnecessary.
Idea #2: augment the data during the dehydrate cycle.
class StudentResource(ModelResource):
class Meta:
queryset = models.Student.objects.all()
resource_name = 'student'
def dehydrate(self, bundle):
bundle.data['last_assignment_date'] = (models.Assignment
.filter(student=bundle.data['id'])
.order_by('assignment_date')[0].assignment_date)
This is not ideal, since it'll be performing a separate database roundtrip for each student record. It's also not very declarative, nor elegant.
So, is there a good way to get this kind of functionality with Tastypie? Or is there a better way to do what I'm trying to achieve?
You can sort a ModelResource by a field name. Check out this part of the documentation http://django-tastypie.readthedocs.org/en/latest/resources.html#ordering
You could also set this ordering by default in the Model: https://docs.djangoproject.com/en/dev/ref/models/options/#ordering
I have two models Category and Entry. There is another model ExtEntry that inherits from Entry
class Category(models.Model):
title = models.CharField('title', max_length=255)
description = models.TextField('description', blank=True)
...
class Entry(models.Model):
title = models.CharField('title', max_length=255)
categories = models.ManyToManyField(Category)
...
class ExtEntry(Entry):
groups= models.CharField('title', max_length=255)
value= models.CharField('title', max_length=255)
...
I am able to use the Category.entry_set but I want to be able to do Category.blogentry_set but it is not available. If this is not available,then I need another method to get all ExtEntryrelated to one particular Category
EDIT
My end goal is to have a QuerySet of ExtEntry objects
Thanks
I need another method to get all ExtEntryrelated to one particular Category
Easy:
ExtEntry.objects.filter(categories=my_category)
Do you know if there is a way to use the _set feature of an inherited
I don't know if there is a direct they for that. It is not mentioned in documentation.
But it is possible to get similar results with the select_related.
for e in category.entry_set.select_related('extentry'):
e.extentry # already loaded because of `select_related`,
# however might be None if there is no Extentry for current e
It is possible to select only entries which has ExtEntry:
for e in category.entry_set.select_related('extentry').exlude(extentry=None):
e.extentry # now this definitely is something, not None
Bad thing about the exclude is that it generates terrybly inefficient query:
SELECT entry.*, extentry.* FROM entry
LEFT OUTER JOIN `extentry` ON (entry.id = extentry.entry_ptr_id)
WHERE NOT (entry.id IN (SELECT U0.id FROM entry U0 LEFT OUTER JOIN
extentry U1 ON (U0.id = U1.entry_ptr_id)
WHERE U1.entry_ptr_id IS NULL))
So my resume would be: use ExtEntry.objects.filter() to get your results. The backwards relations (object.something_set) is just a convenience and does not work in every situation.
See the documentation here for an explanation of how this works.
Basically, since you can get the parent model item, you should be able to get its child because an implicit one-to-one linkage is created.
The inheritance relationship introduces links between the child model and each of its parents (via an automatically-created OneToOneField).
So, you should be able to do:
categories = Category.objects.all()
for c in categories:
entries = c.entry_set.all()
for e in entries:
extentry = e.extentry
print extentry.value
It isn't documented that I can see, but I believe that generally, your one-to-one field name will be a lower class version of the inheriting model name.
The problem your running into is because Entry and ExtEntry are in separate tables. This may be the best solution for you, but you should be aware of that when you choose to use multi-table inheritance.
Something like category.entry_set.exclude(extentry=None) should work for you.
When getting members based on Unit, I only want to get the ones who are actually in that unit as of now.
I've got a model looking like this:
class Member(models.Model):
name = models.CharField(max_length=256)
unit = models.ManyToManyField(Unit, through='Membership')
class Membership(models.Model):
member = models.ForeignKey(Member)
unit = models.ForeignKey(Unit)
start = models.DateField(default=date.today)
stop = models.DateField(blank=True, null=True)
class Unit(models.Model):
name = models.CharField(max_length=256)
As you can see, members can have a "fake" membership in unit, that is only history and should not be considered in the searches and listings of the admin. They should be shown in the change-page for a single object though.
The admin looks like this:
class MembershipInline(admin.TabularInline):
model = Membership
extra = 1
class MemberAdmin(admin.ModelAdmin):
list_filter = ('unit',)
inlines = [MembershipInline,]
So how can I (if at all possible this way), when filtering on unit only get those units whose membership__stop__isnull=True?
I tried Managers, I can make them work on the model in the admin itself, but not on the filtering/searches. There is also a def queryset(self) method that is overrideable, but I can't wrap my head around how to use it to fix my problem.
Edit, how this is used: A member has only one membership in a unit, however, they could be members from before, but they are ended (with stop). So I only want to filter (and show, in the list view) those members who have an open-ended membership (like, that they are members of that unit now).
Any ideas?
So you're trying to get the members of a specific Unit, right?
unit = Unit.objects.select_related().get(id=some_id)
This will pull the unit out of the database for you, along with the Memberships and Users that belong to it. You can access and filter the users by:
for member in unit.membership__set.filter(stop__isnull=True):
print member.name
I hope this helps? I may be wrong, I haven't tested this.
One way to certainly achieve this is by adding a denormalized field for
has_open_ended_membership.
To do this just add a BooleaneField like that to the Member and make sure it's consistent.
From the django documentation this seems to be the only way without writing specialized code in the ModelAdmin object:
Set list_filter to activate filters in
the right sidebar of the change list
page of the admin. This should be a
list of field names, and each
specified field should be either a
BooleanField, CharField, DateField,
DateTimeField, IntegerField or
ForeignKey.
I'm curious about other approaches - list_filter certainly is limited.
I fixed it with putting in a denormalized field in member, with a foreign-key to the active unit. Then, to make it work and be automatically updated in the admin, I made the specialized save-function for Membership.
class Member(models.Model):
name = models.CharField(max_length=256)
unit = models.ManyToManyField(Unit, through='Membership')
unit_denorm = models.ForeignKey(Unit)
class Membership(models.Model):
member = models.ForeignKey(Member)
unit = models.ForeignKey(Unit)
start = models.DateField(default=date.today)
stop = models.DateField(blank=True, null=True)
def save(self, *args, **kwargs):
if not self.stop:
self.member.unit_denorm = self.unit
self.member.save()
super(Membership, self).save(*args, **kwargs)
class Unit(models.Model):
name = models.CharField(max_length=256)
And with list_filter = ('unit_denorm',) in the admin, it does exactly what I want.
Great! Of course, there should only be one field with stop__isnull=True. I haven't figured out how to make that restriction. but people using the system know they shouldn't do that anyway.