django many to many query - python

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()

Related

Get backward relationships items for model in Django

I have a pet project with reviews about spare parts for cars.
Here is models.py:
class CarBrand(models.Model):
brand = models.CharField(max_length=40, choices=(), unique=True, verbose_name="Марка")
def __str__(self):
return self.brand
def get_absolute_url(self):
return reverse_lazy('car_models_all', kwargs={'car_id': self.pk})
class CarModel(models.Model):
model_name = models.CharField(max_length=60, db_index=True, verbose_name="Модель")
brand_id = models.SmallIntegerField(verbose_name="ID марки")
def __str__(self):
return self.model_name
def get_absolute_url(self):
return reverse_lazy('model_info', kwargs={'model_id': self.pk})
class SparePartCategory(models.Model):
name = models.CharField(max_length=255, db_index=True, verbose_name='Название')
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse_lazy('spare_parts_category', kwargs={'category_id': self.pk})
class SparePart(models.Model):
name = models.CharField(max_length=255, db_index=True, verbose_name='Название')
brand = models.CharField(max_length=255, db_index=True, verbose_name="Производитель")
number = models.CharField(max_length=30, db_index=True, verbose_name="Номер (артикул)")
category = models.ForeignKey(SparePartCategory, on_delete=models.PROTECT, verbose_name="Категория")
def __str__(self):
return ' '.join([self.name, self.brand, self.number])
def get_absolute_url(self):
return reverse_lazy('get_spare_part', kwargs={'spare_part_id': self.pk})
class Review(models.Model):
RATING_VALUES = [
('1', 'Ужасно'), ('2', 'Плохо'), ('3', 'Сносно'), ('4', 'Хорошо'), ('5', 'Отлично'),
]
spare_part = models.ForeignKey(SparePart, on_delete=models.PROTECT, verbose_name="Запчасть")
mileage = models.SmallIntegerField(verbose_name="Пробег, тыс.км")
car_brand = models.ForeignKey(CarBrand, on_delete=models.PROTECT, verbose_name="Марка авто")
car_model = models.ForeignKey(CarModel, on_delete=models.PROTECT, verbose_name="Модель авто")
owner = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Владелец")
rating = models.CharField(max_length=1, choices=RATING_VALUES, verbose_name="Рейтинг", default=3)
review = models.TextField(max_length=1000, blank=True, verbose_name="Отзыв")
def __str__(self):
return ' '.join([self.spare_part.name, self.spare_part.brand, self.spare_part.number])
In views.py I get one SparePart
def get_spare_part(request, spare_part_id):
spare_part = get_object_or_404(SparePart, pk=spare_part_id)
installed_on_cars = # here I need to get all CarModel for current SparePart with Review exists
context = {
'spare_part': spare_part,
'installed_on_cars': installed_on_cars,
}
return render(request, 'mileage/spare_part.html', context)
I need to get all CarBrand and CarModel for current SparePart with Review exists, and get hyperlinks for template for them. How do I can to implement this?
I think I need to make it with backward relationships, but can not understand how.
Use the _set manager object (documentation here).
for review in spare_part.review_set.all():
print(f'brand: {review.care_brand}')
print(f'model: {review.car_model}')
If you define a related_name (e.g. 'reviews) for spare_parts in Review, you can use that name for backward query instead of _set (e.g. spare_part.reviews.all()).

Error 'Product' object has no attribute '_combinator_query'

I am creating an e-commerce website in django where the homepage can be changed dynamically by changing the instances of FeaturedProduct objects. These objects have two ForeignKeys. First is to the Product class and the other is to FeaturedCategory class(this is for the type of deal, eg: daily deals, new arrivals, etc). So, I'm trying to get the Product instances in a queryset instead of the FeaturedProduct queryset. When I union two querysets, I get an error that 'Product' object has no attribute '_combinator_query'. The codes have been shown below.
My models.py
class Product(models.Model):
product_id = models.AutoField
product_name = models.CharField(max_length=50, unique=True)
category = models.ForeignKey(Category, on_delete=models.SET_DEFAULT, default='1')
sub_category = models.ForeignKey(SubCategory, on_delete=models.SET_DEFAULT, default='2')
price = models.IntegerField(default=0)
stock = models.IntegerField(default=0)
desc = models.TextField()
pub_date = models.DateField()
avg_rating = models.IntegerField(default=0)
avg_rating_float = models.FloatField(default=0.0)
number_of_ratings = models.IntegerField(default=0)
image1 = models.ImageField(upload_to="images", default="")
image2 = models.ImageField(upload_to="images", default="")
image3 = models.ImageField(upload_to="images", default="")
slug = models.SlugField(blank=True, help_text=('Leave this parameter empty, it will get generated automatically.'))
def save(self, *args, **kwargs):
self.slug = slugify(self.product_name)
super(Product, self).save(*args, **kwargs)
def __str__(self):
return self.product_name
class FeaturedCategory(models.Model):
category = models.CharField(max_length=100)
def __str__(self):
return self.category
class Meta:
verbose_name_plural = "Featured Categories"
class FeaturedProduct(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
featured_category = models.ForeignKey(FeaturedCategory, on_delete=models.CASCADE)
def __str__(self):
return self.product.product_name
My views.py
def index(request):
prod = Product.objects.none()
feat = FeaturedProduct.objects.all()
for pro in feat:
ob = Product.objects.get(product_name=pro.product)
print(ob.product_name)
print(ob.category)
print(ob.sub_category)
print(ob.price)
prod.union(ob) # Error found here
# Working part
products = Product.objects.all()
context = {'products': products}
return render(request, 'index.html', context)
The last three lines are working fine, but not the other part of the index function.
Please help. Thank You.

no match for queryset in UpdateView

The queryset in my view dont send back any result, however when Im executing the raw SQL command with DB Browser for example I have the result I want, I dont understnad why my queryset dont send back anything...
I got a 404 Not Found - No soldier to list found matching the query
the view:
class EditUnitsToListUpdateView(UpdateView):
model = SoldierToList
fields = ('soldier', 'list', 'author')
template_name = 'armybuilder_edit_unit_to_list.html'
def get_queryset(self):
print (self.model.objects.filter(list=54).query)
return self.model.objects.filter(list=54)
My models:
class List(models.Model):
faction = models.ForeignKey(Faction, on_delete=models.CASCADE)
title = models.CharField(max_length=30)
format_points = models.IntegerField()
description = models.CharField(max_length=30)
author = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("home")
class Soldier(models.Model):
title = models.CharField(max_length=30)
picture = models.FileField(blank=True,)
points = models.IntegerField()
factions = models.ManyToManyField(Faction)
def __str__(self):
return self.title
class SoldierToList(models.Model):
soldier = models.ForeignKey(Soldier, on_delete=models.CASCADE,)
list = models.ForeignKey(List, on_delete=models.CASCADE,)
author = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
)
My urls:
path('list/own/<int:list_id>/<int:faction_id>/addunit', AddUnitsToListFormView.as_view(), name='add_unit_to_list'),
path('list/own/<int:pk>/<int:faction_id>/editlist/toto', EditUnitsToListUpdateView.as_view(), name='edit_unit_to_list'),
The raw sql that work when executed separatly:
SELECT "armybuilder_soldiertolist"."id", "armybuilder_soldiertolist"."soldier_id", "armybuilder_soldiertolist"."list_id", "armybuilder_soldiertolist"."author_id" FROM "armybuilder_soldiertolist" WHERE "armybuilder_soldiertolist"."list_id" = 54
Thanks for your help guys and have a great day !

AttributeError; Dynamic url for list of charts by category issue (queryset filter)

Django 'CategorisedListView' object has no attribute 'slug' or Page not found (error 404) issue
I'm on Django 2.0, using generic class list view. I have tried dynamic url based on slug and queryset filter on slug to get list of charts by category.
Please help! I've been stuck here for a couple of days since.
views.py
class CategoriesView(generic.ListView):
template_name = 'Bokeh/categories.html'
context_object_name = 'all_categories'
def get_queryset(self):
return Category.objects.all()
class CategorisedListView(generic.ListView):
model = Category
template_name = 'categories/list_of_charts_by_category.html'
context_object_name = 'categorised'
def get_queryset(self):
self.category = get_object_or_404(Category, name = self.kwargs['slug'])
return Chart.objects.filter(category=self.slug)
models.py
class Category(models.Model):
name = models.CharField(max_length=100)
image_file = models.ImageField(default=None, unique=True)
slug = models.SlugField(max_length=100, unique=True)
parent = models.ForeignKey('self', on_delete=models.PROTECT, blank=True, null=True, related_name='children')
def __str__(self):
return self.name
def get_absolute_url(self):
return '{slug}/'.format(slug=self.slug)
class Meta:
ordering = ('name',)
verbose_name = 'Category'
verbose_name_plural = 'Categories'
class Chart(models.Model):
name = models.CharField(max_length=250)
slug = models.SlugField(max_length=250, unique=True)
description = models.TextField(max_length=250)
url = models.URLField(default=None, blank=True)
embed_url = models.TextField(default=None, blank=True)
image_file = models.ImageField(default=None, unique=True)
code_file = models.FileField(default=None, blank=True, unique=True)
chart_library = models.CharField(max_length=250)
author = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
tag = TaggableManager()
category = models.ForeignKey(Category, on_delete=models.CASCADE, blank=True, null=True)
def __str__(self):
return self.name + ' - ' + self.chart_library
def get_absolute_url(self):
return reverse('Bokeh:detail', kwargs={'pk': self.pk})
def read_file(self):
data = self.code_file.path
with open(self.code_file.path, 'r', encoding='UTF-8') as data:
content = data.read()
return content
class Meta:
ordering = ('name',)
urls.py
path("categories/", views.CategoriesView.as_view(), name='categories'),
# /Bokeh/categories/<category_slug>
path("categories/<slug:slug>/", views.CategorisedListView.as_view(), name='list_of_charts_by_category'),
it is supposed to query the database when a specific category is clicked and return the list of charts categorised under that specific category. However, the page throws 'CategorisedListView' object has no attribute 'slug'
The lookup you're doing in get_queryset() isn't quite right. Firstly, you seem to be looking up the Category by name rather than by the slug. Then you try and filter the Charts using their category attribute, but instead of passing the category you pass a non-existent attribute self.slug.
Try changing the implementation to this:
def get_queryset(self):
# Lookup the Category using it's slug attribute, not name, and assign to local variable
category = get_object_or_404(Category, slug=self.kwargs['slug'])
# Now lookup the Charts using the category we just looked up
return Chart.objects.filter(category=category)

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

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

Categories