Django: форма публикации и список записей на одной странице

#python #html #django

#python #HTML #django

Вопрос:

Я создаю сайт с несколькими пользователями, создаю сообщения с изображениями и возможностью добавлять / удалять друзей. Таким образом, легко создать две разные страницы для списка записей и создать новую. Но, конечно, это выглядит лучше, когда вы можете читать сообщения и создавать новые в одном и том же месте.

Насколько я понимаю (изучаю django менее месяца), я не могу подключить 2 представления к одному и тому же URL, поэтому наиболее логичным способом, который я вижу, является объединение 2 представлений в одно, я также попытался поиграть с наследованием шаблона для отображения формы post, включив шаблон, но на самом деле это не такработа.

Ниже вы можете увидеть мои представления, модель публикации и шаблоны. Спасибо за внимание.

views.py:

 from braces.views import SelectRelatedMixin
from . import models
from django.views import generic
from django.contrib.auth.mixins import LoginRequiredMixin

class PostList(SelectRelatedMixin, generic.ListView):
    model = models.Post
    select_related = ('user',)

class CreatePost(LoginRequiredMixin, SelectRelatedMixin, generic.CreateView):
    fields = ('post_message', 'post_image')
    model = models.Post
    select_related = ('user',)

    def form_valid(self, form):
        self.object = form.save(commit = False)
        self.object.user = self.request.user
        self.object.save()
        return super().form_valid(form)
  

models.py:

 import misaka

class Post(models.Model):
    user = models.ForeignKey(User, on_delete = models.CASCADE, related_name = 'posts')
    posted_at = models.DateTimeField(auto_now = True)
    post_message = models.TextField()
    message_html = models.TextField(editable = False)
    post_image = models.ImageField(upload_to = 'postpics', blank = True)

    def __str__(self):
        return self.post_message

    def save(self, *args, **kwargs):
        self.message_html = misaka.html(self.post_message)
        super().save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse('posts:all')

    class Meta:

        ordering = ['-posted_at']
        unique_together = ['user', 'post_message']
  

urls.py:

 app_name = 'posts'

urlpatterns = [
    path('', views.PostList.as_view(), name = 'all'),
    path('new/', views.CreatePost.as_view(), name = 'create'),
]
  

post_form.html (шаблон, позволяющий создать новый пост, который будет виден в post_list.html ):

 {% extends 'posts/post_base.html'%}
{% block post_content %}
<div class="post-form">
  <form action="{% url 'posts:create' %}" method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    <p>{{ form.post_message }}</p>
    <p>{{ form.post_image }}</p>
    <input id='post-submit' type="submit" value="Post">
  </form>
</div>
{% endblock %}
  

post_list.html:

 {% extends 'posts/post_base.html'%}
{% block post_content %}
<div class="post-container">
  {% for post in post_list %}
  <div class="current-post-container">
    {% include 'posts/_post.html'%}
  </div>
  {% endfor %}
</div>
{% endblock %}
  

_post.html (страницы, которые рендерит Мисака):

 <div class="post-info">
  <h5 id='post-owner' >{{post.user.first_name}} {{post.user.last_name}}</h5>
  <h6>{{ post.posted_at }}</h6>
  <p>{{ post.message_html|safe }}</p>
  <div>
    <img class='post-image'  src="/media/{{ post.post_image }}" alt="">
    <div>
      {% if user.is_authenticated and post.user == user and not hide_delete %}
      <a href="{% url 'posts:delete' pk=post.pk %}" title = 'delete'>Delete</a>
      {% endif %}
    </div>
  </div>
</div>
  

post_base.html:

 {% extends 'base.html' %}
{% block content%}
        {% block prepost %}{% endblock %}
        {% block post_content %}{% endblock %}
        {% block post_post %}{% endblock %}
{% endblock %}
  

Редактировать:
Задача была решена. Я добавил две строки template_name к обоим моим представлениям, так что теперь они выглядят так:

Создайте сообщение в views.py:

 class CreatePost(LoginRequiredMixin, SelectRelatedMixin, generic.CreateView):
    fields = ('post_message', 'post_image')
    model = models.Post
    select_related = ('user',)
    template_name = 'posts/post_list.html'
    template_name = 'posts/post_form.html'


    def form_valid(self, form):
        self.object = form.save(commit = False)
        self.object.user = self.request.user
        self.object.save()
        return super().form_valid(form)
  

Список записей в views.py:

 class PostList(SelectRelatedMixin, generic.ListView):
    model = models.Post
    select_related = ('user',)
    template_name = 'posts/post_list.html'
    template_name = 'posts/post_form.html'
  

Комментарии:

1. Пожалуйста, прочтите эту статью, здесь приведен пример создания динамического контента на странице с использованием django-forms и ajax realpython.com/django-and-ajax-form-submissions

2. Что касается редактирования: почему вы устанавливаете template_name дважды? У них будет просто второе из обоих значений afaik

Ответ №1:

Вы можете поместить post_create_form на ту же страницу, что и post_list_view нет необходимости создавать отдельное представление для создания записей, но вам нужно создавать их для редактирования и удаления. Вы можете предоставить всем этим представлениям одну и ту же HTML-страницу с разными URL-адресами. Используя template_name = 'example/example.html' , в Class_Based_Views . Надеюсь, я понимаю вашу проблему, если не уточню, почему вы не можете объединить два представления в одно.

Комментарии:

1. Я перепробовал так много способов объединить эти PostList и CreatePost views в один, но в любом случае это не сработало. В любом случае я вижу только форму создания или только список сообщений. Я думал о создании нового класса, который будет содержать весь код из этих двух классов и унаследует их оба, но это тоже не работает

Ответ №2:

 def posts(request):
posts = Post.objects.all()

form = PostForm(request.POST or None, request.FILES or None)
if request.method == "POST":
    if form.is_valid():
       ...

context={
    'posts'         : page_obj,
    'create_or_update_post_form' : form,

}
return  render(request, 'post/posts.html',context)
  

Вам трудно сделать это в представлении на основе классов?

Комментарии:

1. Я уже решил эту проблему, используя ваш предыдущий ответ, теперь я опубликую его.

Ответ №3:

Вы можете легко использовать представления на основе классов django.

  • Создавайте представления как
 from django.views.generic import ListView
from django.views.generic.edit import CreateView

class ModelCreate(CreateView):
    model = ModelName
    fields = ['field1', 'field2']
    template_name = 'same_page.html'
    success_url = reverse_lazy('list_view')


class ModelList(CreateView, ListView):
    model = ModelName
    fields = ['field1', 'field2']
    paginate_by = 5
    template_name = 'same_page.html'

    def get_context_data(self, *args, **kwargs):
        context = super().get_context_data(*args, **kwargs)
        context['form'] = self.get_form()
        return context

    # If form post redirect to ModelCreate View
    def post(self, request, *args, **kwargs):
        return ModelCreate.as_view()(request)
  
  • app/urls.py
 from django.urls import path
from app import views

path('list', views.ModelList.as_view(), name='list_view'),
path('add', views.ModelCreate.as_view(), name='add_view'),
  
  • Наконец, в templates/same_page.html
 <div class="row">
   <div class="col-sm-5">
      <form method="post" enctype="multipart/form-data">
         {% csrf_token %}
         {{form.as_p}}
         <button type="submit" value="submit" class="btn btn-primary btn-sm float-right">Submit</button>                              
       </form>
   </div>
   <div class="col-sm-5">
    {% if object_list %}
       {% for object in object_list %}
         <p>{{object.field1}}</p>
         <p>{{object.field2}}</p>
       {% endfor %}
    {% endif %}
   </div>
</div>
  

Надеюсь, это поможет.