#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>
Надеюсь, это поможет.