django reverse lookup foreignkey not working - python

I want to get a specific Video object and then find all of the Rating objects that are associated with it using ForeignKey reverse lookup as described in the docs.
I have models:
class Video(models.Model):
...
rating_int = models.IntegerField(default=1, choices=CHOICES, name='rating_int')
def __str__(self):
return self.title
class Rating(models.Model):
video = models.ForeignKey('Video', related_name='video', null=True)
and views:
def video_ratings(request):
vid_rate = Video.objects.get(pk=1)
ratings_of_video = vid_rate.rating_set.all()
context = {
'vid_rate': vid_rate, 'ratings_video': ratings_of_video
}
return HttpResponse(template.render(context, request))
When I try to run this I get an error 'Video' object has no attribute 'rating_set'
But when i read the django docs it tells me when you do a reverse lookup you need to use this _set.all() command. I am not sure what is missing here.

You have specified related_name in your foreign key loopkup. so rating_set should not work now.
You can lookup like
ratings_of_video = vid_rate.video.all()
A better naming convention will be to use ratings in your related_name
class Rating(models.Model):
video = models.ForeignKey('Video', related_name='ratings', null=True)
and then query like
ratings_of_video = vid_rate.ratings.all()

Related

'ReverseManyToOneDescriptor' object has no attribute 'filter' Django

Hi there Im trying to retrieve a specific object from the related model so as to render data to my view specific to that particular object, in my case I have a custom user model and a related model called Seller.
Models
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class CustomUser(AbstractUser):
is_customer = models.BooleanField(default=False)
is_seller = models.BooleanField(default=False)
class Seller(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, blank=True, null=True)
store_name = models.CharField(max_length=120)
address = models.CharField(max_length=180)
phone = models.IntegerField(blank=True, null=True)
email = models.CharField( max_length=180, blank=True, null=True )
def __str__(self):
return self.store_name
View
#method_decorator( seller_required , name='dispatch')
class SellerDashBoardView(ListView):
model = Seller
template_name = 'seller_dashboard.html'
def get_context_data(self, *args, **kwargs):
user = CustomUser.seller_set.filter(store_name=self.request.user.username)
context = super(SellerDashBoardView, self).get_context_data( **kwargs)
context['products'] = Product.objects.filter(seller=user)[:6]
return context
This is because when you want to filter ManyToOne reverse Relation, you have to make exact the same query as you would've been done with a direct relation:
CustomUser.objects.filter(seller__store_name="Whole Foods")
# Note that would return a queryset not a single user!
# If you want a CustomUser object you will have to use either get or index the query
The doc example and explanations are provided here:
https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_one/
It is also better to use prefetch_related method to tell djano ORM that it does not have to make as many queries as number of related objects, that query should be done in 2 database queries instead of lenght of your related query:
CustomUser.objects.prefetch_related("seller_set").filter(seller__store_name="Whole Foods")
The doc link:
https://docs.djangoproject.com/en/3.1/ref/models/querysets/#prefetch-related
You probably would like to use ...seller_set.filter when you already got a CustomUser object. So if you want to filter its sellers you would use that:
...
user.seller_set.filter(store_name="Whole Foods")
That would provide you the Seller objects queryset filtered by a store name related to a specific user. Basically the same query as this:
Seller.objects.filter(user_pk=user.pk, store_name="Whole Foods")

Cannot resolve keyword 'last_activity' into field

As title says I was trying to sort a list of posts using the django order_by method and since the field I used was later added to the list (The field was not created inside the model) it failed.
Is there anything I can do about it other than adding the field to the model which is something I really don't wanna do?
Here is the model code
class post(models.Model):
title = models.CharField(max_length=236)
content = models.TextField()
post_board = models.ForeignKey(board, on_delete=models.CASCADE)
author = models.ForeignKey(User, on_delete=models.CASCADE)
release_date = models.DateField(auto_now_add=True)
views = models.IntegerField(default=0)
def __str__(self):
return self.title
The function that adds the extra field:
def forumdisplay(request, boardslug=None):
context = { 'board': None }
if boardslug:
context['board'] = board.objects.all().filter(slug=boardslug).first()
if context['board']:
context['posts'] = post.objects.all().filter(post_board=context['board'])
for eachpost in context['posts']:
eachpost.reply_count = len(reply.objects.all().filter(reply_to=eachpost))
eachpost.last_activity = eachpost.release_date
if eachpost.reply_count:
eachpost.last_activity = reply.objects.all().filter(reply_to=eachpost).order_by('release_date').first().release_date
context['posts'] = context['posts'].order_by('last_activity')
alter_posts(context['posts'])
else:
pass
return render(request, "board/forumdisplay.html", context)
The error I got:
Request Method: GET
Request URL: http://127.0.0.1:8000/forumdisplay/news/
Django Version: 3.0.4
Exception Type: FieldError
Exception Value:
Cannot resolve keyword 'last_activity' into field. Choices are: author, author_id, content, id, post_board, post_board_id, release_date, reply, title, views```
You can't.
order_by that you are trying to use is actually will be translated into SQL command to be executed on database, and while database has no column called last_activity so you can't apply this function to it.
what is the problem to add a new column to your DB and make it nullable?

How to filter against URL with foreign key field in Django REST, overwriting get_queryset method correctly

I am trying to filter my queryset against an url with django REST but can't really get it to work.
I want to pass a string in the URL (a project name). According to this string, which is a foreign key, I want to filter my queryset (BuildingGroup).
I don't want to use query params but a url filter. I followed the docs but there is not so much on it on the site.
This is what I am trying:
class ListBuildingGroupProject(ListAPIView):
serializer_class = BuildingGroupSerializer
filter_fields = 'project'
def get_queryset(self):
project = self.kwargs['project']
building_groups = BuildingGroup.objects.filter(project=project)
result = building_groups.order_by('-creation_date')
return result
The line building_groups = BuildingGroup.objects.filter(project=project)
throws me a KeyError for project.
Here are my models. Note that BuildingGroup has one Project. A project can belong to many BuildingGroups.
class BuildingGroup(models.Model):
description = models.CharField(max_length=500, null=True, blank=True)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
creation_date = models.DateTimeField(auto_now=False)
class Project(models.Model):
project_name = models.CharField(max_length=120, primary_key=True, unique=True)
start_date = models.DateTimeField(auto_now=False, null=True, blank=True)
end_date = models.DateTimeField(auto_now=False, null=True, blank=True)
and here my URL:
path('project/<str:project_name>', ListBuildingGroupProject.as_view(), name='building-group-project'),
Help is so much appreciated! Thanks in advance!
In your url, your argument is called project_name. This is what you should get from the kwargs. Beside, you want it to match the project.project_name:
def get_queryset(self):
project_name = self.kwargs['project_name']
building_groups = BuildingGroup.objects.filter(project__project_name=project_name)
result = building_groups.order_by('-creation_date')
return result
You might want to have a look at this DRF documentation about this.
It'll require to install Django Filters
You just need to declare in some rest_filters.py
from django_filters import rest_framework as filters
from .models import BuildingGroup
class BuildingGroupFilter(filters.FilterSet):
class Meta:
model = BuildingGroup
fields = {
"project__name":["exact","icontains"],
"project":["exact","in"]
}
Then within your ViewSet declaration:
[...]
from .rest_filters import BuildingGroupFilter
class ListBuildingGroupProject(ListAPIView):
serializer_class=BuildingGroupSerializer
filterset_class = BuildingGroupFilter
You can now enjoy a restfull behavior with:
{path_to_your_endpoint}?project__name__icontains="Hello World"
or {path_to_your_endpoint}?project__=[Project Id List]
To checkout how things works, filters are available in the browsable API.

get_absolute_url with multiple foreign key

Hello Django Pros out there!
Is it possible to get the pk of a model, which is not the direct foreign key of the model? But the foreignkey of the foreign key model?
My Models:
class Patient(models.Model):
patientID = models.CharField(max_length=200, unique=True, help_text='Insert PatientID')
class Examination(models.Model):
number_of_examination = models.IntegerField(choices=EXA_Choices)
patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
date_of_examination = models.DateField(auto_now=False, auto_now_add=False, help_text='YYYY-MM-DD')
class AbsoluteValue(models.Model):
examination = models.ForeignKey(Examination, on_delete=models.CASCADE)
attr1 = models.BooleanField(default=False)
attr2 = models.BooleanField(default=False)
attr3 = models.BooleanField(default=False)
and I want to define the get_absolute_url of the AbsoluteValue class. It should redirect to the Patient detail page. Due to this it needs the pk of the Patient class.
My try:
def get_absolute_url(self):
return reverse('member:detail', kwargs={'pk': self.examination__patient_id})
The error says that there is no URL to redirect to. So my query is not working, or I should not query in this function.
It looks like you want self.examination.patient_id instead of self.examination__patient_id. The double underscore notation is used by the Django ORM e.g. in filter(). For regular attribute access in Python, use a dot.
def get_absolute_url(self):
return reverse('member:detail', kwargs={'pk': self.examination.patient_id})

Django - Get Object with ForeignKey

versions:
Python 3.4
Django 1.7
I created a gallery app with different galleries and their own images.
my models:
from django.db import models
class Gallery(models.Model):
title = models.CharField(max_length=200)
pub_date = models.DateTimeField('publish date')
def __str__(self):
return self.title
class Image(models.Model):
title = models.CharField(max_length=200)
gallery = models.ForeignKey(Gallery)
pub_date = models.DateTimeField('publish date')
file = models.ImageField(upload_to='img/gallery/'+str(Gallery.objects.get(pk=str(gallery)).id)+'/')
def __str__(self):
return self.title
you see my Gallery and Image model. While creating an Image in the Backend it should create a folder dynamicly in "img/gallery/gallery_id"
my problem is that Image.gallery is a ForeignKey here and I cant convert it into a int or string to use it. Is there a function to get the ID from my Gallery object with the ForeignKey from my Image object?
my solution
Gallery.objects.get(pk=str(gallery)).id
is not working.
btw: I thought foreignkey is always an int like id? isnt it?
The way Django works, a convenient method is automatically added that will give you the model instance that the foreign key represents. This is your gallery field. There is another field, called the same but with _id appended, that holds the actual foreign key value.
As petkostas said, you can pass a function that accepts the instance and filename arguments. You should use gallery_id instead of gallery.id to prevent an unnecessary call to the database.
def gallery_folder(instance, filename):
return '/'.join(['img/gallery', instance.gallery_id, filename])
class Image(models.Model):
...
file = models.ImageField(upload_to=gallery_folder)
upload to can be a callback:
https://docs.djangoproject.com/en/1.6/ref/models/fields/#django.db.models.FileField.upload_to
so:
def gallery_folder(instance, filename):
return '/'.join(['img/gallery', instance.gallery.id, filename])
class Image(models.Model):
title = models.CharField(max_length=200)
gallery = models.ForeignKey(Gallery, related_name='images')
pub_date = models.DateTimeField('publish date')
file = models.ImageField(upload_to=gallery_folder)
def __str__(self):
return self.title
Also add related_name, makes reverse queries easier, also you can opt for instance.gallery.title if you want.

Categories

Resources