I have the following Django model:
class Accounts(models.Model):
account_code = models.CharField(max_length=12)
account_name = models.CharField(max_length=50)
value = models.DecimalField(max_digits=10, decimal_places=2)
When a query the database I want the returned queryset to have its field value divided by 1000.
How can I do this kind of math on a model field as I query the database?
You can define a property on your model using the property decorator. This property would not be defined in the database, but would be accessible on each object once queried.
For example:
class Accounts(models.Model):
account_code = models.CharField(max_length=12)
account_name = models.CharField(max_length=50)
value = models.DecimalField(max_digits=10, decimal_places=2)
#property
def divided_value(self):
return self.value / 1000
Then you can access the divided_value on each account instance as a normal property, e.g. account.divided_value.
I'm not certain that this is actually possible to do in a queryset, even using annotation (I'm actually pretty certain that it's not possible). My first answer is space inefficient, as you'd have to store the same value in two forms, and my second answer is what I would do, and uses the front end to handle the division:
Answer One: A second value field
In your model, you can define a field formatted_value that is also a decimal, but with 6 decimal places (to account for the division by 1000). In the save function, or in a pre_save signal, you can divide value by 1000 and save that in the formatted_value field.
This answer is sub-optimal because you will waste space in your database. I believe that a better answer is this:
Answer Two: View or Front End Handling
In my projects, I often need to manipulate numbers held in the database to output some sort of analytics tool. I return the raw numbers to the front end (as long as they are not sensitive), and then handle the math in the front end using Javascript. This passes the burden of computation to the client, and simplifies your Django. The pro of this is that you can then make the front end interactive and allow the user to change values that affect the analytics they are looking at.
I have a feeling that you are looking for something simpler. If you have a view that always needs to return the value/1000, you can handle this in your view by getting your list of Accounts using Accounts.objects.all() and then looping through each and dividing value by 1000.
Related
Lets say i have two model
class Testmodel1():
amount = models.IntegerField(null=True)
contact = models.CharField()
entry_time = models.DateTimeField()
class Testmodel2():
name = models.CharField()
mobile_no = models.ForeignKey(Testmodel1)
and I am creating the object for this model(Testmodel2). Now I want to find out the count of object(Testmodel2) created in last 24 hours by mobile_no field.
what could be the best way of making query.
Any help would be appreciated.
It'd be better if you made the contact field into a models.DateTime field rather than a models.CharField. If it were a DateTime field, you could do lte, gte, and other operations on it easily to compare it to other datetimes.
For example, if Testmodel.contact were a DateTime field, the answer to your question would be:
Testmodel.objects.filter(contact__gte=past).count()
If the contact field contains a string representing a DateTime, I'd recommend switching it over, since there's really no reason to store it as a string.
If you're unable to change these fields, unfortunately I don't think there's a way to do this on the database level. You'll have to filter them individually on the python side:
from dateutil.parser import parse
results = []
past = arrow.utcnow().shift(hours=-24)
model_query = TestModel.objects.all()
for obj in model_query.iterator():
contact_date = parse(obj.contact) # Parse string into datetime
if contact_date > past:
results.append(obj)
print(len(results))
This will give you a list (note: NOT a queryset) containing all matching model instances. It'll be a lot slower than the other option would be, you can't edit the results afterwards with something like results.filter(amount__gte=1).count(), and it's not quite as clean.
That said, it'll get the job done.
EDIT
It occurs to me that this might be able to be done with annotation, but I'm not sure how that would be accomplished, or if it would even work. I defer to other answers if they can think of a way to use annotation to accomplish this in a better way, but stick to my original assessment that this should probably be a DateTime field.
EDIT 2
With a DateTime field now added on the other model, you can look it up across models like so:
past = arrow.utcnow().shift(hours=-24)
Testmodel2.objects.filter(mobile_no__entry_time__gte=past)
I have the following models:
class Deal(models.Model):
date = models.DateTimeField(auto_now_add=True)
retailer = models.ForeignKey(Retailer, related_name='deals')
description = models.CharField(max_length=255)
...etc
class CustomerProfile(models.Model):
saved_deals = models.ManyToManyField(Deal, related_name='saved_by_customers', null=True, blank=True)
dismissed_deals = models.ManyToManyField(Deal, related_name='dismissed_by_customers', null=True, blank=True)
What I want to do is retrieve deals for a customer, but I don't want to include deals that they have dismissed.
I'm having trouble wrapping my head around the many-to-many relationship and am having no luck figuring out how to do this query. I'm assuming I should use an exclude on Deal.objects() but all the examples I see for exclude are excluding one item, not what amounts to multiple items.
When I naively tried just:
deals = Deal.objects.exclude(customer.saved_deals).all()
I get the error: "'ManyRelatedManager' object is not iterable"
If I say:
deals = Deal.objects.exclude(customer.saved_deals.all()).all()
I get "Too many values to unpack" (though I feel I should note there are only 5 deals and 2 customers in the database right now)
We (our client) presumes that he/she will have thousands of customers and tens of thousands of deals in the future, so I'd like to stay performance oriented as best I can. If this setup is incorrect, I'd love to know a better way.
Also, I am running django 1.5 as this is deployed on App Engine (using CloudSQL)
Where am I going wrong?
Suggest you use customer.saved_deals to get the list of deal ids to exclude (use values_list to quickly convert to a flat list).
This should save you excluding by a field in a joined table.
deals = Deals.exclude( id__in=customer.saved_deals.values_list('id', flat=True) )
You'd want to change this:
deals = Deal.objects.exclude(customer.saved_deals).all()
To something like this:
deals = Deal.objects.exclude(customer__id__in=[1,2,etc..]).all()
Basically, customer is the many-to-many foreign key, so you can't use it directly with an exclude.
Deals saved and deals dismissed are two fields describing almost same thing. There is also a risk too much columns may be used in database if these two field are allowed to store Null values. It's worth to consider remove dismissed_deals at all, and use saved_deal only with True or False statement.
Another thing to think about is move saved_deals out of CustomerProfile class to Deals class. Saved_deals are about Deals so it can prefer to live in Deals class.
class Deal(models.Model):
saved = models.BooleandField()
...
A real deal would have been made by one customer / buyer rather then few. A real customer can have milions of deals, so relating deals to customer would be good way.
class Deal(models.Model):
saved = models.BooleanField()
customer = models.ForeignKey(CustomerProfile)
....
What I want to do is retrieve deals for a customer, but I don't want to include deals that they have dismissed.
deals_for_customer = Deals.objects.all().filter(customer__name = "John")
There is double underscore between customer and name (customer__name), which let to filter model_name (customer is related to CustomerProfile which is model name) and name of field in that model (assuming CutomerProfile class has name attribute)
deals_saved = deals_for_customer.filter(saved = True)
That's it. I hope I could help. Let me know if not.
I have 3 models.
class Picture(models.Model)
name = models.CharField(max_length=255)
image_field = models.ImageField(upload_to="foo/")
slug = models.SlugField()
[...]
class Size(models.Model):
name = models.CharField(max_length=255)
width = models.IntegerField()
height = models.IntegerField()
crop = models.BooleanField(default=True)
upscale = models.BooleanField(default=False)
def __unicode__(self):
return self.name
class Cache(models.Model):
size = models.ForeignKey('Size')
picture = models.ForeignKey('Picture')
image_field = models.ImageField(upload_to="picture/resize/")
I want to use them as follows: First generate Picture objects. Then create Size objects. For every Size and Picture a Cache object should be generated when needed.
My problem is that I don't know where to put the code. It should be something like (pseudocode):
def get_cached_picture(Picture,Size):
try:
cacheObj = Cache.objects.get(picture=Picture, size=Size):
[.. use cacheObj ..]
except Cache.DoesNotExist:
[.. resize Picture according to Size, insert into cache, use it ..]
So where can I plug this code ? I know I could do this within a view, but is there a way to embed it into the models ? Cache should never be filled in the admin, instead it should be generated whenever a certain combination between Cache and Picture is needed.
It is probably easy to do, but I'm lacking of the right keyword for google.
Assumptions:
You want to be able to load a "Representation" of an image at a certain size on the fly.
Size model will store a predefined set of sizes that a Representation can have.
I am going to refer to your Cache model as Representation because I think it makes more sense in context here.
The entry-point of this process would obviously be a view. A request comes in and you determine you need to search "Image1.jpg" # 800x600. The simplest approach is just to put your queries right into the view. But for reusability, it might be better to do any of the following:
A utility function which is then called from the view to retrieve a Representation object
A classmethod of your Representation model, since you are already referencing Picture and Size as foreign keys.
Using a custom manager on the Representation model to do something similar to the above
Any of these will make it reusable as an app if someone else were to have their own views and needed to simply retrieve a Rep instance directly.
While your pseudocode refers to this process being on the Picture mode, I maintain that it should probably be on the Representation model, since it contains both foreign keys and you can easily see if you have a proper rep. If not, create it.
The view should only have to call something simple as opposed to having all of the logic:
# as classmethod
rep = Representation.get_cached_picture(picture, size)
# or with a manager
rep = Representation.objects.get_cached_picture(picture, size)
I have a base LoggedEvent model and a number of subclass models like follows:
class LoggedEvent(models.Model):
user = models.ForeignKey(User, blank=True, null=True)
timestamp = models.DateTimeField(auto_now_add=True)
class AuthEvent(LoggedEvent):
good = models.BooleanField()
username = models.CharField(max_length=12)
class LDAPSearchEvent(LoggedEvent):
type = models.CharField(max_length=12)
query = models.CharField(max_length=24)
class PRISearchEvent(LoggedEvent):
type = models.CharField(max_length=12)
query = models.CharField(max_length=24)
Users generate these events as they do the related actions. I am attempting to generate a usage-report of how many of each event-type each user has caused in the last month. I am struggling with Django's ORM and while I am close I am running into a problem. Here is the query code:
def usage(request):
# Calculate date range
today = datetime.date.today()
month_start = datetime.date(year=today.year, month=today.month - 1, day=1)
month_end = datetime.date(year=today.year, month=today.month, day=1) - datetime.timedelta(days=1)
# Search for how many LDAP events were generated per user, last month
baseusage = User.objects.filter(loggedevent__timestamp__gte=month_start, loggedevent__timestamp__lte=month_end)
ldapusage = baseusage.exclude(loggedevent__ldapsearchevent__id__lt=1).annotate(count=Count('loggedevent__pk'))
authusage = baseusage.exclude(loggedevent__authevent__id__lt=1).annotate(count=Count('loggedevent__pk'))
return render_to_response('usage.html', {
'ldapusage' : ldapusage,
'authusage' : authusage,
}, context_instance=RequestContext(request))
Both ldapusage and authusage are both a list of users, each user annotated with a .count attribute which is supposed to represent how many particular events that user generated. However in both lists, the .count attributes are the same value. Infact the annotated 'count' is equal to how many events that user generated, regardless of type. So it would seem that my specific
authusage = baseusage.exclude(loggedevent__authevent__id__lt=1)
isn't excluding by subclass. I have tried id__lt=1, id__isnull=True, and others. Halp.
The key to Django model inheritance is remembering that with a non-abstract base class everything is really an instance of the base class which might happen to have some extra data strapped on the side from a separate table. This means that when you do searches on the base table you get back instances of the base class and there's no way to tell which subclass it is without doing repeated database queries on the subclass tables to see if they contain a record with a matching key ("I have an event. Does it have a record in AuthEvent? No. What about LDAP Event?…"). Among other things this means that you can't easily filter on them in normal queries on the base class without doing a join on every subclass table.
You have a couple of choices: one would simply be to do your queries on the subclass and tally the results (ldap_event_count = LDAPEvent.objects.filter(user=foo).count(), …), which might be sufficient for a single report. I usually recommend adding a content type field to the base class so you can efficiently tell which particular subclass an instance is without having to do another query:
content_type = models.ForeignKey("contenttypes.ContentType")
That allows two major improvements: the most common one is that you can deal with many Events generically without having to do something like hit the subclass-specific accessors (e.g. event.authevent or event.ldapevent) and handling DoesNotExist. In this case it would also make it trivial to rewrite your query since you could just do something like Event.objects.aggregate(Count("content_type")) to get the report values, which becomes particularly handy if your logic gets more complicated ("Event is Auth or LDAP and …").
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.