Django: Как назначить кнопку для приема информации и сохранения()
Есть ли способ для кнопки сделать следующее: когда пользователь нажимает кнопку, она берет user.username
текущего пользователя и автоматически заполняет форму BookInstance
из models.py
и сохраняет ее в базе данных.
From models.py
:
class BookInstance(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
book = models.ForeignKey("Book", on_delete=models.RESTRICT, null=True)
imprint = models.CharField(max_length=200, blank=True, null=True)
due_back = models.DateField(blank=True, null=True)
borrower = models.ForeignKey(
User, on_delete=models.SET_NULL, blank=True, null=True)
LOAN_STATUS = (
('m', 'Maintenance'),
('o', 'On Loan'),
('a', 'Available'),
('r', 'Reserved')
)
status = models.CharField(
max_length=1, choices=LOAN_STATUS, blank=True, default='a')
class Meta:
ordering = ['due_back']
def __str__(self):
return f'{self.id} - {self.book.title}'
def get_absolute_url(self):
return reverse("catalog:book_list")
class Book(models.Model):
title = models.CharField(max_length=50)
author = models.ForeignKey(
'Author', on_delete=models.SET_NULL, null=True)
summary = models.TextField(
max_length=500, help_text="Enter brief description")
isbn = models.CharField('ISBN', max_length=13, unique=True)
genre = models.ManyToManyField(Genre, help_text="Select genre")
language = models.ForeignKey(
"Language", on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("catalog:book_detail", kwargs={"pk": self.pk})
Это мое от моего views.py
:
def borrowBook(request, pk):
context = {
'book_instance': BookInstance.objects.all()
}
success_url = reverse_lazy('catalog:index')
if request.method == "POST":
form = BorrowForm(request.POST or None)
if form.is_valid():
book_instance.id = BookInstance.objects.get(pk=pk)
book_instance.book = BookInstance.objects.get(book=book)
book_instance.borrower = request.user
book_instance.status = 'o'
book_borrowed_count = BookInstance.objects.filter(
owner=request.user).count()
if book_borrowed_count < 4:
book_instance = form.save(commit=False)
book_instance.save()
else:
print("Maximum limit reached!")
return redirect('catalog:index')
return render(request, 'catalog/book_detail.html', {'form': form})
вот из моего BorrowForm
из forms.py
:
class BorrowForm(forms.ModelForm):
class Meta:
model = BookInstance
fields = '__all__'
вот мое от моего urls.py
:
path("book_list/book/<int:pk>/borrow", views.borrowBook, name="borrowBook"),
Я также попробовал использовать CBV здесь:
class BorrowBookView(PermissionRequiredMixin, CreateView):
permission_required = 'login'
model = BookInstance
fields = '__all__'
template_name = 'catalog/borrow_form.html'
success_url = reverse_lazy('catalog:index')
def post(self, request, *args, **kwargs):
book_instance.id = BookInstance.objects.get(pk=pk)
book_instance.book = BookInstance.objects.get(book=book)
book_instance.borrower = request.user
book_instance.status = 'o'
book_instance = form.save(commit=False)
book_instance.save()
CBV путь от urls.py
:
path("book_list/book/<int:pk>/borrow/",
views.BorrowBookView.as_view(), name="book_borrow"),
Вот как я реализовал кнопку, используя предложения отсюда:
<form action="#" method="post">
{% csrf_token %}
<button
type="submit"
class="btn btn-dark flex-shrink-0 "
value="{{ book.id }}">Borrow
</button>
но когда я нажимаю, кажется, что ничего не сохраняется в базе данных и просто всплывают ошибки, хотя я могу реализовать кнопку или функцию из моих представлений неправильно. Спасибо и признателен за любую оказанную помощь.
Для этого вам не нужен Django form
. Формы обычно используются, когда вы хотите создать объект или отредактировать его поля (как на странице администратора). В то время как здесь user
не редактирует и не создает объект (книгу), а заимствует его.
По сути, нам просто нужно перечислить все доступные экземпляры книг (status='a')
и иметь кнопку для "заимствования". Действие заимствования заключается в обновлении status
до 'r'
или 'o'
и обновлении заемщика до текущего user
, который гарантированно существует внутри объекта request
по LoginRequiredMixin
views.py
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import View
from django.contrib import messages
from django.urls import reverse
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from .models import BookInstance
class BorrowBook(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
book_id = kwargs['pk']
available_books = BookInstance.objects.filter(book__pk=book_id, status='a')
return render(request, 'borrow_book.html', {'available_books': available_books})
def post(self, request, *args , **kwargs):
book_instance_id = request.POST['id']
obj = get_object_or_404(BookInstance, id=book_instance_id)
obj.status = 'r'
obj.borrower = request.user
# Maybe also update due_back data
# obj.due_back = ...
obj.save()
messages.success(request, "Your book is reserved.")
# I used the redirection to the same template
# But you probably want to send the user somewhere else
return HttpResponseRedirect(reverse('core:borrow-book', kwargs={'pk': 1}))
borrow_book.html
{% extends 'base.html' %}
{% block content %}
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% for instance in available_books %}
<form action="{% url 'core:borrow-book' instance.book.id %}" method="POST">
{% csrf_token %}
<input type="hidden" name="id" value="{{instance.id}}">
<p>{{instance.book}}</p>
<p>{{instance.book.language.name}}</p>
<input type="submit" value="Borrow this book.">
</form>
{% endfor %}
{% endblock content %}
urls.py
from django.urls import path
from core import views
app_name = 'core'
urlpatterns = [
path("book_list/book/<int:pk>/borrow/", views.BorrowBook.as_view(), name="borrow-book"),
]