I have a model which is an instance for the existence of an item (a ticket), and on each creation of a ticket I create a instance of another model, a record. Each record keeps track of who made a change to the ticket, and what they did with it, it basically keeps a record of what has happened with it. I want to tickets creator and creation date to be defined as the creator and creation date of the first activity made which points to it. (The first of the many in a many to one relation.
As is, I have a function which does this very simply:
def created_by(self):
records = Record.objects.filter(ticket=self.id).order_by('created_on')
return records[0].created_by
However I run into an issue with this when trying to sort a collection of tickets (which is logically most often going to be sorted by creation date). I cannot sort by a function using django's filter for queries.
I don't really want to store the redundant data in the database, and I'd rather have the record than not so all date items related to the ticket can be seen in the records. Idea's on how to make it so I can sort and search by this first instance of record? (Also need to search for the creator because some users can only see their own tickets, some can see all, some can see subsets)
Thanks!
Assuming the Record ticket field is a Foreign key to the Ticket model:
class Record (models.Model):
....
create_time = models.DateTimeField()
ticket = models.ForeignKey(Ticket,related_name='records')
You can replace the ModelManager (objects) of the Ticket model and override the get_queryset function:
class TicketManager(models.ModelManager):
def get_queryset():
return super(TicketManager, self).get_queryset().annotate(create_time=Min('records__create_time')).order_by('create_time')
class Ticket(models.Model):
.....
objects = TicketManager
Now every query like Ticket.objects.all() or Ticket.objects.filter(...) will be sorted by the create time
Related
I'm trying to return a list of users that have recently made a post, but the order_by method makes it return too many items.
there is only 2 accounts total, but when I call
test = Account.objects.all().order_by('-posts__timestamp')
[print(i) for i in test]
it will return the author of every post instance, and its duplicates. Not just the two account instances.
test#test.example
test#test.example
test#test.example
test#test.example
foo#bar.example
Any help?
class Account(AbstractBaseUser):
...
class Posts(models.Model):
author = models.ForeignKey('accounts.Account',on_delete=models.RESTRICT, related_name="posts")
timestamp = models.DateTimeField(auto_now_add=True)
title = ...
content = ...
This is totally normal. You should understand how is the SQL query generated.
Yours should look something like that:
select *
from accounts
left join post on post.account_id = account.id
order by post.timestamp
You are effectively selecting every post with its related users. It is normal that you have some duplicated users.
What you could do is ensure that your are selecting distinct users: Account.objects.order_by('-posts__timestamp').distinct('pk')
What I would do is cache this information in the account (directly on the acount model or in another model that has a 1-to-1 relashionship with your users.
Adding a last_post_date to your Account model would allow you to have a less heavy request.
Updating the Account.last_post_date every time a Post is created can be a little tedious, but you can abstract this by using django models signals.
I have the following models:
class Company(ndb.Model):
name = ndb.StringProperty(indexed=False)
# some other fields
class User(polymodel.PolyModel):
company = ndb.KeyProperty(kind=Company)
# some other fields
class Object(ndb.Model):
user = ndb.KeyProperty(kind=User)
# some other fields
Now I have a user and I want to query Objects that are associated with other Users in the same company like this:
Object.query(Object.user.company == user.company)
Of course, this doesn't work, since Object.user is a key and I cannot access anything beyond that.
Is there any way to do it? I only need the company key, I was thinking on a ComputedProperty but I'm not sure if it's the best solution. Also, it would be better to query based on any field in company.
You need to denormalize and store redundant information, as the datastore doesn't support joins.
For instance given your models above, a user can only be a member of one company, if you really need to search all objects whose user is a member of a particular company then store the company key in the Object.
Use a computed property if that works best for you.
Alternately use a factory that always takes the User as a argument and construct Object that way.
Good evening,
I am working on some little website for fun and want users to be able to add items to their accounts. What I am struggling with is coming up with a proper solution how to implement this properly.
I thought about adding the User Object itself to the item's model via ForeignKey but wouldn't it be necessary to filter through all entries in the end to find the elements attached to x user? While this would work, it seems quite inefficient, especially when the database has grown to some point. What would be a better solution?
From what I understand of your use case, a User can have many items and and an Item can belong to multiple users. It this s the case, using ManyToManyField seems the way to go :
class Item(models.Model):
users = models.ManyToManyField('auth.User', related_name='items')
You can then query items from a specific user like this:
# adding an item to a user
user.items.add(my_item)
# query user items
user.items.all()
user.items.filter(name__startswith='Hello')
If you want to store additional information about the relationship, such as the date were the item was linked to the user, you have to specifiy an explicit intermediate model:
class Item(models.Model):
users = models.ManyToManyField('auth.User', through='ItemUser', related_name='users')
class ItemUser(models.Model):
"""Explicit intermediary model"""
user = models.ForeignKey('auth.User')
item = models.ForeignKey(Item)
date_added = models.DateTimeField(auto_now_add=True)
To create the binding beetween a User and an Item, just instanciate the intermediate model:
binding = ItemUser(user=user, item=item)
binding.save()
assert user in item.users.all()
You could create a model UserItems for each user with a ForeignKey pointing to the user and an item ID pointing to items. The UserItems model should store the unique item IDs of the items that belong to a user. This should scale better if items can be attached to multiple users or if items can exist that aren't attached to any user yet.
I'm currently building an app using Django and django-rest-framework.
My problem is relatively simple, but i got stuck at some point.
Basically, i manage Collection and Collectible objects. A Collectible object is assigned to a Collection. Both object have a field "created_at".
I would like to generate a view containing all Collections and for each, all Collectible. It works easily.
Now, i'm looking to generate the very same structure but with a filtering param "createdfrom" to have the new Collections and new Collectibles from the provided date.
Here is the code I have using django-filters:
class CollectionFilter(django_filters.FilterSet):
# /api/collections/?createdfrom=2013-11-20
createdfrom = django_filters.DateTimeFilter(name="collectibles__created_at", lookup_type='gt')
class Meta:
model = Collection
This works almost great. There is only a couple of issues:
It displays all Collectibles from a Collection in which at least one of them match the filter (basically, it also displays the outdated items along with the news ones)
It doesn't show new Collections created after such date.
Could anyone help me ?
Thanks a lot
If I understand your problem correctly, both the Collection and Collectible must have a date > the date provided for the filter. Thus, we will define an "action" to be taken with the QuerySet and value once provided. This is outlined in the django-filter documentation covering Core Arguments (specifically action).
def action(queryset, value):
return queryset.filter(
collectibles__created_at__gt=value,
created_at__gt=value,
)
class CollectionFilter(django_filters.FilterSet):
# /api/collections/?createdfrom=2013-11-20
createdfrom = django_filters.DateTimeFilter(
name="collectibles__created_at",
action=action,
)
class Meta:
model = Collection
We created an action function definition to be called with the QuerySet as the first argument, and the value (date) as the second argument.
action: An optional callable that tells the filter how to handle the queryset. It recieves a QuerySet and the value to filter on and should return a Queryset that is filtered appropriately. -From Documentation
Currently I have an InstrumentedList that represents a one-to-many relationship in my pyramid app. The relationship is constructed in the following way:
Class project:
submissions = relationship('Submission', backref='project')
I want to iterate over every submission in a list of projects. However, I want my submissions to be ordered by timestamp (a datetime object)
Here is how I am iterating over my submissions at the moment:
for project in projects:
for submission in project.submissions:
# Do some stuff with each submission here
The problem is that the order of my submissions for every project changes whenever the app is reloaded. I need the order to be consistent and ordered by timestamp, how do I go about doing that?
You'll need to specify an ordering in your relationship definition, using the order_by parameter:
class Project(Base):
# ...
submissions = relationship('Submission',
backref='Project', order_by='Submission.timestamp')
#martjin answer is completely ok , but if you want to order your table in descending order, then use desc() function:
class Project(Base):
# ...
submissions = relationship('Submission',
backref='Project', order_by='Submission.timestamp.desc()')