How to change the button based on the user input? - python

I am implementing a pypi package called django-shopping-card https://pypi.org/project/django-shopping-cart/, so the users can see their saved posts.
My issue is that I could not make the button to display "Remove Post" instead of "Add to Card", if the post was added already. I have tried to create a different method to pass the posts which have been saved, but that caused a an error, as I cannot access the key and values of the cart without for loop. I am new to this and I would highly appreciate any comments and suggestions.
def add_fav(request, id):
cart = Cart(request)
post = Auction.objects.get(id=id)
cart.add(product=post)
return redirect("watchlist")
def item_clear(request, id):
cart = Cart(request)
product = Auction.objects.get(id=id)
cart.remove(product)
return redirect("watchlist")
def items_clear(request):
cart = Cart(request)
cart.clear()
return redirect("watchlist")
def get_cart(request):
return render(request, 'auctions/watchlist.html', {'cart': Cart(request)})
listings.html
{% block body %}
{% for auction in object_list %}
<div class="col-md-4">
<div class="card mb-2">
<div class="card-body">
<h5 class="card-title">{{ auction.name }}</h5>
Price: {{ auction.price }}<br>
<p class="card-text">{{ auction.description|slice:":10" }} ...</p>
{{ auction.author }}
Category: {{ auction.category }}
<hr><img class="card-img-top" src="{{ auction.image.url }}" alt="no" ><br>
{% for key,value in request.session.cart.items|slice:1 %} <br>
{% if value.product_id == auction.id %}
- Delete
{% endif %}
{% endfor %}
<a class="btn btn-primary" id="add_card" href="{% url 'add_fav' auction.id %}"
style="margin-top: 10px; ">Add to card</a><br>
</div>
{{ text }}
</div>
</div>
{% endfor %}
{% endblock %}

Related

List with checked checkboxes in Django

So, i want to get the checked checkboxes items ids as a list and show them on another page. But when i get to that specific page i get the value 'None' instead of the list of ids. What could go wrong? I tried some different versions from another questions already posted on the site, but the result was the same.
Here is the code:
models.py:
from django.db import models
class afirmatii(models.Model):
text = models.CharField(max_length = 250)
def __str__(self):
return self.text
views.py:
def exam(request):
if request.method == 'POST':
checks = request.POST.get('selected[]')
request.session['checks2'] = checks
context = {
'title' : 'Title1',
'aff': afirmatii.objects.order_by('id')
}
return render(request, 'pages/exam.html', context)
def result(request):
checks = request.session.get('checks2')
context = {
'title' : 'Title2',
'checks': checks
}
return render(request, 'pages/result.html', context)
exam.html:
{% extends "./base.html" %}
{% block content %}
<div class="text-break">
<form action="{% url 'result' %}" method="POST">
{% csrf_token %}
{% for q in aff %}
<div class="border mb-3 rounded-sm bg-light p-2">
<div class="custom-control custom-checkbox checkbox-info">
<input type="checkbox" class="custom-control-input" id="{{ q.id }}" name = "selected[]">
<label class="custom-control-label" for="{{ q.id }}" name = 'selected[]'> {{ q.text }} </label>
</div>
</div>
{% endfor %}
<button type="submit" class="btn btn-md btn-outline-info">Next</button>
</form>
</div>
{% endblock content %}
result.html:
{% extends "./base.html" %}
{% block content %}
<body>
<div class="text-center">
<p class="pb-5"> {{ checks }} </p><br>
<div class="row">
<div class="col">
Home
</div>
<div class="col">
Learn more
</div>
</div>
</div>
</body>
{% endblock content %}
You can try use FORMSETS A formsets is a layer of abstraction to work with multiple forms on the same page.
You can paint the list of questions according to records in the table and get ids (or other fields) of the marked answers
forms.py
class ExamForm(forms.Form):
checkbox = forms.BooleanField(required=False)
id = forms.CharField(widget=forms.HiddenInput)
text = forms.CharField(widget=forms.HiddenInput)
views.py
from django.shortcuts import render
from django.forms import formset_factory
from .forms import *
def exam(request):
aff = afirmatii.objects.order_by('id')
exam_formset = formset_factory(ExamForm, extra=0)
formset = exam_formset(initial=[{'id': x.id, 'text': x.text} for x in aff])
checks = []
if request.method == 'POST':
formset = exam_formset(request.POST)
if formset.is_valid():
for form in formset.forms:
if form.cleaned_data.get('checkbox', None):
checks.append(form.cleaned_data)
context = {
'formset': formset,
'checks': checks,
}
return render(request, 'pages/exam.html', context)
exam.html
{% if not checks %}
<h1>Exam:</h1>
<form action="{% url 'exam' %}" method="POST">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset.forms %}
<div class="form-group">
{{ form.checkbox }}
{{ form.text.value }}
{{ form.id }}
{{ form.text }}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{% else %}
<h1>Results:</h1>
{% for check in checks %}
<p>{{ check.id }} {{ check.text }}</p>
{% endfor %}
{% endif %}

How to post data from google books API to your Book model using Django

I know this is my first question and I wouldn't be like writing it here, but I have a problem which I couldn't handle for 2 days now.
I am writing an app in Django, and my goal is to handle requests from google books API and display books in the template which I did.
I wrote a function like this
services.py
from googleapiclient.discovery import build
import json
def get_books_data(query):
"""Retriving data from google books API"""
service = build('books',
'v1',
developerKey=API_KEY
)
request = service.volumes().list(q=query)
response = request.execute()
book_list = [response['items'][item]['volumeInfo']
for item in range(len(response['items']))]
return book_list
I get a list of key: value pairs representing ten books from API.
I passed them into a template like this
views.py
def search(request):
query = request.GET.get('q')
books = get_books_data(query)
context = {
'books': books
}
return render(request, 'books_list.html', context)
This is how book_list.html looks like.
list_book.html
{% extends 'base.html' %}
{% load static %}
{% block content%}
{% for book in books %}
<div class="row">
<div class="col-lg-8 mx-auto">
<ul class="list-group shadow">
<li class="list-group-item">
<div class="media align-items-lg-center flex-column flex-lg-row p-3">
<div class="media-body order-2 order-lg-1">
<h5 class="mt-0 font-weight-bold mb-2">{{ book.title }}</h5>
<p class="font-italic text-muted mb-0 small">{{ book.subtitle }}</p>
{% for identifier in book.industryIdentifiers %}
<p class="font-italic text-muted mb-0 small">{{ identifier.type }} : {{ identifier.identifier }}</p>
{% endfor %}
<p class="font-italic text-muted mb-0 small">Language: {{ book.language }}</p>
<p class="font-italic text-muted mb-0 small">Published date: {{ book.publishedDate }}</p>
<div class="media-body order-2 order-lg-1">
{% if book.authors %}
<h6 class="font-weight-bold my-2">Authors:</h6>
{% for author in book.authors %}
<p class="font-italic text-muted mb-0 small">{{ author }}</p>
{% endfor %}
{% endif %}
</div>
{% if book.pageCount %}
<div class="d-flex align-items-center justify-content-between mt-1">
<h6 class="font-weight-bold my-2">Number of pages: {{book.pageCount}}</h6>
</div>
{% endif %}
</div>
{% if book.imageLinks %}
<img class="thumbnail" src="{{book.imageLinks.thumbnail}}" alt="">
{% else %}
<img class="thumbnail2" src="{% static 'images/placeholder4.png'%}" alt="">
{% endif %}
</div>
<form action="." method="post">
{% csrf_token %}
<button type="submit" class="btn btn-primary">ADD THIS BOOK TO YOUR BOOKSHELF</button>
</form>
</li>
</ul>
</div>
</div>
{% endfor %}
{% endblock content %}
And last part of my task is to have a button in each card with a book, I can use to save a particular book from API to the database.
I am a beginner in Django, and I've tried to use forms, I've read, I could use Django Rest Framework somehow but really, I don't have an idea, how I could approach this problem.
Please, Can you help me?
Than you in advance.

How to loop though user objects in django

I want to show all the user's Items.
Currently I can only show 1 object
my_items.html (where i want it to show)
{% extends 'base.html' %}
{% block content%}
<main role="main">
<div class="container">
<!-- Example row of columns -->
<div class="row">
{% for item in item %}
<!--{% if item.id == request.user.id %}-->
<div class="col-md-4">
<div class="col-md-4">
<img style="max-width: 100px; max-height: 300px" src="{{ item.thumb.url }}">
</div>
<h2>{{ item.name }}</h2>
<p>{{ item.snippet }}</p>
<p>{{ item.date }}</p>
<p><a class="btn btn-warning" href="#" role="button">Edit</button></a></p>
<p><a class="btn btn-danger" href="#" role="button">Delete</a></p>
</div>
<!--{% endif %}-->
{% endfor %}
</div>
<hr>
</div> <!-- /container -->
</main>
{% endblock %}
views.py
def item_myitems(request):
item = Item.objects.all().order_by('date')
return render(request, 'items/my_items.html', {'item': item})
I tried using filter() and get() on views.py
You should use a plural name to pass your items to your view:
def item_myitems(request):
items = Item.objects.all().order_by('date')
return render(request, 'items/my_items.html', {'items': items})
So you can distinguish one item from many items when you loop through them in your view:
{% for item in items %}
omg I got it working, i feel so dumb right now LOL
I uncommented my if in the html and set to this > {% if item.author_id == request.user.id %} i was comparing with the item id instead of the author_id

i am getting an error saying category matching query does not exist

The voting proceess is working fine with this code. The problem is only when redirecting after voting the options.
Exception Type:DoesNotExist
Exception Value:
Category matching query does not exist.
category = Category.objects.get(slug=slug)
urls.py
path('<slug>/',views.options,name='options'),
path('<slug>/vote/', views.vote, name='vote'),
views.py
def home(request):
categories = Category.objects.filter(active=True)
return render(request,'rank/base.html',{'categories': categories,'title':'TheRanker'})
def options(request,slug):
category = Category.objects.get(slug=slug)
options = Option.objects.filter(category=category)
return render(request,'rank/options.html',{'options':options,'title':'options'})
def vote(request,slug):
option = Option.objects.get(slug=slug)
if Vote.objects.filter(slug=slug,voter_id=request.user.id).exists():
messages.error(request,'You Already Voted!')
return redirect('rank:options',slug)
else:
option.votes += 1
option.save()
voter = Vote(voter=request.user,option=option)
voter.save()
messages.success(request,'Voted!')
return redirect('rank:options',slug)
options.html
{% extends "rank/base.html" %}
<title>{% block title %}{{title}}{% endblock title%}</title>
{% load bootstrap4 %}
{% block content %}
<center><br>
<center>{% bootstrap_messages %}</center>
<ol type="1">
{% for option in options %}
<div class="col-lg-6 col-md-6 mb-6">
<div class="card h-100">
<div class="card-body">
<b><li>
<img src="/media/{{option.image}}" width="200" height="100">
<h4>{{option.name}}
</h4>
<h5 class="card-text">{{ option.details}}</h5>
<h5>{{ option.votes }} votes</h5>
<form action="{% url 'rank:vote' option.slug %}" method="post">
{% csrf_token %}
<input type="submit" class="btn btn-success" value="Vote" >
</form>
</li></b>
</div>
<div class="card-footer">
<small class="text-muted"></small>
</div>
</div>
</div>
{% endfor %}
</ol>
</center>
{% endblock content%}
You're confusing categories and options. The form sends the slug of the option, but then you redirect to the categories view using the same slug. But those are two different models.

Change BooleanField from False to True when message is opened

I've created my own message engine on Django framework to let users send messages to each others, here is my message model
models.py
class Message(models.Model):
sender = models.ForeignKey(UserModel, related_name="sender", on_delete='CASCADE')
receiver = models.ForeignKey(UserModel, related_name="receiver", on_delete='CASCADE')
msg_title = models.CharField(max_length=150, verbose_name='عنوان الرسالة', default='رسالة جديدة من مستخدم فوستانيا')
msg_content = models.TextField(max_length=1200,verbose_name='محتوى الرسالة')
created_at = models.DateTimeField(auto_now=True)
read = models.BooleanField(default=False)
Then am listing messages for the user, they can see the messages with read=False as a new message, they are able to click it to see the full message, I want the read status to be changed to True after the user clicks the message from the template,, How to do it!
urls.py
path('messages/', views.messages, name="messages"),
path('messages/<int:pk>/', views.message_page, name="message_page"),
views.py
#login_required
def messages(request):
inbox = Message.objects.filter(receiver=request.user, read=True)
context = {
'inbox': inbox,
}
return render(request, 'fostania_web_app/messages.html', context)
def message_page(request, pk):
current_msg = get_object_or_404(Message, pk=pk)
context = {
'current_msg': current_msg,
}
return render(request, 'fostania_web_app/message_page.html', context)
Message list template message.html
{% extends 'fostania_web_app/base.html' %}
{% block content %}
{% load static %}
{% if user.is_authenticated %}
<br><br>
<div class="card text-white bg-warning mb-3" style="max-width: 75rem;" align="right">
<div class="card-header">رسائل جديدة </div>
<div class="card-body">
<p class="card-text">
{% if new_messages.count != 0 %}
{% for msg in new_messages %}
<img src="{% static 'img/new-msg.png' %}"> {{ msg.msg_title }}
<br>
{% endfor %}
{% else %}
لا توجد رسائل غير مقروءة
{% endif %}
</p>
</div>
</div>
<!-- old msgs -->
<div class="card text-dark bg-ligh mb-3" style="max-width: 75rem;" align="right">
<div class="card-header"><img src="{% static 'img/inbox.png' %}"> صندوق الوارد </div>
<div class="card-body">
<p class="card-text">
{% for msg in inbox %}
<img src="{% static 'img/old-msg.png' %}"> {{ msg.msg_title }}<br>
{% endfor %}
</p>
</div>
</div>
{% else %}
يتوجب عليك تسجيل الدخول اولاً
{% endif %}
{% endblock %}
Message body after clicking and passing it's pk message_page.html
{% extends 'fostania_web_app/base.html' %}
{% block content %}
{% load static %}
<Br><br>
<div class="card bg-light mb-3" style="max-width: 50rem;" align="right ">
<div class="card-header">{{ current_msg.sender.name }}</div>
<div class="card-body">
<h5 class="card-title">{{ current_msg.msg_title }}</h5>
<p class="card-text">{{ current_msg.msg_content }}
<Br><br>
<button class="btn btn-success">إرسـال رد</button>
<button class="btn btn-danger">رجوع للرسائل </button>
</p>
</div>
</div>
{% endblock %}
You can avoid too much work by simply updating the message being read:
def message_page(request, pk):
current_msg = get_object_or_404(Message, pk=pk)
current_msg.read = True
current_msg.save()
context = {
'current_msg': current_msg,
}
return render(request, 'fostania_web_app/message_page.html', context)
BONUS:
instead of
{% if new_messages.count != 0 %}
{% for msg in new_messages %}
''' '''
{% endfor %}
{% else %}
لا توجد رسائل غير مقروءة
{% endif %}
Inside the loop, you can check whether the msg is read or not rather than send one more queryset, so you can simply do
{% for msg in new_messages %} # instead of new_messages, send all_messages
{% if msg.read %}
''' old message '''
{% else %}
''' new message '''
{% endif %}
{% empty %}
لا توجد رسائل غير مقروءة # don't really know what does that mean
{% endfor %}

Categories