I'm currently going around in a bit of a "QuerySet' object has no attribute '' <> app.models.DoesNotExist: Messages matching query does not exist loop.
Essentially, I'm trying to define "last_activity" on a Room model that is referencing the time at which the last Message associated to that room was sent. This is my attempt:
class Room(models.Model):
title = models.CharField(max_length=255)
staff = models.BooleanField(default=False)
slug = models.SlugField(max_length=250, default='')
banner = models.ImageField(storage=USER_UPLOAD_LOC, null=True, blank=True)
def last_activity(self):
last_persisted_message = Messages.objects.filter(where=self.title).order_by('-sent_at')[:1]
return last_persisted_message.sent_at
class Messages(models.Model):
room = models.ForeignKey(Room, on_delete=models.CASCADE)
where = models.CharField(max_length=255)
message = models.TextField(default='')
user = models.ForeignKey(settings.AUTH_USER_MODEL)
username_from = models.CharField(max_length=255)
username_to = models.CharField(max_length=255, default='all')
sent_at = models.DateTimeField(default=datetime.datetime.now)
I've tried so many things now and referenced the query set documentation and nothing seems to be working.
I can also confirm that the "where" field for the Messages model is populated when a message is created by {{ room.title }}. I'm using a web socket connection on the client side to pass a "message" back to the websocket consumer.py which then persists the message to the DB).
If you slice the queryset with [:1] you will obtain a queryset containing at most one item, but not an item itself. You can use [0] to obtain the first item, or, .first():
def last_activity(self):
last_persisted_message = Messages.objects \
.filter(where=self.slug) \
.order_by('-sent_at') \
.first()
if last_persisted_message is not None:
return last_persisted_message.sent_at
If you use [0] and there is no such item, then the program will raise an IndexError (since there is no item with index 0).
In case there is no such Messages object (that satisfies the filter(..)), then last_persisted_message will be None, so you have to find a way to resolve that case. Here we return None in that case.
Related
I am trying to display quiz only for users that are registered in a particular course, i.e if a user is registered in a Frontend Crash Course i want them to see only the quiz related to that course they are registered in, and not all the quiz from the db.
i have a model UserCourse where i am storing all the courses a user have enrolled in, when i try filtering by that models while user_course is get like this below
user_course = UserCourse.objects.get(user=request.user)
quizzes = Quiz.objects.filter(course__usercourse=user_course).annotate(questions_count=Count('questions'))
i get this error get() returned more than one UserCourse -- it returned 3! Now i have changed .get() to .filter() like this
user_course = UserCourse.objects.filter(user=request.user)
quizzes = Quiz.objects.filter(course__usercourse=user_course).annotate(questions_count=Count('questions'))
i then get this error The QuerySet value for an exact lookup must be limited to one result using slicing.
What is the right way to write this query.
models.py
class UserCourse(models.Model):
user = models.ForeignKey(User , null = False , on_delete=models.CASCADE)
course = models.ForeignKey(Course , null = False , on_delete=models.CASCADE, related_name="usercourse")
class Quiz(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="quizzes")
title = models.CharField(max_length=255)
course = models.ForeignKey(Course, on_delete=models.SET_NULL, null=True, related_name="quizzes")
date = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(unique=True)
user_course = models.ForeignKey(UserCourse, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.title
The Problem in the Second Line
user_course = UserCourse.objects.filter(user=request.user)
quizzes=Quiz.objects.filter(course__usercourse=user_course).annotate(questions_count=Count('questions'))
remember that when You are using filter you get QuerySet not one object
if you want to return the quizes those related to user_course_queryset you can use __in filter
print(user_course) # print it to understand more
quizzes=Quiz.objects.filter(course__usercourse__in=user_course)
this will Return every Quiz Related to the QuerySet objects
The goal of this project is to create an API that refreshes hourly with the most up to date betting odds for a list of games that I'll be scraping hourly from the internet. The goal structure for the JSON returned will be each game as the parent object and the nested children will be the top 1 record for each of linesmakers being scraped by updated date. My understanding is that the best way to accomplish this is to modify the to_representation function within the ListSerializer to return the appropriate queryset.
Because I need the game_id of the parent element to grab the children of the appropriate game, I've attempted to pull the game_id out of the data that gets passed. The issue is that this line looks to be populated correctly when I see what it contains through an exception, but when I let the full code run, I get a list index is out of range exception.
For ex.
class OddsMakerListSerializer(serializers.ListSerializer):
def to_representation(self, data):
game = data.all()[0].game_id
#if I put this here it evaluates to 1 which should run the raw sql below correctly
raise Exception(game)
data = OddsMaker.objects.filter(odds_id__in = RawSQL(''' SELECT o.odds_id
FROM gamesbackend_oddsmaker o
INNER JOIN (
SELECT game_id
, oddsmaker
, max(updated_datetime) as last_updated
FROM gamesbackend_oddsmaker
WHERE game_id = %s
GROUP BY game_id
, oddsmaker
) l on o.game_id = l.game_id
and o.oddsmaker = l.oddsmaker
and o.updated_datetime = l.last_updated
''', [game]))
#if I put this here the data appears to be populated correctly and contain the right data
raise Exception(data)
data = [game for game in data]
return data
Now, if I remove these raise Exceptions, I get the list index is out of range. My initial thought was that there's something else that depends on "data" being returned as a list, so I created the list comprehension snippet, but that doesn't resolve the issue.
So, my question is 1) Is there an easier way to accomplish what I'm going for? I'm not using a postgres backend so distinct on isn't available to me. and 2) If not, its not clear to me what instance is that's being passed in or what is expected to be returned. I've consulted the documentation and it looks as though it expects a dictionary and that might be part of the issue, but again the error message references a list. https://www.django-rest-framework.org/api-guide/serializers/#overriding-serialization-and-deserialization-behavior
I appreciate any help in understanding what is going on here in advance.
Edit:
The rest of the serializers:
class OddsMakerSerializer(serializers.ModelSerializer):
class Meta:
list_serializer_class = OddsMakerListSerializer
model = OddsMaker
fields = ('odds_id','game_id','oddsmaker','home_ml',
'away_ml','home_spread','home_spread_odds',
'away_spread_odds','total','total_over_odds',
'total_under_odds','updated_datetime')
class GameSerializer(serializers.ModelSerializer):
oddsmaker_set = OddsMakerSerializer(many=True, read_only=True)
class Meta:
model = Game
fields = ('game_id','date','sport', 'home_team',
'away_team','home_score', 'away_score',
'home_win','away_win', 'game_completed',
'oddsmaker_set')
models.py:
class Game(models.Model):
game_id = models.AutoField(primary_key=True)
date = models.DateTimeField(null=True)
sport=models.CharField(max_length=256, null=True)
home_team = models.CharField(max_length=256, null=True)
away_team = models.CharField(max_length=256, null=True)
home_score = models.IntegerField(default=0, null=True)
away_score = models.IntegerField(default=0, null=True)
home_win = models.BooleanField(default=0, null=True)
away_win = models.BooleanField(default=0, null=True)
game_completed = models.BooleanField(default=0, null=True)
class OddsMaker(models.Model):
odds_id = models.AutoField(primary_key=True)
game = models.ForeignKey('Game', on_delete = models.CASCADE)
oddsmaker = models.CharField(max_length=256)
home_ml = models.IntegerField(default=999999)
away_ml = models.IntegerField(default=999999)
home_spread = models.FloatField(default=999)
home_spread_odds = models.IntegerField(default=9999)
away_spread_odds = models.IntegerField(default=9999)
total = models.FloatField(default=999)
total_over_odds = models.IntegerField(default=999)
total_under_odds = models.IntegerField(default=999)
updated_datetime = models.DateTimeField(auto_now=True)
views.py:
class GameView(viewsets.ModelViewSet):
queryset = Game.objects.all()
serializer_class = GameSerializer
Thanks
To answer the question in the title:
The instance being passed to the Serializer.to_representation() is the instance you pass when initializing the serializer
queryset = MyModel.objects.all()
Serializer(queryset, many=True)
instance = MyModel.objects.all().first()
Serializer(data)
Usually you don't have to inherit from ListSerializer per se. You can inherit from BaseSerializer and whenever you pass many=True during initialization, it will automatically 'becomeaListSerializer`. You can see this in action here
To answer your problem
from django.db.models import Max
class OddsMakerListSerializer(serializers.ListSerializer):
def to_representation(self, data): # data passed is a queryset of oddsmaker
# Do your filtering here
latest_date = data.aggregate(
latest_date=Max('updated_datetime')
).get('latest_date').date()
latest_records = data.filter(
updated_date_time__year=latest_date.year,
updated_date_time__month=latest_date.month,
updated_date_time__day=latest_date.day
)
return super().to_representation(latest_records)
I am sorting a query on a timefield from a manytomany object but have trouble during pagination.
models.py:
class Validated(models.Model):
job_id_list = models.ManyToManyField(JobId , related_name='JobId', blank=True)
class JobId(models.Model):
user = models.ForeignKey(User, blank=True, null=True, default=None)
job_time = models.DateTimeField(auto_now_add=True)
views.py:
results_list = Validated.objects.filter(job_id_list__user=request.user).\
distinct().order_by('-job_id_list__job_time')
My problem is that pagination is messed up and I get duplicates in my pagination output, even when the query output is ok. (other have this problem too)
I tried several solutions but my issue does not get solved as sorting is bases on a field from a many-to-many object order_by('job_id_list__job_time')
I was thinking of a work-around through creating an annotation to my model by the use of a Model.Manager. Inside this annotation, i try to add the job_time which is a result of a function inside the model. In that way, the job_time would be easily accessible:
for i in result_list:
job_time_from_model = result_list[i].job_time
I would do this as followed but I don't know how to incorporate the %%function logic%% inside the annotation.
Is this even possible in this way or is another approach required?
models.py:
class ValidatedManager(models.Manager):
**%%function-logic%%**
def date(self, user, id):
xlinkdatabase_validated_object = self.get(id=id)
job_id_list = xlinkdatabase_validated_object.\
job_id_list.all().order_by('-job_time')
date_added = None
for item in job_id_list:
if item.user == user:
date_added = item.job_time
break
return date_added
def get_queryset2(self, user):
qs = super(XlinkdatabaseValidatedManager, self).\
get_queryset().annotate(job_date= **%%function-logic%%**, output_field=DateTimeField())
return qs
views.py:
results_list = xlinkdatabase_validated.objects.get_queryset2(request.user).\
filter(job_id_list__user=request.user).distinct().order_by('-job_date')
I have a Django model that looks something like this :
class Candidate(models.Model):
first_name = models.CharField(max_length=30, blank=True, null=True)
middle_name = models.CharField(max_length=30, blank=True, null=True)
last_name = models.CharField(max_length=30, blank=True, null=True)
current_job = models.ForeignKey(
Job,
on_delete=models.SET_NULL,
blank=True,
null=True,
default=None,
)
I get an instance of "Candidate", and try to save some of the values into a dictionary
candidate = Candidate.objects.get(first_name = "John")
data['first_name'] = candidate.first_name
data['last_name'] = candidate.last_name
data['company_name'] = candidate.current_job.company
This works fine when all values and foreign-keys are properly populated.
However, when any of the values of the fields are None, especially important regarding the ForeignKey relationships, I'll hit an AttributeError, something like : 'NoneType' object has no attribute 'company'
I want to properly handle the "None" case for any Field in the Model.
I've found these two work-arounds for it right now, but neither seem satisfactory to me.
A) I can put a try-except around EACH and EVERY field (which doesn't seem correct as my models get to ~20 fields)
try:
data['first_name'] = candidate.first_name
data['last_name'] = candidate.last_name
except:
pass
try:
data['company_name'] = candidate.current_job.company
B) I can convert the instance to a dict like this and use a .get() since that never raises an Exception.
candidate_dict = candidate.__dict__
data['first_name'] = candidate_dict.get('first_name')
Is there a better way of handling the possibility of field values being None without handling an AttributeError exception on each and every single field?
First You need to check following query will return a record or not. You can put in try catch and handle the DoesNotExist exception.
candidate = Candidate.objects.get(first_name="John")
if candidate record present then you do not need to handle exception for
first_name, middle_name, last_name fields.
Since current_job is FK field and it can be null so before getting Job model fields data you first need to check the candidate related current_job field is not null
I am working on a library system to manage certain items in our office, I don't need a full-blown integrated library system so I decided to hand roll one with Django.
Below is a simplified version of my model:
class ItemObjects(models.Model):
# Static Variables
IN_STATUS = 'Available'
OUT_STATUS = 'Checked out'
MISSING = 'Missing'
STATUS_CHOICES = (
(IN_STATUS, 'Available'),
(OUT_STATUS, 'Checked out'),
(MISSING, 'Missing'),
)
# Fields
slug = models.SlugField(unique=True)
date_added = models.DateField(auto_now_add=True)
last_checkin = models.DateTimeField(editable=False, null=True)
last_checkout = models.DateTimeField(editable=False, null=True)
last_activity = models.DateTimeField(editable=False, null=True)
status = models.CharField(choices=STATUS_CHOICES, default=IN_STATUS, max_length=25)
who_has = models.OneToOneField(User, blank=True, null=True)
times_out = models.PositiveIntegerField(default=0, editable=False)
notes = models.CharField(blank=True, max_length=500)
history = models.TextField(blank=True, editable=False)
pending_checkin = models.BooleanField(default=False)
pending_transfer = models.BooleanField(default=False)
At first I was using a method on ItemObject to process checking out an item to a user and who_has was an EmailField because I couldn't get a CharfField to populate with the logged in user's name, but I figured using a OneToOneField is probably closer to the "right" way to do this.. While who_has was an EmailField, the following method worked:
def check_out_itemobject(self, user):
user_profile = user.get_profile()
if self.status == 'Available' and self.who_has == '':
self.status = 'Checked out'
self.who_has = user.email
self.last_checkout = datetime.datetime.now()
self.last_activity = datetime.datetime.now()
self.times_out += 1
if self.history == '':
self.history += "%s" % user_profile.full_name
else:
self.history += ", %s" % user_profile.full_name
if user_profile.history == '':
user_profile.history += self.title
else:
user_profile.history += ", %s" % self.title
else:
return False # Not sure is this is "right"
user_profile.save()
super(ItemObjects, self).save()
Now that I am using a OneToOneField this doesn't work, so I started looking at using a subclass of ModelForm but none of the cases I saw here on SO seemed to apply for what I am trying to do; my form would be a button, and that's it. Here are some of the questions I looked at:
Django: saving multiple modelforms simultaneously (complex case)
(Django) (Foreign Key Issues) model.person_id May not be NULL
django update modelform
So was I on the right track with a sort of altered save() method, or would a ModelForm subclass be the way to go?
EDIT/UPDATE: Many thanks to #ChrisPratt!
So I am trying to get Chris Pratt's suggestion for showing ItemHistory to work, but when I try to render it on a page I get an AttributeError that states "'User' object has no attribute 'timestamp'". So my question is, why is it complaining about a User object when last_activity is an attribute on the ItemObject object ?
My view:
#login_required
def item_detail(request, slug):
item = get_object_or_404(Item, slug=slug)
i_history = item.last_activity
user = request.user
return render_to_response('items/item_detail.html',
{ 'item' : item,
'i_history': i_history,
'user' : user })
I do not see why a User object is coming up at this point.
EDIT2: Nevermind, history is clearly a M2M field whose target is User. That's why!
Assuming users will log in and check out books to themselves, then what you most likely want is a ForeignKey to User. A book will only have one User at any given time, but presumably Users could check out other items as well. If there is some limit, even if the limit is actually one per user, it would be better to validate this in the model's clean method. Something like:
def clean(self):
if self.who_has and self.who_has.itemobject_set.count() >= LIMIT:
raise ValidationError('You have already checked out your maximum amount of items.')
Now, you checkout method has a number of issues. First, status should be a defined set of choices, not just random strings.
class ItemObject(models.Model):
AVAILABLE = 1
CHECKED_OUT = 2
STATUS_CHOICES = (
(AVAILABLE, 'Available'),
(CHECKED_OUT, 'Checked Out'),
)
...
status = models.PositiveIntegerField(choices=STATUS_CHOICES, default=AVAILABLE)
Then, you can run your checks like:
if self.status == self.STATUS_AVAILABLE:
self.status = self.STATUS_CHECKED_OUT
You could use strings and a CharField instead if you like, as well. The key is to decouple the static text from your code, which allows much greater flexibility in your app going forward.
Next, history needs to be a ManyToManyField. Right now, your "history" is only who last checked the item out or what the last item the user checked out was, and as a result is pretty useless.
class ItemObject(models.Model):
...
history = models.ManyToManyField(User, through='ItemHistory', related_name='item_history', blank=True)
class ItemHistory(models.Model):
CHECKED_OUT = 1
RETURNED = 2
ACTIVITY_CHOICES = (
(CHECKED_OUT, 'Checked Out'),
(RETURNED, 'Returned'),
)
item = models.ForeignKey(ItemObject)
user = models.ForeignKey(User)
activity = models.PostiveIntegerField(choices=ACTIVITY_CHOICES)
timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-timestamp'] # latest first
Which then allows you to get full histories:
some_item.history.all()
some_user.item_history.all()
To add a new history, you would do:
ItemHistory.objects.create(item=some_item, user=some_user, activity=ItemHistory.CHECKED_OUT)
The auto_now_add attribute ensures that the timestamp is automatically set when the relationship is created.
You could then actually get rid of the last_checkout and last_activity fields entirely and use something like the following:
class ItemObject(models.Model):
...
def _last_checkout(self):
try:
return self.history.filter(activity=ItemHistory.CHECKED_OUT)[0].timestamp
except IndexError:
return None
last_checkout = property(_last_checkout)
def _last_activity(self):
try:
return self.history.all()[0].timestamp
except IndexError:
return None
last_activity = property(_last_activity)
And, you can then use them as normal:
some_item.last_checkout
Finally, your checkout method is not an override of save so it's not appropriate to call super(ItemObject, self).save(). Just use self.save() instead.