Объединение DetailView и CreateView в Django 1.6

У меня есть 2 отдельные модели, Post и Comment. Я использую DetailView для отображения содержимого сообщения и хочу использовать CreateView для отображения формы создания комментариев на той же странице. Каков самый чистый способ сделать это?

Единственное, что приходит на ум, это использовать пользовательское представление, которое и получает объект, и обрабатывает форму комментария, но это выглядит слишком грязно:

def post_detail(request, slug):
    post = get_object_or_404(Post, slug=slug)
    if request.POST:
        form = CommentForm(request.POST)
        # do comment form processing here
    return render(request, "post/post_detail.html", {
        "object": post, "comment_form": form})

Есть ли какой-нибудь чистый способ сделать это, используя представления на основе классов? Или просто какой-то способ отделить код отображения сообщений от кода обработки комментариев?


person Ruslan Osipov    schedule 26.12.2013    source источник
comment
Что грязного в этом взгляде? Если дело в том, что вы смешали GET и POST, попробуйте django.views.generic.base.View. Или создайте теги шаблонов для создания форм комментариев к объектам (как это было в старом django.contrib.comments).   -  person Maciej Gol    schedule 26.12.2013
comment
@kroolik Что грязного в том, что логика моих моделей комментариев и сообщений не разделена. Хотя мне нравится идея с тегами шаблонов. Таким образом, я могу иметь отдельный вид для создания комментариев.   -  person Ruslan Osipov    schedule 26.12.2013
comment
Вы можете посмотреть, как это делается здесь   -  person Maciej Gol    schedule 26.12.2013


Ответы (2)


Один из вариантов — использовать DetailView для сообщения и тег шаблона для отображения формы комментария. Отправьте форму комментария в Comment CreateView, который перенаправляется в DetailView в случае успеха.

Тем не менее, это может стать немного некрасивым, если форма недействительна. В крайнем случае вы всегда можете вызвать DetailView или его методы из одного из методов CreateView. Но ИМО, это вводит больше связи, а не меньше. Или у вас может быть отдельная служебная функция, которую вы можете вызывать из CreateView для отображения публикации, если в форме комментария есть ошибки.

Другой вариант — использовать AJAX для обработки формы комментариев (в отдельном CreateView) вместо загрузки новой страницы.

В конце концов, независимо от языка или фреймворка, будет существовать ограничение на то, насколько можно отделить представление, которое должно отображать один тип объекта и создавать другой.

person spoon    schedule 30.12.2013
comment
AJAX слишком неприятный, но тег шаблона был моим решением. Я использовал идею отсюда: github.com /django/django/blob/master/django/contrib/comments/ (спасибо @kroolik). Вот что я сделал в конце: github.com/ruslanosipov/ rblog/blob/master/comment/templatetags/ - person Ruslan Osipov; 31.12.2013
comment
Мне нравится это решение — его можно даже обобщить на любую модель, которую необходимо отредактировать в чужом DetailView. Итак, теперь мне любопытно: как вы справляетесь со случаями, когда форма комментария не проходит проверку? - person spoon; 01.01.2014
comment
Я перевожу пользователя на отдельную страницу, где он может отредактировать комментарий: github.com/ruslanosipov/rblog/blob/master/comment/views.py. Но отказ от использования AJAX — это просто личный выбор. - person Ruslan Osipov; 01.01.2014
comment
В этом выборе нет ничего плохого — я тоже иногда делал его в прошлом. Мне также нравится изящная деградация: даже если вы в конечном итоге добавите AJAX, полезно иметь возможность обрабатывать случай, когда у пользователя отключен javascript. - person spoon; 01.01.2014
comment
@RuslanOsipov первые две ссылки, которые вы предоставили, больше не доступны. - person therealak12; 23.04.2020
comment
@AK12 Честно говоря, я даже не помню, что это было 6 лет спустя. - person Ruslan Osipov; 25.04.2020

Можно комбинировать DetailView и CreateView. Вы используете класс для DetailView и другой класс для CreateView, затем вы создаете новый класс, который наследуется от View. Этот новый класс имеет методы get и post. Метод get вызывает DetailView, а метод post вызывает CreateView. Обратите внимание на использование reverse_lazy для success_url в CreateView. Итак, в основном ваш код должен выглядеть примерно так:

class PostView(DetailView):
    # your code 
    pass ;

class CommentView(CreateView):
    def get_success_url(self):
        return reverse_lazy('post_detail', kwargs={'pk': self.get_object(Post.objects.all().pk})

class PostCommentView(View):
    def get(self, request, *args, **kwargs):
         view = PostView.as_view()
         return view(request, *args, **kwargs) 

    def post(self, request, *args, **kwargs) :
         view = CommentView.as_view()
         return view(request, *args, **kwargs) 

Итак, ваш urls.py будет указывать на

PostCommentView 

Я переопределил get_success_url, потому что он попытается перейти к подробному представлению нового комментария, который не существует и не является тем, что вы хотите сделать. Таким образом, переопределение приведет вас к элементу DetailView сообщения.

Объяснение есть в документация.

person Iyanuoluwa Ajao    schedule 03.05.2018