I have the field 'submission' which has a user and a problem. How can I get an SQL search result which will give a list of only one result per user-problem pair?
Models are like this:
class Problem(models.Model):
title = models.CharField('Title', max_length = 100)
question = models.TextField('Question')
class Submission(models.Model):
user = models.ForeignKey(User)
problem = models.ForeignKey(Problem)
solution = models.CharKey()
time = models.DateTimeField('Time', auto_now_add=True)
Try this:
distinct_users_problems = Submission.objects.all().values("user", "problem").distinct()
It will give you a list of dicts like this one:
[{'problem': 1, 'user': 1}, {'problem': 2, 'user': 1}, {'problem': 3, 'user': 1}]
containing all the distinct pairs.
It actually results in your usual SELECT DISTINCT SQL query.
Update 2:
(After reading OP's comments) I suggest adding a new model to track the latest submission. Call it LatestSubmission.
class LatestSubmission(models.Model):
user = models.ForeignKey(User)
problem = models.ForeignKey(Problem)
submission = models.ForeignKey(Submission)
You can then either
override Submission.save() to create/update the entry in LatestSubmission every time an user posts a new solution for a Problem
attach a function that does the same to a suitable signal.
such that LatestSubmission will contain one row per problem-user-submission combination pointing to the latest submission for the problem by each user. Once you have this in place you can fire a single query:
LatestSubmission.objects.all().order_by('problem')
Update:
Since the OP has posted sample code, the solution can now be changed as follows:
for user in User.objects.all(): # Get all users
user.submission_set.latest('time') # Pick the latest submission based on time.
Original Answer
In the absence of any date/time based criteria for deciding which is "older" or "newer", you can use the primary key (id) of Submission to "neglect the old ones".
for user in User.objects.all(): # Get all users
user.submission_set.latest('id') # Pick the latest submission by each user.
Related
I am building a small BlogApp and I build a feature of adding favorite users. User can search and add the user in his favorite users list
I am now building a feature if searched user is already in another's users favorite user list then exclude the user from the result
For example :- If user_1 added user_50 in his favorite user's list. and then if user_2 searched user_50 then it will not show in the search list.
BUT when i try to exclude then it is not excluding.
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,unique=True)
full_name = models.CharField(max_length=100,default='')
friends = models.ManyToManyField("Profile",blank=True)
email = models.EmailField(max_length=60,default='')
class FavouriteUsers(models.Model):
adder = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
favouriteUser = models.ManyToManyField(User, related_name='favouriteUser', blank=True)
views.py
def search_users_favourite(request):
q = request.GET.get('q')
exclude_this = FavouriteUsers.objects.filter(favouriteUser=request.user)
results = Profile.objects.filter(user__username__icontains=q).exclude(exclude_this)
serialized_results = []
for result in results:
serialized_results.append({
'id': result.id,
'username': result.user.username,
})
return JsonResponse({'results': serialized_results})
BUT this is showing :-
TypeError: Cannot filter against a non-conditional expression.
I have tried many times but it is still that error.
Any help would be Appreciated.
Thank You in Advance.
Try this query:
Profile.objects.filter(user__username__icontains=q, user__favouriteUser__isnull=True)
This will exclude all profiles that are already mapped in FavouriteUsers (already has been a favorite)
I think you should be doing it this way
exclude_this = FavouriteUsers.objects.filter(favouriteUser=request.user).values_list('favouriteUser__username',flat=True)
results = Profile.objects.filter(user__username__icontains=q).exclude(user__username__in=exclude_this) here, i assume you want to exclude usernames matching the entire name.
For a better answer, please attach the log of the error.
I spent hours tearing my hair out over this issue, so I wanted to post a quick response here on what is actually causing this exception:
The problem is this (pseudo code):
query = Model.objects.filter(something=value)
result = Model.objects.filter(query).first()
This won't work (apparently). Django hates it big time.
The problem is that you can't pass a QuerySet to filter or exclude.
Instead, use your QuerySet directly:
query = Model.objects.filter(something=value)
result = query.first()
I have the following documents:
class Note(EmbeddedDocument):
value = mongo_db.StringField(max_length=200, required=True)
id = mongo_db.UUIDField(required=True, primary_key=True)
class Post(Document,):
notes = mongo_db.ListField(mongo_db.EmbeddedDocumentField(Note))
How to write a statement that update the value field for a Note object inside the list of a Post object. in other words how to write something that do the following:
update(post_id, note_id, new_valye)
In similar way, how I can delete an instance of the embedded documents Note:
delete(post_id, note_id)
First I edited My Post Document to get the benefits of EmbeddedDocumentListField:
class Note(EmbeddedDocument):
value = mongo_db.StringField(max_length=200, required=True)
id = mongo_db.UUIDField(required=True, primary_key=True)
class Post(Document,):
notes = mongo_db.EmbeddedDocumentListField(Note, required=False)
Then used for updating:
Post.objects(
id=post_id,
notes__id=note_id
).update(
set__notes__S__value=my_value
)
And for delete:
Post.objects(id=post_id).update_one(
pull__notes__id=note_id
)
But I think, there is a problems with this approach, first update now is hard to write if you are updating many fields.
You've got 2 ways of doing this, let's assume you want to update the second item of the list (i.e at index=1):
1) Get your document instance and use .save()
post = Post.objects().first()
post.notes[1].value = 'new_value'
post.save()
2) If all you need is updating a field of a document, and you know its position in the array, then you can use:
Post.objects.update(set__notes__1__value='new_value')
I have a form with a select list.
When the user selects a value of 8888 or 9999 from the award_grant_type select list, I want some of the data that may or may not exist in the form input fields (the user may have entered data into the form text input fields and then selected 8888 or 9999) to be deleted before the form data is commited to the database.
So I have the following model.py code:
.....
DISPLAY_ONLY_AWARD_AND_GRANT_DESCRIPTION_WITH_PROMPT = 8888
DISPLAY_ONLY_AWARD_AND_GRANT_DESCRIPTION_WITHOUT_PROMPT = 9999
.....
AWARD_GRANT_TYPES = (
(SELECT_AWARD_AND_GRANT_TYPE, _('Select Type')),
(AWARD, _('Award')),
(GRANT, _('Grant')),
(TRAVEL_GRANT, _('Travel Grant')),
(OTHER_AWARD, _('Other Award')),
(OTHER_GRANT, _('Other Grant')),
(WRITE_MY_OWN_AWARD_AND_GRANT_TYPE_DESCRIPTION, _('Write my own Type description')), #7777
(DISPLAY_ONLY_AWARD_AND_GRANT_DESCRIPTION_WITH_PROMPT, _('Display only Description with prompt')), #8888
(DISPLAY_ONLY_AWARD_AND_GRANT_DESCRIPTION_WITHOUT_PROMPT, _('Display only Description without prompt')) #9999
)
user = models.ForeignKey(User)
language_version = models.ForeignKey('LanguageVersion')
award_grant_type = models.PositiveIntegerField(choices=AWARD_GRANT_TYPES, default=SELECT_AWARD_AND_GRANT_TYPE, validators=[MinValueValidator(1)])
award_grant_type_description = models.CharField(null=True, blank=True, max_length=250)
award_grant_date = models.DateField(null=True, blank=True)
award_grant_description = models.TextField(null=False, blank=False, max_length=5000)
Here is my forms.py clean code that should remove the award_grant_type_description and award_grant_date fields when the user has selected 8888 or 9999 from the select list award_grant_type before being committed to the db:
def clean(self):
cd_agdf = super(AwardGrantDetailsForm, self).clean()
if 'award_grant_type' in cd_agdf:
if cd_agdf['award_grant_type'] == '':
self._errors['award_grant_type'] = self.error_class([_("You must select a Type.")])
elif cd_agdf['award_grant_type'] == 8888 or cd_agdf['award_grant_type'] == 9999:
# remove the entered values when the award grant type only requires minimum data.
self.cleaned_data.pop('award_grant_type_description', None)
self.cleaned_data.pop('award_grant_date', None)
else:
....
return cd_agdf
Can anyone point out what I have done incorrectly? The award_grant_type_description and award_grant_date are not removed before the form data is committed to the db.
EDIT / UPDATE
This issue only occurs when the existing record is updated. A new record removes the data as required before the form is saved to the db. When an existing record has a date field as part of the db record and the award_grant_type is changed from say 1 to 8888 or 9999, then the award_grant_date is NOT removed from the db. I cannot figure out why.
2nd EDIT
I have posted a related thread here.
Try to change self.cleaned_data to cd_agdf. Dictionary, that method clean returns, will be used as cleaned_data. You popped items from self.cleaned_data, but returned not changed cd_ahdf. This is described here (see last step starting with "The form's subclass...").
Answering to the edit only: there is a fight over what the data means.
Form validation happens first, its purpose is to parse the submitted data, clean it up and point any error in the data. The result of this step should be the cleaned up, canonical form of the data.
Then action: if valid, form is acted upon. You interpret that data to take appropriate action. Here, writing it to a database.
Your two steps disagree on the meaning of data. Validation removes award_grant_type_description and award_grant_date from the final data to mean “blank out those fields”. Then, the action interprets missing data as “leave that field as it is” (that's what the default ModelForm.save() does).
Your choice: either conform to ModelForm's convention and set the fields to None instead of removing them, or override your form's save() so it interprets missing data as “remove from object”. Unless I had a good reason to alter ModelForm's semantics, I'd go with setting the fields to None.
I finally figured this issue out.
When I wrap the values in quotation marks, the issue is resolved.
Here is the example code I used that works:
elif cd_agdf['award_grant_type'] == '8888' or cd_agdf['award_grant_type'] == '9999':
I hope that this will help someone.
instead of self.cleaned_data.pop()
do cd_agdf.pop() as you are assigning cd_agdf to superclass
What is the proper way to order and filter on a ForeignKey key on model like this one?
class Ticket(models.Model):
name = models.CharField(max_length=250)
created_time = models.DateTimeField(auto_now_add=True)
def current(self):
return TicketUpdate.objects.filter(ticket=self.id).first()
class TicketUpdate(models.Model):
ticket = models.ForeignKey(Ticket)
description = models.TextField()
status = models.CharField(max_length=1, choices=STATUSES, default='N')
type = models.CharField(max_length=1, choices=TYPES, default='N')
priority = models.CharField(max_length=1, choices=PRIORITIES, default='D')
created_time = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created_time']
Every ticket has one (at least) or more TicketUpdate related.
I want to:
list all the ticket from Ticket and show their current status (the newest TicketUpdate item)
order the list by TicketUpdate__created_time or Ticket__created_time
filter the list by TicketUpdate__priority or TicketUpdate__type or TicketUpdate__status
I am not sure if I have to make a Queryset on Ticket or on TicketUpdate.
I am not even sure if I need that current() function on the Ticket model: I use it on my ListView to retrieve the TicketUpdate info.
With
Ticket.objects.all().order_by('ticketupdate__created_time')
I get a list ordered but with too many entries.
Everything must run on a sqlite3 db too.
Edit:
This filter queryset
Ticket.objects.filter(ticketupdate__status='New').values('name', 'ticketupdate__status').order_by('ticketupdate__created_time')
return all the existing ticket, since all of them have an initial New status. I keep the whole history of a ticket: New, Working, Fixed, NotFixed, Working ("Working" again: that fix did not work and the user reopen the ticket)
So I want to filter just by the latest status: I need all the Working but what if a ticket have both Working and Fixed? I just need to filter on the latest.
Yeah you don't really need that current method.
You could just get the queryset and take the first item;
Ticket.objects.all().order_by('ticketupdate__created_time')[0]
Or take a more django based approach of;
Ticket.objects.all().latest('ticketupdate__created_time')
And if you want to filter things;
Ticket.objects.filter(ticketupdate__status='status').order_by(
'ticketupdate__created_time')
Ticket.objects.filter(ticketupdate__priority='high').latest(
'ticketupdate__created_time')
You can try:
For list all the ticket from Ticket and show their current status (the newest TicketUpdate item):
For List:
Ticket.objects.values('name', 'ticketupdate__status')
For latest Ticket Update Object:
TicketUpdate.objects.latest('ticket__created_time')
For ordering the list by TicketUpdate__created_time or Ticket__created_time:
Ticket.objects.values('name', 'ticketupdate__status').order_by('ticketupdate__created_time')
or
Ticket.objects.values('name', 'ticketupdate__status').order_by('created_time')
For filtering the list by TicketUpdate__priority or TicketUpdate__type or TicketUpdate__status:
Ticket.objects.filter(ticketupdate__status='your status choice').values('name', 'ticketupdate__status').order_by('ticketupdate__created_time') # simillary priority
EDIT
As I can see, status field in the TicketUpdate is a Character Field, so that A TicketUpdate object can't have both Working or New Status. If you want to get the object which was lastly updated/created, consider adding auto_now to field created_time and whenever you query using:
Ticket.objects.filter(ticketupdate__status='New').values('name', 'ticketupdate__status').order_by('ticketupdate__created_time')
You will get the list sorted in such order that the last updated/created object will be the first index of that list. Also:
Ticket.objects.filter(ticketupdate__status='New').values('name', 'ticketupdate__status').order_by('ticketupdate__created_time').first()
Will return the latest Ticket data.
I am trying to understand the 1-to-many relationships in datastore; but I fail to understand how query and update the record of a user when the model includes ReferenceProperty. Say I have this model:
class User(db.Model):
userEmail = db.StringProperty()
userScore = db.IntegerProperty(default=0)
class Comment(db.Model):
user = db.ReferenceProperty(User, collection_name="comments")
comment = db.StringProperty()
class Venue(db.Model):
user = db.ReferenceProperty(User, collection_name="venues")
venue = db.StringProperty()
If I understand correctly, the same user, uniquely identified by userEmail can have many comments and may be associated with many venues (restaurants etc.)
Now, let's say the user az#example.com is already in the database and he submits a new entry.
Based on this answer I do something like:
q = User.all()
q.filter("userEmail =", az#example.com)
results = q.fetch(1)
newEntry = results[0]
But I am not clear what this does! What I want to do is to update comment and venue fields which are under class Comment and class Venue.
Can you help me understand how this works? Thanks.
The snippet you posted is doing this (see comments):
q = User.all() # prepare User table for querying
q.filter("userEmail =", "az#example.com") # apply filter, email lookup
- this is a simple where clause
results = q.fetch(1) # execute the query, apply limit 1
the_user = results[0] # the results is a list of objects, grab the first one
After this code the_user will be an object that corresponds to the user record with email "az#example.com". Seing you've set up your reference properties, you can access its comments and venues with the_user.comments and the_user.venues. Some venue of these can be modified, say like this:
some_venue = the_user.venues[0] # the first from the list
some_venue.venue = 'At DC. square'
db.put(some_venue) # the entry will be updated
I suggest that you make a general sweep of the gae documentation that has very good examples, you will find it very helpful:
http://code.google.com/appengine/docs/python/overview.html
** UPDATE **: For adding new venue to user, simply create new venue and assign the queried user object as the venue's user attribute:
new_venue = Venue(venue='Jeferson memorial', user=the_user) # careful with the quoting
db.put(new_venue)
To get all Comments for a given user, filter the user property using the key of the user:
comments = Comment.all().filter("user =", user.key()).fetch(50)
So you could first lookup the user by the email, and then search comments or venues using its key.