Selecting only active records django query - python

In my Django project, I have an is_active boolean column in every table of my database. Every time I or the framework accesses the database, I want only the active records to show up. What is the standard way to achieve this? Certainly I don't want to check for is_active in every queries I make.

The easiest way to do this is to create a custom model manager, like this:
class OnlyActiveManager(models.Manager):
def get_queryset(self):
return super(OnlyActiveManager, self).get_queryset().filter(is_active=True)
Then, add it to your models:
class MyModel(models.Model):
objects = models.Manager()
active = OnlyActiveManager()
Next, use it like this:
foo = MyModel.active.all()
You can also use it to replace the default manager (called objects), but then you'll have to do custom queries to get all records that are in-active.

You can write a manager class for your model, A sample model manager is given below, for more you can refer Django official website
class MediaManager(models.Manager):
def get_queryset(self):
return MediaQuerySet(self.model, using=self._db)
def active(self):
return self.filter(is_active=True)
class Media(models.Model):
(..model fields..)
objects = MediaManager()
The query should be like
media = Media.objects.active()

you can do it by using django model managers.
please check django documentaion for detail django documentaion

Related

Django Queryset Design: Filtering out soft-deleted users?

I have a soft-delete user model in Django, where we set is_active to False.
But one problem I'm running into is needing to filter out is_active users on every type of content:
Item.objects.filter(user__is_active=False, ...)
Comment.objects.filter(user__is_active=False, ...)
User.objects.filter(is_active=False, ...)
And so-on. Is there some type of Django / Pythonic design pattern I can use here to avoid needing to manually filter out all users every time I query something made by a user, or a current list of users?
https://docs.djangoproject.com/en/4.0/topics/db/managers/
You need to use custom managers and add to model.
You can redefine get_queryset method to filter is_active.
You can use ModelManager.
For example:
class ItemManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(is_active=True)
class Item(models.Model):
.....
objects = ItemManager() # your custom manager
all_objects = models.Manager() # default manager
Now with Item.objects.all() you will get objects having is_active=True only.
If you want all the objects then you can use Item.all_objects.all()

Prefetch object not working with order_by queryset

Using Django 11 with PostgreSQL db. I have the models as shown below. I'm trying to prefetch a related queryset, using the Prefetch object and prefetch_related without assigning it to an attribute.
class Person(Model):
name = Charfield()
#property
def latest_photo(self):
return self.photos.order_by('created_at')[-1]
class Photo(Model):
person = ForeignKey(Person, related_name='photos')
created_at = models.DateTimeField(auto_now_add=True)
first_person = Person.objects.prefetch_related(Prefetch('photos', queryset=Photo.objects.order_by('created_at'))).first()
first_person.photos.order_by('created_at') # still hits the database
first_person.latest_photo # still hits the database
In the ideal case, calling person.latest_photo will not hit the database again. This will allow me to use that property safely in a list display.
However, as noted in the comments in the code, the prefetched queryset is not being used when I try to get the latest photo. Why is that?
Note: I've tried using the to_attr argument of Prefetch and that seems to work, however, it's not ideal since it means I would have to edit latest_photo to try to use the prefetched attribute.
The problem is with slicing, it creates a different query.
You can work around it like this:
...
#property
def latest_photo(self):
first_use_the_prefetch = list(self.photos.order_by('created_at'))
then_slice = first_use_the_prefetch[-1]
return then_slice
And in case you want to try, it is not possible to use slicing inside the Prefetch(query=...no slicing here...) (there is a wontfix feature request for this somewhere in Django tracker).

How to change the default model manager (queryset?) for filters

I want to change the default model manager of django rest framework filter and I can't seem to find a way to do it. My default model manager objects excludes some records, I have created objects_all for getting all records. filter seems to be using Model.objects instead of objects_all, is there a way I can somehow make it use objects_all so that filtering is possible.
filters.py
import rest_framework_filters as filters
ItemFilter(filters.FilterSet):
name = filters.AllLookupsFilter()
some_id = filters.NumberFilter(name="some_name")
class Meta:
model = Item
models.py
class myModel(models.Model):
objects_all = models.Manager() # Rename the default model manager
objects = ObjectsWithNoStateManager()
objects_deleted = ObjectsDeletedManager()
objects_archived = ObjectsArchivedManager()
It seems like you need to add extra filter to your ModelManager. Why don't you just add methods for that extra filter in single ModelManager rather than creating separate manager for each.
Here is the example https://docs.djangoproject.com/en/1.9/topics/db/managers/#adding-extra-manager-methods

Django model class inheritance with non managed classes

I have a simple REST API that I would like to use Django and the DJANGO REST Framework for. To start I need to connect to 2 different remote databases and get a recordset of unique countries from each. I would then like to combine those record-sets into one model class. I would like to keep each recordset in a separate classes for use in other areas of the API.
I have tried using Model class inheritance but I have not been able to get that to work with non managed tables. This is the latest version of the Model.
class CountryA(models.Model):
Country = models.CharField(db_column='field_country_country_value',primary_key = True, max_length=255)
class Meta:
abstract = True
managed = False
class CountryB(models.Model):
Country = models.CharField(primary_key = True, max_length=255)
class Meta:
abstract = True
managed = False
class CombinedCountries(ACountry,BCountry):
class Meta:
managed = False
Django still seems to look for a local table for CombinedCountires. I've also tried as a Proxy table without abstraction but it then looks for mcapi.content_field_country_country the field from CountryA as the table name. I'm sure there must be a way to do this in the Model with remote tables but it's obviously not a common use case.
I think a better solution for your problem will be to chain results from both models and use the final result as input list for API.
How to combine 2 or more querysets in a Django view?

Django models and Python properties

I've tried to set up a Django model with a python property, like so:
class Post(models.Model):
_summary = models.TextField(blank=True)
body = models.TextField()
#property
def summary(self):
if self._summary:
return self._summary
else:
return self.body
#summary.setter
def summary(self, value):
self._summary = value
#summary.deleter
def summary(self):
self._summary = ''
So far so good, and in the console I can interact with the summary property just fine. But when I try to do anything Django-y with this, like Post(title="foo", summary="bar"), it throws a fit. Is there any way to get Django to play nice with Python properties?
Unfortunately, Django models don't play very nice with Python properties. The way it works, the ORM only recognizes the names of field instances in QuerySet filters.
You won't be able to refer to summary in your filters, instead you'll have to use _summary. This gets messy real quick, for example to refer to this field in a multi-table query, you'd have to use something like
User.objects.filter(post___summary__contains="some string")
See https://code.djangoproject.com/ticket/3148 for more detail on property support.

Categories