How to get books of the the same author in Django - django

I am developing an online Book Store.
Here is the models:
class Author(models.Model):
name = models.CharField(max_length=250, unique=True)
class Publisher(models.Model):
name = models.CharField(max_length=250, unique=True)
class Book(models.Model):
author = models.ManyToManyField(Author, related_name='authors')
publisher = models.ForeignKey(Publisher, on_delete=models.PROTECT, blank=True, null=True)
isbn13 = models.BigIntegerField(unique=True)
name = models.CharField(max_length=500)
...
Here is the View:
class AuthorsListView(ListView):
model = Author
context_object_name = 'authors_list'
template_name = 'authors_list.html'
paginate_by = 500
class AuthorBooksListView(ListView):
model = Book
context_object_name = 'author_books'
template_name = 'author_books.html'
def get_queryset(self, **kwargs):
author_id = Author.objects.get(pk = self.kwargs['pk'])
qs = super().get_queryset(**kwargs)
return qs.filter(author = author_id)
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
# Add in a QuerySet
context['author'] = Author.objects.get(pk = self.kwargs['pk'])
return context
class PublishersListView(ListView):
model = Publisher
context_object_name = 'publishers_list'
template_name = 'publishers_list.html'
paginate_by = 500
class PublisherBooksListView(ListView):
model = Book
context_object_name = 'publisher_books'
template_name = 'publisher_books.html'
paginate_by = 20
def get_queryset(self, **kwargs):
publisher_id = Publisher.objects.get(pk = self.kwargs['pk'])
qs = super().get_queryset(**kwargs)
return qs.filter(publisher = publisher_id)
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
# Add in a QuerySet
context['publisher'] = Publisher.objects.get(pk = self.kwargs['pk'])
return context
class BooksListView(ListView):
model = Book
context_object_name = 'books_list'
template_name = 'books_list.html'
paginate_by = 100
class BookDetailView(DetailView):
model = Book
template_name = 'book_detail.html'
Here is the urls:
path('authors/', AuthorsListView.as_view(), name = 'authors_list'),
path('author/<int:pk>/', AuthorBooksListView.as_view(), name='author_detail'),
path('publishers/', PublishersListView.as_view(), name='publishers_list'),
path('publisher/<int:pk>/', PublisherBooksListView.as_view(), name='publisher_detail'),
path('', BooksListView.as_view(), name='books_list'),
path('book/<int:pk>/', BookDetailView.as_view(), name='book_detail'),
On the Book Detail Page I want to display:
Related books by the same author
Related books by the same publisher
How can I do this? Please help me.
I was trying to add these code to the BookDetailView:
def get_queryset(self, **kwargs):
book = Book.objects.get(pk = self.kwargs['pk'])
queryset = {
'books': Book.objects.all(),
'publisher_books': Book.objects.filter(publisher = book.publisher.id),
}
return queryset
But it gives me an error:
'dict' object has no attribute 'filter'

#djangodjarhes - Can you try the following? Ideally I modify the get_queryset if I want to change the way the queryset should be filtered other than the URL kwargs. For anything else, I override the get_context_data
def get_context_data(self, **kwargs):
context = super(BookDetailView, self).get_context_data(**kwargs)
book = Book.objects.get(pk = self.kwargs['pk'])
publisher_books = Book.objects.filter(publisher = book.publisher.id)
context["publisher_books"] = publisher_books
return context
In your case and feel free to correct me
queryset = {
'books': Book.objects.all(),
'publisher_books': Book.objects.filter(publisher = book.publisher.id),
}
This is not right. You are returning a dict when the get_queryset is supposed to return a queryset. You cannot return a dict. Either you change it to do this
queryset = Book.objects.filter(publisher = book.publisher.id)
return queryset
or use get_context_data if you want to return a dict.

Related

How to pass a calendar in a generic form with a request?

Can you please tell me how to transfer the calendar to the form with a get request, with clicking on the days of the week and transferring to the form? There is a filtering for all fields at the same time now, only with the date of trouble (
Approximately how such a calendar can be transmitted? Thanks in advance.
class Traveller(models.Model):
title = models.CharField(max_length=30,default='',null=False)
origin = models.ForeignKey(Origin,on_delete=models.CASCADE,max_length=100,verbose_name= 'Источник',default='')
destination = models.ForeignKey(Destination,on_delete=models.CASCADE, verbose_name="Местонахождение",default='')
transport = models.ForeignKey(Transport,on_delete=models.CASCADE, verbose_name="Транспорт",default='')
passengers = models.ForeignKey(Passengers,on_delete=models.CASCADE, verbose_name="Пассажиры",default='')
url = models.SlugField(max_length=130, unique=True)
def __str__(self):
return self.title
class Meta:
verbose_name = 'Путешествие'
verbose_name_plural = 'Путешествие'
def get_absolute_url(self):
return reverse("traveller", kwargs={"url": self.url})
`views:
class FullTraveller:
def get_origin(self):
return Origin.objects.all()
def get_destination(self):
return Destination.objects.all()
def get_transport(self):
return Transport.objects.all()
def get_passengers(self):
return Passengers.objects.all()
class TravellerView(FullTraveller, ListView):
template_name = 'index.html'
model = Traveller
queryset = Traveller.objects.all()
paginate_by = 1
class FilterTravelView(FullTraveller,ListView):
def get_queryset(self):
if self.request.GET.getlist("origin") and self.request.GET.getlist("destination") and self.request.GET.getlist(
"transport") and self.request.GET.getlist("destination"):
queryset = Traveller.objects.filter(origin__in=self.request.GET.getlist("origin"),
destination__in=self.request.GET.getlist("destination"),
transport__in=self.request.GET.getlist("transport"),
passengers__in=self.request.GET.getlist("passengers"))
else:
queryset = Traveller.objects.filter(Q(origin__in=self.request.GET.getlist("origin")) | Q(
destination__in=self.request.GET.getlist("destination")) | Q(
transport__in=self.request.GET.getlist("transport"))| Q(
passengers__in=self.request.GET.getlist("passengers")))
return queryset
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context["origin"] = ''.join([f"origin={x}&" for x in self.request.GET.getlist("origin")])
context["destination"] = ''.join([f"destination={x}&" for x in self.request.GET.getlist("destination")])
context["transport"] = ''.join([f"transport={x}&" for x in self.request.GET.getlist("transport")])
context["passengers"] = ''.join([f"passengers={x}&" for x in self.request.GET.getlist("passengers")])
return context
forrm in template
`
```
```
I tried various options with widgets, but it didn’t work to insert them into the template

How to pass data (specific fiiled) from views.py to models.py

I have a problem. How can i pass the data (def maybe) from models.py
I need this for filter by category in future
class Tag(models.Model):
.......
category = models.ForeignKey(Category, null=True, on_delete=models.PROTECT, related_name='category', verbose_name='Tag category')
......
def get_category(self):
return self.category
To views.py. This is it doesn't work
class GetDetailTag(DetailView):
model = Tag
template_name = 'main/catalog.html'
context_object_name = 'tag'
category = Tag.get_category
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(**kwargs,)
context['pansion_in_tag_list'] = Pansions.objects.filter(tags__slug=self.kwargs['slug'])
context['tags_in_category'] = Tag.objects.filter(category__slug = '...INSERT THE DATA FROM MODEL HERE...')
return context
I was trying to call the 'def'(get_category) in views.py
Anyway? How i can to do that?
You can just obtain this from the tag, so:
{{ tag.category }}
or in the DetailView:
class TagDetailView(DetailView):
model = Tag
template_name = 'main/catalog.html'
context_object_name = 'tag'
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(object_list=object_list, **kwargs)
context['pansion_in_tag_list'] = Pansions.objects.filter(
tags__slug=self.kwargs['slug']
)
context['tags_in_category'] = Tag.objects.filter(
category_id=self.object.category_id
)
# category = self.object.category (obtain the category)
return context

Django FieldError : Cannot resolve keyword 'total_sales' into field

This is the query I am running to get Total Sales for each party.
Party.objects.annotate(total_sales=Sum('sales__salestransaction__total_cost'))
It shows correct results. But when I try to apply in my view with get_queryset, it is not working and shows a FieldError which is:
Cannot resolve keyword 'total_sales' into field. Choices are: party_address, party_id, party_name, party_phone, sales
My View
class PartyListView(ListView):
paginate_by = 2
model = Party
template_name = 'mael/parties.html'
def querystring(self):
qs = self.request.GET.copy()
qs.pop(self.page_kwarg, None)
return qs.urlencode()
def get_queryset(self):
qs = super().get_queryset()
if 'q' in self.request.GET:
search_txt = self.request.GET['q']
qs = qs.filter(party_name__icontains=search_txt).annotate(total_sales=Sum('sales__salestransaction__total_cost'))
return qs.order_by('total_sales')
def get(self, request):
form = PartyForm()
party_list = self.get_queryset()
qrstring = self.querystring()
paginator = Paginator(party_list, 5)
page_number = request.GET.get('page')
party_list = paginator.get_page(page_number)
return render(request, self.template_name, {'form': form, 'party_list': party_list, 'querystring': qrstring})
Models
class Party(models.Model):
party_id = models.BigAutoField(primary_key=True)
party_name = models.CharField(max_length=128)
party_phone = models.CharField(max_length=128)
party_address = models.CharField(max_length=128)
def __str__(self):
return self.party_name
class Sales(models.Model):
invoice_no = models.BigAutoField(primary_key=True)
invoice_date = models.DateField(default=date.today)
party = models.ForeignKey(Party, on_delete=models.CASCADE)
def __str__(self):
return str(self.invoice_no)
class SalesTransaction(models.Model):
sales = models.ForeignKey(Sales, on_delete=models.CASCADE)
item_qty = models.PositiveIntegerField(default=0)
total_cost = models.PositiveIntegerField(default=0)
def __str__(self):
return self.item_name
What is a problem with the get_queryset function and how can I solve this error? Please help.
You can not .order_by('total_sales') in case the if 'q' in self.request.GET returns False, you thus should annotate in both cases:
def get_queryset(self):
qs = super().get_queryset().annotate(
total_sales=Sum('sales__salestransaction__total_cost')
)
if 'q' in self.request.GET:
search_txt = self.request.GET['q']
qs = qs.filter(party_name__icontains=search_txt)
return qs.order_by('total_sales')

not enough values to unpack (expected 2, got 1)

I have a problem with a queryset in one view. My idea is show all users who are not registered in a program, I put here the models:
models.py
class UCAUser(AbstractUser):
dni_cif=models.CharField(
max_length=9,
blank=True,
verbose_name="DNI/CIF"
)
class InscripcionRealizada(models.Model):
formulario = models.ForeignKey(Formulario)
inscrito = models.ForeignKey(UCAUser,related_name="inscripciones_realizadas")
fecha_registro = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = "Inscripción realizada"
verbose_name_plural = "Inscripciones realizadas"
def __str__(self):
return "{} - {} - {}".format(self.formulario.programa, self.formulario.edicion, self.inscrito)
You can see UCAUser and InscripcionRealizada are connected by InscripcionRealizada.inscrito field.
view.py
class InscribirUsuariosListView(ListView):
template_name = "inscripciones/InscribirUsuariolist.html"
model = UCAUser
group_required = ['Administrador']
login_url = "auth-login"
def get_queryset(self):
qs = super(InscribirUsuariosListView, self).get_queryset()
return qs.filter(UCAUser.objects.filter(inscripciones_realizadas__formulario!=self.kwargs['formulario_id']))
def get_context_data(self, **kwargs):
context = super(InscribirUsuariosListView, self).get_context_data(**kwargs)
context['formulario_id'] = self.kwargs['formulario_id']
return context
When I try this, I get an error:
not enough values to unpack (expected 2, got 1)
Any idea?

form.is_valid method keeps failing

I'm trying to make an editing page for the users to update an object data. However, form.is_valid() keeps failing, I have no idea why.
My model:
class Thread(models.Model):
title = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
creator = models.ForeignKey(User, blank=True, null=True)
body = models.TextField(max_length=10000)
USER_TYPES = (
('INI','Iniciante'),
('INT','Intermediário'),
('AVA','Avançado')
)
user_type = models.CharField(max_length=20, choices = USER_TYPES, default='INI')
category = models.ForeignKey(Category)
orcamento = models.IntegerField(default=0)
slug = models.SlugField(max_length=40, unique=True)
def get_absolute_url(self):
return "/%s/" % self.slug
def __str__(self):
return self.title
def save(self, **kwargs):
slug_str = "%s %s" % (self.category, self.title)
unique_slugify(self, slug_str)
super(Thread, self).save(**kwargs)
My view:
def edit_thread(request, thread_slug):
thread = Thread.objects.get(slug=thread_slug)
if request.method == 'POST':
form = EditThread(request.POST)
if form.is_valid():
thread.title = form.cleaned_data['title']
thread.orcamento = form.cleaned_data['orcamento']
thread.user_type = form.cleaned_data['experiencia']
thread.body = form.cleaned_data['pergunta']
thread.save()
return HttpResponseRedirect('/thread' + thread.get_absolute_url())
else:
data = {'title' : thread.title, 'experiencia':thread.user_type, 'orcamento' : thread.orcamento, 'pergunta': thread.body}
form = EditThread(initial=data)
return render(request, 'edit_thread.html', {
'form': form })
My form:
class EditThread(forms.ModelForm):
title = forms.CharField(label='Título', max_length=200, error_messages=my_default_errors)
orcamento = forms.IntegerField(label='Preço máximo', error_messages=my_default_errors)
experiencia = forms.ChoiceField(label='Você é um usuário...', choices=Thread.USER_TYPES, error_messages=my_default_errors)
pergunta = forms.CharField(label='Pergunta', widget=forms.Textarea, error_messages=my_default_errors)
class Meta:
model = Thread
def __init__(self, *args, **kwargs):
super(EditThread, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.layout = Layout(
Div('title',
'experiencia',
PrependedAppendedText('orcamento', 'R$', ',00', active=True),
'pergunta',
FormActions(
Submit('save', 'Salvar alterações'),
)))
When accessing the page, the form gets pre-populated with the object's data as it should.
Your form should be inherited from the simple forms.Form instead of the forms.ModelForm:
class EditThread(forms.Form):
...
I would suggest you look at django's class based UpdateView. It can generate an update form for you or you could give it a custom ModelForm by overriding the form_class attribute on your view. When using a ModelForm, you also have to specify which model the form is for eg:
class EditThread(forms.ModelForm):
"field definitions ..."
class Meta:
model = Thread
fields = ['my_field_1', 'my_field_2']