Заполнение формы FormMixin
Можно ли заполнить данные формы FormMixin, не передавая переменную формы в шаблон? У меня есть шаблон, но я не понимаю, как создать форму с помощью Django, поэтому я просто указываю атрибут name в шаблоне. Форма создается, все хорошо, я переопределяю метод
get_initial(), но форма не заполняется Возможно ли это сделать или мне нужно передать переменную формы?
class CommentEditView(View, FormMixin):
form_class = EditCommentForm
def get_initial(self):
initial = super().get_initial()
comment = get_object_or_404(Comment, pk=15)
initial['review_text'] = comment.review_text
initial['grade'] = comment.grade
return initial
def get(self, request, comment_id):
return render(request, 'catalog/review-edit.html')
class EditCommentForm(ModelForm):
class Meta:
model = Comment
fields = ['review_text', 'grade']
<form method="POST">
{% csrf_token %}
<textarea class="product-detail-reviews-textarea" name="review_text" id="id_review_text"></textarea>
{% for error in form.review_text.errors %}
<p class="product-detail-reviews-error">* {{ error }} </p>
{% endfor %}
<div class="product-detail-reviews-row">
<div class="product-detail-reviews-stars">
<p>Stars:</p>
<div class="rating-area">
<input type="radio" id="id_grade_five" name="grade" value="5">
<label for="id_grade_five" title="Star «5»"></label>
<input type="radio" id="id_grade_four" name="grade" value="4">
<label for="id_grade_four" title="Star «4»"></label>
<input type="radio" id="id_grade_three" name="grade" value="3">
<label for="id_grade_three" title="Star «3»"></label>
<input type="radio" id="id_grade_two" name="grade" value="2">
<label for="id_grade_two" title="Star «2»"></label>
<input type="radio" id="id_grade_one" name="grade" value="1">
<label for="id_grade_one" title="Star «1»"></label>
</div>
</div>
<button type="submit" class="product-detail-reviews-link">Confirm</a>
</div>
{% for error in form.grade.errors %}
<p class="product-detail-reviews-error">*{{ error }} </p>
{% endfor %}
</form>
Переопределенный метод get_initial()
Вы выводите поля вручную, поэтому вам также нужно позаботиться о том, чтобы включить начальные значения для этих полей. Например, для review_text
<textarea class="product-detail-reviews-textarea" name="review_text" id="id_review_text">{{ form.review_text.initial }}</textarea>
Если вы просто хотите добавить несколько CSS-классов к элементам формы, лучше объявить их в виджетах, как описано здесь, или в форме Meta, как описано здесь. Например:
class EditCommentForm(ModelForm):
class Meta:
model = Comment
fields = ["review_text", "grade"]
widgets = {"review_text": Textarea(attrs={"class": "product-detail-reviews-textarea"})}
Таким образом, вы можете позволить django делать большую часть рендеринга:
{{ form.review_text }}
{% for error in form.review_text.errors %}
<p class="product-detail-reviews-error">* {{ error }} </p>
{% endfor %}
Кроме того, подумайте о том, чтобы включить метки для элементов управления формы. Они предлагают больше, чем просто описание поля:
- Текст метки не только визуально связан с соответствующим текстовым вводом, он также связан с ним программно. Это означает, что, например, программа чтения с экрана будет считывать метку, когда пользователь сосредоточен на вводе формы, облегчая пользователю вспомогательных технологий понимание того, какие данные следует ввести.
- Когда пользователь щелкает или касается метки, браузер передает фокус на связанный с ней ввод (результирующее событие также поднимается для ввода). Увеличение области попадания для фокусировки ввода дает преимущество всем, кто пытается его активировать, включая тех, кто использует устройство с сенсорным экраном.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label
Вы не передаете форму в контекст, в этом и заключается проблема. Не переопределяйте .get(…)
: FormMixin
добавит элемент в контекст да, но, переопределив метод .get(…)
и просто отобразив шаблон, он даже не построит контекст.
Вы можете позволить TemplateView
сделать работу за вас: это сгенерирует контекст, а затем отобразит шаблон:
from django.views.generic import TemplateView
class CommentEditView(FormMixin, TemplateView):
form_class = EditCommentForm
template_name = 'catalog/review-edit.html'
def get_initial(self):
initial = super().get_initial()
comment = get_object_or_404(Comment, pk=15)
initial['review_text'] = comment.review_text
initial['grade'] = comment.grade
return initial
# no def get(self, request, comment_id)
Что касается шаблона, то вы загружаете данные из формы в шаблон, например, так:
<textarea class="product-detail-reviews-textarea" name="review_text" id="id_review_text">
{{ form.review_text.widget.value }}
</textarea>
Если бы у меня было гипотетическое приложение под названием "myapp", я бы:
- Направьте корневой urls.py на urls.py myapp'а, используя
include
:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('myapp.urls'))
]
- Возможно, модель выглядит так:
class Comment(models.Model):
review_title = models.CharField(max_length=100)
review_text = models.TextField(max_length=1000)
grade = models.IntegerField(validators=[
MinValueValidator(1), MaxValueValidator(5)
])
def __str__(self):
return str(self.review_title)
def get_absolute_url(self):
return reverse('myapp:comment-detail', kwargs={"pk": self.pk})
- У меня будет несколько url-путей:
from django.urls import path
from myapp.views import (
CommentListView, CommentCreateView,
CommentUpdateView, CommentDetailView
)
app_name = "myapp"
urlpatterns = [
path('', CommentListView.as_view(), name='comment-list'),
path('create/', CommentCreateView.as_view(), name='comment-create'),
path('edit/<int:pk>/', CommentUpdateView.as_view(), name='comment-edit'),
path('comment/<int:pk>/', CommentDetailView.as_view(), name='comment-detail'),
]
- views.py будет выглядеть следующим образом:
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views.generic import (
ListView, DetailView, CreateView, UpdateView
)
from myapp.forms import EditCommentForm
from myapp.models import Comment
class CommentListView(ListView):
template_name = 'catalog/comments-list.html'
model = Comment
class CommentCreateView(CreateView):
template_name = 'catalog/comment-form.html'
form_class = EditCommentForm
def form_valid(self, form):
self.object = form.save()
return HttpResponseRedirect(self.object.get_absolute_url())
class CommentUpdateView(UpdateView):
template_name = 'catalog/comment-form.html'
form_class = EditCommentForm
model = Comment
class CommentDetailView(DetailView):
template_name = 'catalog/comment-detail.html'
model = Comment
- Сделайте три шаблона:
catalog/comments-list.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<div><a href="{% url 'myapp:comment-create' %}">Create</a></div>
<h2>Comments</h2>
{% for comment in object_list %}
<div>
<a href="{% url 'myapp:comment-detail' comment.pk %}">{{ comment.review_title }}</a>
</div>
{% endfor %}
</div>
</body>
</html>
catalog/comment-form.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div style="margin: 100px auto; width: 400px;">
<form method="POST">
{% csrf_token %}
{{ form.as_div }}
<input type="submit" class="product-detail-reviews-link" value="Confirm">
</form>
</div>
</body>
</html>
catalog/comment-detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<h2>The Review</h2>
<div>{{ object.review_title }}</div>
<div>{{ object.review_text }}</div>
<div>{{ object.grade }}</div>
<a href="{% url 'myapp:comment-list' %}">back to list</a>
<a href="{% url 'myapp:comment-edit' object.pk %}">edit comment</a>
</div>
</body>
</html>
Это должно проиллюстрировать, как работают формы, как создавать новые экземпляры и редактировать их. Надеюсь, это поможет.