Cannot query "Cast object (1)": Must be "Person" instance - python

I am trying to create a detail-list of my actor where it will show all the shows he has been a cast member of. This is part of mozilla's challenge yourself section at the end of the tutorial.
I am having trouble filtering my class Cast so that I can get a specific Actor.
I do not understand why the filter is not working. If self.object has a value of '3' for example, it should be filtering out all of the actors and only display the actor with the id of 3. But that does not seem to be the case. I also am not understanding the error code it is tossing out. My Cast class does have a foreignkey to person.
Similar to my show details page, instead of casts, I want it to be the actor's starred in movies.
Image of my Show Details Page
View
class ActorDetailView(generic.DetailView):
model = Cast
template_name = 'show/actor-detail.html'
def get_context_data(self, **kwargs):
context = super(ActorDetailView, self).get_context_data(**kwargs)
context['casts'] = Cast.objects.filter(person_id=self.object)
return context
Models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Character(models.Model):
name = models.CharField(max_length=128)
on_which_show = models.ForeignKey('Show', on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.name
class Cast(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
cast_show = models.ForeignKey('Show',on_delete=models.CASCADE)
character = models.ForeignKey(Character, on_delete=models.CASCADE, null=True)
def get_absolute_url(self):
return reverse('actor-detail', args=[str(self.id)])
class Show(models.Model):
title = models.CharField(max_length=200)
genre = models.ManyToManyField(Genre, help_text='Select a genre for this book')
language = models.ForeignKey('Language', on_delete=models.SET_NULL, null=True)
summary = models.TextField(max_length=1000, help_text='Enter a brief description of the show', null=True)
cast_of_the_show = models.ManyToManyField(Person,through='Cast')
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('show-detail', args=[str(self.id)])

The model for your ActorDetailView should be Person instead of Cast. Then you can use the person record to get all of the casts they belong to.
class ActorDetailView(generic.DetailView):
model = Person
template_name = 'show/actor-detail.html'
def get_context_data(self, **kwargs):
context = super(ActorDetailView, self).get_context_data(**kwargs)
context['casts'] = Cast.objects.filter(person=self.object)
return context

Related

Django generic create view . Can we add conditions to save data from the form?

This is what my code looks like and I want to add some condition to the Borrower create view like if the stock method of book returns 0 then don't list that book in field while creating a new borrower or if it isn't possible at least throw some error while adding borrower to that book.
models.py:
class Book(models.Model):
id = models.UUIDField(primary_key=True, unique=True,
default=uuid.uuid4, editable=False)
title = models.CharField(max_length=200)
author = models.CharField(max_length=100)
summary = models.TextField(
max_length=1000, help_text="Enter a brief description of the book")
isbn = models.CharField('ISBN', max_length=13,
help_text='13 Character https://www.isbn-international.org/content/what-isbn')
genre = models.ManyToManyField(
Genre, help_text="Select a genre for this book")
language = models.ForeignKey(
'Language', on_delete=models.SET_NULL, null=True)
total_copies = models.IntegerField()
pic = models.ImageField(blank=True, null=True, upload_to='books')
def stock(self):
total_copies = self.total_copies
available_copies = total_copies - \
Borrower.objects.filter(book=self).count()
if available_copies > 0:
return available_copies
else:
return 0
def __str__(self):
return self.title
class Borrower(models.Model):
id = models.UUIDField(primary_key=True, unique=True,
default=uuid.uuid4, editable=False)
student = models.ForeignKey('Account', on_delete=models.CASCADE)
book = models.ForeignKey('Book', on_delete=models.CASCADE)
issue_date = models.DateField(
null=True, blank=True, help_text='YYYY-MM-DD', default=date.today)
return_date = models.DateField(
null=True, blank=True, help_text='YYYY-MM-DD')
def __str__(self):
return self.student.name.title()+" borrowed "+self.book.title.title()
def fine(self):
today = date.today()
fine = 0
if self.return_date <= today:
fine += 5 * (today - self.return_date).days
return fine
views.py:
class BorrowerView(LoginRequiredMixin, ListView):
model=Borrower
context_object_name='borrowers'
template_name = 'library/borrower_list.html'
def get_context_data(self, **kwargs):
context=super().get_context_data(**kwargs)
if self.request.user.is_admin or self.request.user.is_superuser:
context['borrowers']=context['borrowers']
else:
context['borrowers']=context['borrowers'].filter(student = self.request.user.id)
return context
class BorrowerCreate(LoginRequiredMixin, UserAccessMixin, CreateView):
model=Borrower
permission_required= 'borrowers.add_borrowers'
fields='__all__'
success_url=reverse_lazy('library:borrower-list')
def form_valid(self, form):
form.instance.user=self.request.user
return super(BorrowerCreate, self).form_valid(form)
class BorrowerDetail(LoginRequiredMixin, DetailView):
model=Borrower()
context_object_name='borrower'
template_name='library/borrower.html'
class Book(models.Model):
id = models.UUIDField(primary_key=True, unique=True,
default=uuid.uuid4, editable=False)
title = models.CharField(max_length=200)
author = models.CharField(max_length=100)
summary = models.TextField(
max_length=1000, help_text="Enter a brief description of the book")
isbn = models.CharField('ISBN', max_length=13,
help_text='13 Character https://www.isbn-international.org/content/what-isbn')
genre = models.ManyToManyField(
Genre, help_text="Select a genre for this book")
language = models.ForeignKey(
'Language', on_delete=models.SET_NULL, null=True)
total_copies = models.IntegerField()
pic = models.ImageField(blank=True, null=True, upload_to='books')
#new, use this to keep track of available books
available_copies = models.IntegerField()
def __str__(self):
return self.title
When any borrower borrows a copy of the book, you will subtract it from the total copies.
class BorrowerCreate(LoginRequiredMixin, UserAccessMixin, CreateView):
model=Borrower
permission_required= 'borrowers.add_borrowers'
fields='__all__'
success_url=reverse_lazy('library:borrower-list')
#remember to get the object using slug or 404
def form_valid(self, form):
instance = form.save(commit=False)
instance.user = self.request.user
book = Book.objects.get(id=instance.book.id)
#get the book id from the form and check if the book is still available, then subtract.
if book.available_copies > 0:
book.available_copies -= 1
book.save()
instance.save()
message.success(self.request, _("successful")
message.error(self.request, _("Book not in stock")
return super(BorrowerCreate, self).form_valid(form)
If user return the book and click returned. you can perform a similar action by adding to available copies.
This is not the solution, you can write a fat model with methods that takes care of both borrowing and return. Like this
def borrow(self):
self.available_copies -= 1
def returned(self):
self.available_copies += 1
You can call these two methods in different views or define a signal that call them using pre_save
Ist:
Instead of defining a new method which you called stock, why not add stock as a field instead of making a database query.
2nd:
calling the class inside the same class is not the best way to make queries inside the class.
3rd:
To add a condition while adding an object, you need to override the save method of the object like this.
def save(self, *args, **kwargs):
# do_something() here.....
# then
return super().save(*args, **kwargs)
The above code will enable you to perform any action before saving the object.
Another way you can do this is inside the form_valid function like this.
def form_valid(self, form):
instance = form.save(commit=False)
# commit = False will make sure that the form is not saved
# then you can now query the database and check conditions like
if Borrower.object.all().count() > 0:
instance.save()
messages.success(self.request, _("saved successfully")
else:
messages.error(self.request, _("Error")
return redirect("URL")

django many to many query

I'm attempting to create an application that would help me store old music.
These are my models.
class ArtistGenre(models.Model):
genre_name = models.CharField('Genre', max_length=20)
def __str__(self):
return self.genre_name
def get_absolute_url(self):
return reverse('genre_detail', kwargs={'pk': self.pk})
class ArtistTrait(models.Model):
trait_name = models.CharField('Trait', max_length=20)
def __str__(self):
return self.trait_name
def get_absolute_url(self):
return reverse('trait_detail', kwargs={'pk': self.pk})
class Artist(models.Model):
stage_name = models.CharField('Stage Name', max_length=255)
real_name = models.CharField('Birth Name', max_length=255, blank=True)
artist_genre = models.ForeignKey(ArtistGenre, on_delete=models.CASCADE)
artist_trait = models.ManyToManyField(ArtistTrait)
def __str__(self):
return self.stage_name
def get_absolute_url(self):
return reverse('profile_artist', kwargs={'pk': self.pk})
My hang-up is properly querying the ArtistGenre and ArtistTrait models in order to create clickable links that would list all artists in a Genre or with a particular Trait.
Do I have to create Many To Many fields in the Trait and Genre models that link to the artists or is there a way for me to query the it currently?
Thank You!
You probably need something like this:
class Artist(models.Model):
stage_name = models.CharField('Stage Name', max_length=255)
real_name = models.CharField('Birth Name', max_length=255, blank=True)
artist_genre = models.ForeignKey(ArtistGenre, on_delete=models.CASCADE, related_name='artists')
artist_trait = models.ManyToManyField(ArtistTrait, related_name='artists')
Now from a given genre or trait model, you'll be able to get all the artists because of the related_name attribute.
# Get all artists from the ArtistGenre -
genre = ArtistGenre.objects.first()
artists = genre.artists.all()
# Get all artists from ArtistTrait
artists = ArtistTrait.artists.all()

how to filter values of main table from foreign key table view?

I a trying to display the values of a foreign key table sorted upon the values of other foreign table.
am unable to find a way to show all the type of categories available in a specific city in the views.
From the 'views' I am able to get all the business's present in the specific city, but along with that I want to find the category types available in the specific city. A help is very much appreciated
#models.py
class business(models.Model):
title = models.CharField(max_length=200)
category = models.ForeignKey('Type', on_delete=models.SET_NULL, null=True)
summary = models.TextField(max_length=1000, help_text="Enter a brief description of the business")
city = models.ForeignKey('City', help_text="Select a city for this business")
def get_absolute_url(self):
return reverse('business-detail', args=[str(self.id)])
def __str__(self):
return self.title
class Type(models.Model):
category_name = models.CharField(max_length=200,help_text="Enter business category")
def __str__(self):
return self.category_name
class City(models.Model):
city_name = models.CharField(max_length=200,help_text="Enter a city")
def __str__(self):
return self.city_name
#views.py
class citydetail(generic.ListView):
model = City
def get_context_data(self, **kwargs):
context = super(citydetail, self).get_context_data(**kwargs)
context['test'] = Type.objects.all()

Django access ForeignKey field and get their values

I`m trying to build a small webshop platform where a user can create a shop, select a category of products and add products to it.
To achieve my goal I created this simplified models.py
class Organization(models.Model):
org_id = models.AutoField(primary_key=True)
company_name = models.CharField(max_length=255)
owned_by = models.OneToOneField(UserProfile, on_delete=models.CASCADE)
def __str__(self):
return f'{self.company_name} ORG'
def get_absolute_url(self):
return reverse('org-view', kwargs={'pk': self.org_id})
class Category(models.Model):
CATEGORIES = ( ('electric', 'Electronics'), ('food', 'FrozenFood'), ('shoes', 'slippers') )
cat_name = models.CharField(max_length=255, choices=CATEGORIES)
def __str__(self):
return f'{self.cat_name} Category'
def get_absolute_url(self):
return reverse('cat-view', kwargs={'id': self.pk})
class Product(models.Model):
org_id = models.ForeignKey(Organization, on_delete=models.CASCADE, blank=True, null=True)
cat_name = models.ForeignKey(Category, on_delete=models.CASCADE)
product_name = models.CharField(max_length=255)
def __str__(self):
return self.product_name
In my views i want to keep the user on a single page where he can manage his shop.
My current views.py:
class OrganizationDetailView(LoginRequiredMixin, UserPassesTestMixin, DetailView, FormMixin):
model = Organization
queryset = Organization.objects.all()
template_name = 'org/org_view.html'
form_class = ProductForm
def test_func(self):
org = self.get_object()
if self.request.user.profile == org.owned_by:
return True
return False
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data()
pk = self.object.serializable_value('pk')
product = Product.objects.filter(org_id=pk)
return self.render_to_response(context)
I need help to understand a few things:
how to execute the queries to retrieve all of his products and be able to see the category in which the product belongs.
My bad solution: the product variable holds all the products for that shop, including a cat_name_id that points to the category pk. Thats nice, but i need the name of the category.
i need something like this: print(product.category_name) and i should see 'Electronics'
how to execute a query that groups together items under the same category.
I already spent days trying to understand those queries, so please Explain like i`m five
You can filter all products of one user with the following command:
products = Product.objects.all().filter(org_id__owned_by=user)
See the documentation: https://docs.djangoproject.com/en/3.0/topics/db/queries/#retrieving-specific-objects-with-filters. Here, 'user' is the user object from your User_Profile class.
With respect to your second question, I'm guessing that you want to order a specific query by category; in that case the statement would be:
products = Product.objects.order_by('cat_name')
Or you can combine the two with:
products = Product.objects.all().filter(org_id__owned_by=user).order_by('cat_name')

List posts that fall under a particular catgeory in Django 1.9

I am working on a blog like project but different and I have recently started learning Django. So, in my app we have categories and tags as well. Now there's an Entry model which has ManyToMany relation with both Category and Tag. Now I am trying to get all the Entries which falls under a particular category, it's a similar feature that we have in blogs.
Following is my Tag and Category Model.
class CategoryQuerySet(models.QuerySet):
def category_menu(self):
return self.filter(intopmenu=True)
def top_catgories(self):
return self.order_by("views")[:5]
class Category(models.Model):
name = models.CharField(max_length=50, unique=True)
views = models.IntegerField(default=0)
intopmenu = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
slug = models.SlugField(unique=True)
objects = CategoryQuerySet.as_manager()
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
def __str__(self):
return self.name
class Meta:
verbose_name = "Entry Category"
verbose_name_plural = "Entry Categories"
ordering = ["created"]
class Tag(models.Model):
name = models.CharField(max_length=20)
slug = models.SlugField(max_length=200, unique=True)
def __str__(self):
return self.slug
Following is my Entry Model.
class EntryQuerySet(models.QuerySet):
def published(self):
return self.filter(publish=True)
def most_liked(self, num):
return self.order_by("-likes")[:num]
def most_views(self, num):
return self.order_by('-views')[:num]
class Entry(models.Model):
image = models.ImageField(upload_to='entries_images/', null=True)
image_alt = models.CharField(max_length=200, blank=True)
name = models.CharField(max_length=50, blank=True)
text = models.CharField(max_length=500, unique=True)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
publish = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
source = models.URLField(blank=True)
slug = models.SlugField(unique=True)
categories = models.ManyToManyField(Category)
tags = models.ManyToManyField(Tag)
objects = EntryQuerySet.as_manager()
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Entry, self).save(*args, **kwargs)
def __str__(self):
return self.text
class Meta:
verbose_name = "Entry"
verbose_name_plural = "Entries"
ordering = ["created"]
In my urls.py I have the following url to view all entries by that fall under a particular category.
url(r'^category/(?P<category_slug>[\w\-]+)/$', views.category, name='category'),
Apparently, I don't understand how to write the view to retrieve list of all the entries falling under particular category or tag. Any help will be appreciated. I did refer many blog posts on the web regarding my problem and also searched SO, 1 is a similar question I found but that didn't help much.
try:
def category(request,category_slug):
category = get_object_or_404(Category,slug=category_slug)
return render(request,'template_name.html',{'category':category,'posts':category.entry_set.all()})
More information on https://docs.djangoproject.com/en/1.9/topics/db/examples/many_to_many/

Categories