Custom properties in a query - django

Given the simplified example below, how would I access my custom "current_status" property within a queryset? Is it even possible?
At the moment, I want to list the all the current Events and show the current status. I can get the property to display in a template ok, but I can't order the queryset by it. Alternatively, would I need to create a custom manager with some kind of nested "if" statement in the 'Select'?
class Event(models.Model):
....
date_registered = models.DateField(null=True, blank=True)
date_accepted = models.DateField(null=True, blank=True)
date_reported = models.DateField(null=True, blank=True)
...
def _get_current_status(self):
...
if self.date_reported:
return "Reported"
if self.date_accepted:
return "Accepted"
if self.date_registered:
return "Registered"
if self.date_drafted:
return "Drafted"
current_status = property(_get_current_status)

Instead of calculating the status as a property, create a proper model field for it and update it in the save method. Then you can use that field directly in the query.

You cannot use a custom property in query, since Django's ORM will try to map it to a database column and fail. Of course you can use it in an evaluated queryset, e.g. when you're iterating about the objects of a query's results!
You can only filter for things like: Event.objects.filter(date_drafted__isnull=False).
http://docs.djangoproject.com/en/dev/ref/models/querysets/#isnull

Thanks to Daniel. I think that I might use your approach. However, I also managed to get it working using the queryset 'extra' method, which might also be useful to other people, although its probably isn't database agnostic.
qs = Event.objects.extra(select={'current_status_id':
'''(CASE
WHEN date_cancelled THEN 0
WHEN date_closed THEN 6
WHEN date_signed_off THEN 5
WHEN date_reported THEN 4
WHEN date_accepted THEN 3
WHEN date_registered THEN 2
WHEN date_drafted THEN 1
ELSE 99
END)
'''})

Related

django distinct query using custom equivalence

Say that my model looks like this:
class Alert(models.Model):
datetime_alert = models.DateTimeField()
alert_type = models.ForeignKey(Alert_Type, on_delete=models.CASCADE)
dismissed = models.BooleanField(default=False)
datetime_dismissed = models.DateTimeField(null=True)
auid = models.CharField(max_length=64, unique=True)
entities = models.ManyToManyField(to='Entity', through='Entity_To_Alert_Map')
objects = Alert_Manager()
def __eq__(self, other):
return isinstance(other,
self.__class__) and self.alert_type == other.alert_type and \
self.entities.all() == other.entities().all() and self.dismissed == other.dismissed
def __ne__(self, other):
return not self.__eq(other)
what I'm trying to accomplish is say this: two alert objects are equivalent if the dismissed status, alert type, and the associated entities are the same. Using this idea, is it possible to write a query to ask for all the distinct alerts based off that criteria? Selecting all of them and then filtering them out doesn't seem appealing.
You mention one method to do it, and I don't think it is very bad. I'm not aware of anything in Django that can do this.
However, I want you to think why this problem arises? If two alerts are equal if message, status and type is the same, then maybe this should be it's own class. I would consider creating another class DistinctAlert (or some better name) and have a foreign key to this class from Alert. Or even better, have one class that is Alert, and one that is called AlertEvent(your Alert class).
Would this solve your problem?
Edit:
Actually, there is a way to do this. You can combine values() and distinct(). This way, your query will be
Alert.objects.all().values("alert_type", "dismissed", "entities").distinct()
This will return a dictionary.
See more in the documentation of values()

Extracting Object values from a Queryset without a for loop

I have a model called
class UserTag(models.Model):
name = models.CharField(max_length=64, unique= True)
users = models.ManyToManyField(User)
I am trying to filter its contents based on the user like this
usertags = UserTag.objects.filter(users=request.user)
now I want a list of all the tag names for this particular query. I know I can probably use a loop
for tag in usertags:
tags.append(tag.name)
But what if a user has a 1000 tags? wont this slow down the response?
Is there a more efficient way to handling this?
If you just want the tag names, use a values_list query:
tags = UserTag.objects.filter(users=request.user).values_list('name', flat=True)

django prefetch_related with filter

models.py:
class Ingredient(models.Model):
_est_param = None
param = models.ManyToManyField(Establishment, blank=True, null=True, related_name='+', through='IngredientParam')
def est_param(self, establishment):
if not self._est_param:
self._est_param, created = self.ingredientparam_set\
.get_or_create(establishment=establishment)
return self._est_param
class IngredientParam(models.Model):
#ingredient params
active = models.BooleanField(default=False)
ingredient = models.ForeignKey(Ingredient)
establishment = models.ForeignKey(Establishment)
I need to fetch all Ingredient with parametrs for Establishment. First I fetch Ingredients.objects.all() and use all params like Ingredients.objects.all()[0].est_param(establishment).active. How I can use django 1.4 prefetch_related to make less sql queries? May be I can use other way to store individual Establishment properties for Ingredient?
Django 1.7 adds the Prefetch object you can put into prefetch_related. It allows you to specify a queryset which should provide the filtering. I'm having some problems with it at the moment for getting a singular (latest) entry from a list, but it seems to work very well when trying to get all the related entries.
You could also checkout django-prefetch which is part of this question which does not seem a duplicate of this question because of the vastly different wording.
The following code would fetch all the ingredients and their parameters in 2 queries:
ingredients = Ingredients.objects.all().prefetch_related('ingredientparam_set')
You could then access the parameters you're interested in without further database queries.

__in Filter Does Not Work

I inherited a Django application that serves high school sports information. I recently received a request to modify a certain set of data so information is displayed only from the current season, which I accomplished this way:
teams = Team.objects.filter(season__school_year__in=school_year_filter_list)
(school_year_filter_list contains [1,3])
This query causes an error in pgpool (a Postgres database pooling/replication utility) so I cannot use it. As a side note, the query works properly in the Python shell, and when I bypass pgpool and use Postgres directly. However, our network architecture dictates the use of pgpool, so I am trying to find an alternate way to retrieve the same data.
Can you help me determine another way to get all Teams with a Season in the current SchoolYear?
The (simplified) models look like this:
class Team(models.Model):
season = models.ForeignKey(Season)
class Season(models.Model):
school_year = models.ForeignKey(SchoolYear, blank=True, null=True)
class SchoolYear(models.Model):
school_year = models.CharField(max_length=150)
The '_schoolyear' table looks like:
id | school_year
----+-------------
1 | 2010-2011
2 | 2009-2010
3 | 2011-2012
In the end, I modified another model to make this work. Rather than parsing years to get active seasons, I added an "active" flag to the SchoolYear model and modified my query to check for that flag:
def queryset(self, request):
qs = super(PlayerYearAdmin, self).queryset(request)
return qs.filter(team__season__school_year__active=True)
Have you tried
teams = Team.objects.filter(season__school_year__id__in=school_year_filter_list)
?
Isn't it right that your school_year_filter_list is a list of school year ids?
Small note: I see 'django-admin' tag, so I think that you add season__school_year_in=[1, 2] to URL query string like /admin/sports/team/?season_school_year__in=[1, 2] Is it correct?
If so, are you shure that school_year_filter_list contains list [1,3], but not a string containing repr of list '[1,3]'
Can you provide us data about error that pgpool or Django ORM returns?

How can i get a list of objects from a postgresql view table to display

this is a model of the view table.
class QryDescChar(models.Model):
iid_id = models.IntegerField()
cid_id = models.IntegerField()
cs = models.CharField(max_length=10)
cid = models.IntegerField()
charname = models.CharField(max_length=50)
class Meta:
db_table = u'qry_desc_char'
this is the SQL i use to create the table
CREATE VIEW qry_desc_char as
SELECT
tbl_desc.iid_id,
tbl_desc.cid_id,
tbl_desc.cs,
tbl_char.cid,
tbl_char.charname
FROM tbl_desC,tbl_char
WHERE tbl_desc.cid_id = tbl_char.cid;
i dont know if i need a function in models or views or both. i want to get a list of objects from that database to display it. This might be easy but im new at Django and python so i having some problems
Django 1.1 brought in a new feature that you might find useful. You should be able to do something like:
class QryDescChar(models.Model):
iid_id = models.IntegerField()
cid_id = models.IntegerField()
cs = models.CharField(max_length=10)
cid = models.IntegerField()
charname = models.CharField(max_length=50)
class Meta:
db_table = u'qry_desc_char'
managed = False
The documentation for the managed Meta class option is here. A relevant quote:
If False, no database table creation
or deletion operations will be
performed for this model. This is
useful if the model represents an
existing table or a database view that
has been created by some other means.
This is the only difference when
managed is False. All other aspects of
model handling are exactly the same as
normal.
Once that is done, you should be able to use your model normally. To get a list of objects you'd do something like:
qry_desc_char_list = QryDescChar.objects.all()
To actually get the list into your template you might want to look at generic views, specifically the object_list view.
If your RDBMS lets you create writable views and the view you create has the exact structure than the table Django would create I guess that should work directly.
(This is an old question, but is an area that still trips people up and is still highly relevant to anyone using Django with a pre-existing, normalized schema.)
In your SELECT statement you will need to add a numeric "id" because Django expects one, even on an unmanaged model. You can use the row_number() window function to accomplish this if there isn't a guaranteed unique integer value on the row somewhere (and with views this is often the case).
In this case I'm using an ORDER BY clause with the window function, but you can do anything that's valid, and while you're at it you may as well use a clause that's useful to you in some way. Just make sure you do not try to use Django ORM dot references to relations because they look for the "id" column by default, and yours are fake.
Additionally I would consider renaming my output columns to something more meaningful if you're going to use it within an object. With those changes in place the query would look more like (of course, substitute your own terms for the "AS" clauses):
CREATE VIEW qry_desc_char as
SELECT
row_number() OVER (ORDER BY tbl_char.cid) AS id,
tbl_desc.iid_id AS iid_id,
tbl_desc.cid_id AS cid_id,
tbl_desc.cs AS a_better_name,
tbl_char.cid AS something_descriptive,
tbl_char.charname AS name
FROM tbl_desc,tbl_char
WHERE tbl_desc.cid_id = tbl_char.cid;
Once that is done, in Django your model could look like this:
class QryDescChar(models.Model):
iid_id = models.ForeignKey('WhateverIidIs', related_name='+',
db_column='iid_id', on_delete=models.DO_NOTHING)
cid_id = models.ForeignKey('WhateverCidIs', related_name='+',
db_column='cid_id', on_delete=models.DO_NOTHING)
a_better_name = models.CharField(max_length=10)
something_descriptive = models.IntegerField()
name = models.CharField(max_length=50)
class Meta:
managed = False
db_table = 'qry_desc_char'
You don't need the "_id" part on the end of the id column names, because you can declare the column name on the Django model with something more descriptive using the "db_column" argument as I did above (but here I only it to prevent Django from adding another "_id" to the end of cid_id and iid_id -- which added zero semantic value to your code). Also, note the "on_delete" argument. Django does its own thing when it comes to cascading deletes, and on an interesting data model you don't want this -- and when it comes to views you'll just get an error and an aborted transaction. Prior to Django 1.5 you have to patch it to make DO_NOTHING actually mean "do nothing" -- otherwise it will still try to (needlessly) query and collect all related objects before going through its delete cycle, and the query will fail, halting the entire operation.
Incidentally, I wrote an in-depth explanation of how to do this just the other day.
You are trying to fetch records from a view. This is not correct as a view does not map to a model, a table maps to a model.
You should use Django ORM to fetch QryDescChar objects. Please note that Django ORM will fetch them directly from the table. You can consult Django docs for extra() and select_related() methods which will allow you to fetch related data (data you want to get from the other table) in different ways.