So, I am new to the django and what I am trying to achive is to edit a comment in bootstrap modal.
My problem is that when I launch modal for editing specific comment, comment text isn't shown in modal. I am using the same CommentForm class for creating and editing comment, as I am using the same principle for the rest model classes in my app.
Here is the edit comment view:
def edit_comment(request, p_id):
comment = get_object_or_404(Comment, pk=p_id)
task_id = comment.task.id
task = get_object_or_404(Task, pk=task_id)
if request.method == "POST":
form = CommentForm(request.POST, instance=comment)
if form.is_valid():
form.save()
return redirect(reverse('task_details', kwargs={'p_id' : task.id}))
else:
data = {
'form' : CommentForm(instance=comment),
}
return render(request, "polls/task_details.html",data)
Because the list of all comments attached to the task are shown in task details, an this is where i launch edit modal, here is the view:
def task_details(request, p_id):
projects = Project.objects.filter(users=request.user)
task = get_object_or_404(Task, pk=p_id)
comments = Comment.objects.filter(task__id=p_id)
proj_id = task.project.id
project = get_object_or_404(Project, pk=proj_id)
if request.method == "POST":
data = {'task': task,
'comments': comments,
'project' : project,
'form' : CommentForm(),
'projects' : projects}
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.user = request.user
comment.type = "comment"
comment.task = task
comment.save()
return render(request, "polls/task_details.html", data)
else:
data = {'task': task,
'comments': comments,
'project' : project,
'form' : CommentForm(),
'projects' : projects}
data.update(csrf(request))
return render(request, "polls/task_details.html", data)
forms.py:
class CommentForm(ModelForm):
class Meta:
model = Comment
fields = ('comment_text',)
exclude = ('user', 'time_occurred', 'type', 'task', 'milestone')
widgets = {'comment_text': forms.Textarea(attrs={'class':"form-control",
'required':"",
'rows':3,
})}
labels = {"comment_text": _("Comment"),
}
urls.py:
url(r'^edit_comment/(?P<p_id>\d+)/$', views.edit_comment, {}, 'edit_comment'),
Comment is attached to the Task, and Comment inherits LogEvent abstract class, so here is the models.py part:
class Task(models.Model):
project = models.ForeignKey(Project)
user = models.ForeignKey(User, related_name='task_created_by')
assigned = models.ForeignKey(User, related_name='task_assigned_to', null=True)
priority = models.ForeignKey(Priority,null=True)
milestone = models.ForeignKey(Milestone)
name = models.CharField(max_length = 50)
description = models.CharField(max_length = 5000)
type = models.ForeignKey(Type, null=True)
state = models.CharField(max_length = 20, choices = State)
def __str__(self):
return self.name
class LogEvent(models.Model):
user = models.ForeignKey(User)
time_occurred = models.DateTimeField('time_occurred')
type = models.CharField(max_length = 50)
task = models.ForeignKey(Task, null=True, blank=True)
milestone = models.ForeignKey(Milestone, null=True, blank=True)
class Meta:
abstract = True
class Comment(LogEvent):
comment_text = models.TextField()
def save(self, *args, **kwargs):
''' On save, update timestamps '''
if not self.id:
self.time_occurred = datetime.datetime.today()
return super(Comment, self).save(*args, **kwargs)
def __str__(self):
return self.user.username
Finally, the template:
(This is the part of the task details template, where all comments attached to specific task are shown)
<div class="col-lg-12">
{% for comment in comments %}
<div class="well">
<p>
<i class="fa fa-fw fa-user"></i><strong>{{comment.user.get_full_name}}</strong>
<i class="fa fa-fw fa-clock-o"></i>{{comment.time_occurred}}
{% if comment.user == user %}
<a href=""
class="btn btn-info btn-xs btn-outline"
style="float: right; margin-left: 5px" data-toggle="modal" data-target="#EditModal{{forloop.counter}}"> <i class="fa fa-fw fa-edit"></i> Edit</a>
<!-- EDIT MODAL -->
<div class="modal fade" id="EditModal{{forloop.counter}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" >
<div class="modal-content" style=" border-color: #5cb85c;">
<div class="modal-header" style=" color: white;background-color: #5cb85c;border-color: #5cb85c;">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel" >Edit comment</h4>
</div>
<form action="{% url 'edit_comment' p_id=comment.id %}" method="post">
{% csrf_token %}
{% for field in form %}
<div class="modal-body">
{{field.errors}}
{{field}}
</div>
{% endfor %}
<div class="modal-footer">
<button type="button" class="btn btn-default btn-outline" data-dismiss="modal">Close</button>
<input type="submit" class="btn btn-success btn-outline" value="Save changes">
</div>
</form>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
{% endif %}
<p>{{comment.comment_text}}</p>
</div>
{% endfor %}
</div>
My question is what should I do to show the comment text in textarea inside the modal, or what have I missed, so the user can easily modify his comment, without copying the text before lauching the modal?
Related
I want to count number of replies on a particular post in Django
View.py
def forum(request):
profile = Profile.objects.all()
if request.method=="POST":
user = request.user
image = request.user.profile.image
content = request.POST.get('content','')
post = Post(user1=user, post_content=content, image=image)
post.save()
messages.success(request, f'Your Question has been posted successfully!!')
return redirect('/forum')
posts = Post.objects.filter().order_by('-timestamp')
return render(request, "forum.html", {'posts':posts})
Reply code
def discussion(request, myid):
post = Post.objects.filter(id=myid).first()
replies = Replie.objects.filter(post=post)
if request.method=="POST":
user = request.user
image = request.user.profile.image
desc = request.POST.get('desc','')
post_id =request.POST.get('post_id','')
reply = Replie(user = user, reply_content = desc, post=post, image=image)
reply.save()
messages.success(request, f'Your Reply has been posted successfully!!')
return redirect('/forum')
return render(request, "discussion.html", {'post':post, 'replies':replies})
model.py
class Post(models.Model):
user1 = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
post_id = models.AutoField
post_content = models.CharField(max_length=5000)
timestamp= models.DateTimeField(default=now)
image = models.ImageField(upload_to="images",default="")
def __str__(self):
return f'{self.user1} Post'
class Replie(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
reply_id = models.AutoField
reply_content = models.CharField(max_length=5000)
post = models.ForeignKey(Post, on_delete=models.CASCADE, default='')
timestamp= models.DateTimeField(default=now)
image = models.ImageField(upload_to="images",default="")
def __str__(self):
return f'{self.user1} Post'
My Forum.html code:
{% for post in posts %}
<div class="container-fluid mt-10">
<div class="row">
<div class="col-md-12">
<div class="card mb-4 forumcardcss">
<div class="card-header forumcardheader">
<div class="media flex-wrap w-100 align-items-center imgcss"> <img src="/media/{{post.image}}"
class="d-block ui-w-40 rounded-circle" alt="profileimage"style="width: 40px;height: 40px;"> <p class="ml-4 usernamecss"> {{post.user1}} </p>
<div class="media-body ml-3"> <button class="btn btn-light" style="color:blue; font-size: 13px;">Add or See reply </button>
</div>
<div class="text-muted small ml-3">
<div class="px-4 pt-3">Nmber of reply {{post.timestamp}} </div>
</div>
{% if user.is_superuser or user.is_staff %}
<button class="btn btn-danger btn-sm" onclick="window.mytest()">Delete Post</button>
<script type="text/javascript">window.mytest = function() { var isValid = confirm('If you click ok then its delete this post and related reply on it. Are you sure to delete?');if (!isValid) { event.preventDefault(); alert("It wont delete. Yay!");}}</script>
{% endif %}
</div>
</div>
<div class="card-body forumcardbody">
<p>{{post.post_content}}</p>
</div>
<div class="card-footer d-flex flex-wrap justify-content-between align-items-center px-0 pt-0 pb-3">
</div>
</div>
</div>
</div>
</div>
{% endfor %}
I want to do like this
where on the place of Number of reply, I want to display the number of replies of the particular post
Is there any way to find if Question(Post) has been answered(reply) on my post page(forum.py)
I want to do it like this If the Question has been answered then it should show "Answered" else "Not answered yet"
#Eega suggested the right answer just some changes in the code will help you
class Post(models.Model):
user1 = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
post_id = models.AutoField
post_content = models.CharField(max_length=5000)
timestamp= models.DateTimeField(default=now)
image = models.ImageField(upload_to="images",default="")
#property
def count_replies(self):
return self.replie_set.count()
def __str__(self):
return f'{self.user1} Post'
post = Post.objects.filter(id=myid).first() to post = Post.objects.filter(id=myid).first().prefetch_related('replies_set') This will make your query optimized
Also accept #Eega answer only, I have just showed you the edited code
Now I am suggesting one good method here
Post.objects.get(id=myid).annotate(post_count=Count("replie"))
Simply use this in your views without changing #models.py and access it in your template as post.post_count in for loop.
To archive this you can use the related name of the Post model (have a look at the documentation). Django will create a field for every foreign key that allows you to access the related model. By default, this will be named replie_set on the Post model.
This field you can then use to get the number of replies to a post by calling the count() method of the replie_set queryset. I would also add a method to the Post model that does that for you as a convenience.
To bring this together, your Post model would look like this:
class Post(models.Model):
user1 = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
post_id = models.AutoField
post_content = models.CharField(max_length=5000)
timestamp= models.DateTimeField(default=now)
image = models.ImageField(upload_to="images",default="")
#property
def count_replies():
return self.replies_set.count()
def __str__(self):
return f'{self.user1} Post'
Assuming that your forum.html template iterates over the posts like that:
{% for post in posts %}
...
<p>Posts: {{ post.count_replies }}</p>
...
{% endfor %}
You get the number of replies by calling post.count_replies(). Of course, if you don't want to add a dedicated method to the model you can just use do post.replie_set.count() directly.
An alternative - and more efficient method - is to annotate your posts with the reply count as Abdul Aziz Barkat suggests. To do this you have to change your view like that:
from django.db.models import Count
def forum(request):
profile = Profile.objects.all()
if request.method=="POST":
user = request.user
image = request.user.profile.image
content = request.POST.get('content','')
post = Post(user1=user, post_content=content, image=image)
post.save()
messages.success(request, f'Your Question has been posted successfully!!')
return redirect('/forum')
posts = Post.objects.annotate(count_replies=Count("replie")).order_by('-timestamp')
return render(request, "forum.html", {'posts':posts})
I changed only the second to last line here:
posts = Post.objects.annotate(count_replies=Count("replie")).order_by('-timestamp')
This adds the aggregated count of replies to each post as count_replies.
Then this value is used in the forum.html template like that:
{% for post in posts %}
<div class="container-fluid mt-10">
<div class="row">
<div class="col-md-12">
<div class="card mb-4 forumcardcss">
<div class="card-header forumcardheader">
<div class="media flex-wrap w-100 align-items-center imgcss"> <img src="/media/{{post.image}}"
class="d-block ui-w-40 rounded-circle" alt="profileimage"style="width: 40px;height: 40px;"> <p class="ml-4 usernamecss"> {{post.user1}} </p>
<div class="media-body ml-3"> <button class="btn btn-light" style="color:blue; font-size: 13px;">Add or See reply </button>
</div>
<div class="text-muted small ml-3">
<div class="px-4 pt-3">Number of replies {{ post.count_replies }} </div>
</div>
{% if user.is_superuser or user.is_staff %}
<button class="btn btn-danger btn-sm" onclick="window.mytest()">Delete Post</button>
<script type="text/javascript">window.mytest = function() { var isValid = confirm('If you click ok then its delete this post and related reply on it. Are you sure to delete?');if (!isValid) { event.preventDefault(); alert("It wont delete. Yay!");}}</script>
{% endif %}
</div>
</div>
<div class="card-body forumcardbody">
<p>{{post.post_content}}</p>
</div>
<div class="card-footer d-flex flex-wrap justify-content-between align-items-center px-0 pt-0 pb-3">
</div>
</div>
</div>
</div>
</div>
{% endfor %}
So, only a single line changed here either:
<div class="px-4 pt-3">Number of replies {{ post.count_replies }} </div>
Background: I've been working on the 'mini blog' challenge in Mozilla's tutorial. Got 'author' (user), 'post' working. Added 'comment'. With bits of code from this (among others), I managed to use a function-based view to get 'CommentForm' work on the 'post-detail' page. But trying to convert the function-based view to a class-based view stumped me. Because the various errors I encountered all relate to some key fundamental concepts, like explicit/implicit 'request', passing 'context', I've been working at it, hoping to understand Django better. But I'm getting nowhere. The problem is the form, 'CommentForm', doesn't render in the template. At one point, it rendered, but 'submit' the form led to not allowed error. I figured it related to 'GET' vs 'POST'. At this point, I'm not sure where the issue is--views? template? Appreciate some pointers.
Here's my code:
models.py
class Post(models.Model):
post = models.TextField(max_length=1000)
post_title = models.CharField(max_length=100)
description = models.TextField(max_length=500)
post_created_at = models.DateTimeField(auto_now_add=True)
post_updated_at = models.DateTimeField(auto_now=True)
author = models.ForeignKey(User, related_name="posts", on_delete=models.CASCADE)
#property
def num_comments(self):
return Comment.objects.filter(post_connected=self).count()
def __str__(self):
return f'{self.author or ""} – {self.post_title[:40]}'
def get_absolute_url(self):
return reverse('post-detail', args=[str(self.id)])
def get_absolute_url(self):
return "/blog/{}/".format(self.pk)
class Meta:
ordering = ['-post_created_at']
class Comment(models.Model):
comment_title = models.CharField(max_length=100)
comment = models.TextField(max_length=1000)
comment_created_at = models.DateTimeField(auto_now_add=True)
comment_updated_at = models.DateTimeField(auto_now=True)
commenter = models.ForeignKey(User, related_name="commented", null=True, blank=True, on_delete=models.CASCADE)
active = models.BooleanField(default=False)
post_connected = models.ForeignKey(Post, related_name='comment', on_delete=models.CASCADE, default=None, null=True) #
class Meta:
ordering = ['comment_created_at']
def __str__(self):
return str(self.commenter) + ' : ' + self.comment_title[:40]
def get_absolute_url(self):
return reverse('post-detail', args=[str(self.id)])
### function-based views.py (clumsy, but the form renders and saves)
def post_detail(request, pk):
template_name = 'post_detail.html'
post = get_object_or_404(Post, pk=pk)
comments = post.comment.filter(active=True)
new_comment = None
# Comment posted
if request.method == 'POST':
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post_connected = post
new_comment.save()
return redirect('/')
else:
comment_form = CommentForm()
return render(request, 'post_detail.html', {'post': post,
'comments': comments,
'new_comment': new_comment,
'comment_form': comment_form})
### function-based template (everything works):
<div class="col-md-8 card mb-4 mt-3 ">
<div class="card-body">
<!-- comments -->
<h2>{{post.num_comments}} comments:</h2>
{% for comment in comments %}
<div class="comments" style="padding: 10px;">
<p class="font-weight-bold">
{{ comment.comment_title }} - {{comment.commenter}}
<span class=" text-muted font-weight-normal">
{{ comment.comment_created_at }}
</span>
</p>
{{ comment.comment | linebreaks }}
</div>
{% endfor %}
</div>
</div>
<div class="col-md-8 card mb-4 mt-3 ">
<div class="card-body">
<h3>Leave a comment</h3>
<form method="post" style="margin-top: 1.3em;">
{{ comment_form.as_p }}
{% csrf_token %}
<button type="submit" class="btn btn-primary btn-lg">Submit</button>
</form>
</div>
</div>
urls.py (for both views, I comment out the url (and view) not in use)
urlpatterns += [
path('blog/<int:pk>/', views.post_detail, name='post_detail'),
#path('blog/<int:pk>/', views.PostDetailView.as_view(), name='post-detail'),
]
Same models.py, but class-based view:
### Class-based view (form doesn't get rendered at all)
class PostDetailView(generic.DetailView):
# pass
model = Post
form_class = CommentForm
def post_detail_view(self, request, primary_key):
post = get_object_or_404(Post, pk=primary_key)
post_connected = Comment.objects.filter(
post_connected=self.get_object()).order_by('-comment_created_at')
comments = post_connected
return comments
def get_success_url(self):
return reverse('post-detail', kwargs={'pk' : self.object.pk})
def get_form_kwargs(self, *args, **kwargs):
kwargs = super(PostDetailView, self).get_form_kwargs(
*args, **kwargs)
return kwargs
if self.request.user.is_authenticated:
comment_form = CommentForm()
comment_form = CommentForm(instance=selfrequest.user)
new_comment = CommentForm(request.POST)
new_comment.save()
def get_object(self):
post = super().get_object()
post_connected = Comment.objects.filter(
post_connected=self.get_object()).order_by('-comment_created_at')
if self.request.user.is_authenticated:
self.request.user = CommentForm(instance=self.request.user)
comment = CommentForm(request.POST)
comment.save()
post.author = User.objects.filter(id=post.author.id)
post.views +=1
post.save()
return post
The code for the templates is identical for both views, but the files are in different directories:
<div class="col-md-8 card mb-4 mt-3 ">
<div class="card-body">
<!-- comments -->
<h2>{{post.num_comments}} comments:</h2>
{% for comment in comments %}
<div class="comments" style="padding: 10px;">
<p class="font-weight-bold">
{{ comment.comment_title }} - {{comment.commenter}}
<span class=" text-muted font-weight-normal">
{{ comment.comment_created_at }}
</span>
</p>
{{ comment.comment | linebreaks }}
</div>
{% endfor %}
</div>
</div>
<div class="col-md-8 card mb-4 mt-3 ">
<div class="card-body">
<h3>Leave a comment</h3>
<form action="{% url 'post-detail' post.id %}" method="POST" style="margin-top: 1.3em;">
{{ comment_form.as_p }}
{% csrf_token %}
<button type="submit" class="btn btn-primary btn-lg">Submit</button>
</form>
</div>
</div>
I am having some trouble getting a file to post via a form using generic class-based view CreateView. Below is what i have so far. I am not quite sure how to handle the file and if request.FILES is getting the file being posted or if there is something else i need to be doing to capture the file information in the form. I have tried following the docs, however no luck in getting something working. File uploads as a blank field.
views.py
# Create
class FileUploadCreateView(BSModalCreateView):
template_name = 'fileupload/create-file.html'
form_class = FileUploadModelForm
success_message = 'Success: File was uploaded.'
success_url = reverse_lazy('files_list')
# Add required field my_user prior to posting form
def form_valid(self, form):
form = FileUploadModelForm(self.request.POST, self.request.FILES)
self.object = form.save(commit=False)
self.object.my_user = self.request.user
self.object.file_status = 'ready'
return super().form_valid(form)
forms.py
class FileUploadModelForm(BSModalModelForm):
class Meta:
model = FileUpload
fields = ['file_name', 'file_description', 'file_date_from', 'file_date_to','file_upload']
widgets = {
'file_name': forms.TextInput(attrs={'class':'form-control mb-3', 'id':'ruleset_name'}),
'file_description': forms.Textarea(attrs={'rows':5}),
'file_date_from': DatePickerInput(
options={
"format": "MM/DD/YYYY",
"showClose": True,
"showClear": True,
"showTodayButton": True,
}
),
'file_date_to': DatePickerInput(
options={
"format": "MM/DD/YYYY",
"showClose": True,
"showClear": True,
"showTodayButton": True,
}
),
'file_upload': forms.FileInput(attrs={'class':'form-control-file mb-3', 'id':'file_upload', 'type':'file', }),
}
html
{% load widget_tweaks %}
<form method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
<div class="modal-header">
<h5 class="modal-title" style="color:#7a7a7a;">
<i class="fas fa-plus-square fa-med pr-2 align-middle"></i>
<span class="align-middle">ADD File</span>
</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="{% if form.non_field_errors %}invalid{% endif %} mb-2">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_label }}" style="font-size: small; color:#7a7a7a;">{{ field.label }}</label>
{% render_field field class="form-control" %}
<div class="{% if field.errors %} invalid{% endif %}">
{% for error in field.errors %}
<p class="help-block">{{ error }}</p>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">Cancel</button>
<button type="button" class="submit-btn btn btn-primary pr-4 pl-4">Save</button>
</div>
</form>
model.py
class FileUpload(models.Model):
"""
Class for the creation of file uploads
"""
id = models.AutoField(primary_key=True)
my_user = models.ForeignKey('users.MyUser', on_delete=models.CASCADE, related_name='file_uploads', default=None)
file_name = models.CharField(max_length=255, blank=False, default=None, verbose_name='File Name')
file_description = models.CharField(max_length=255, blank=False, default=None, verbose_name='File Description')
file_date_from = models.DateField(default=None, null=True, blank=False, verbose_name='File Date From')
file_date_to = models.DateField(default=None, null=True, blank=False, verbose_name='File Date To')
STATUS_CHOICES = (
('ready','Ready'),
('processed', 'Processed'),
('archived','Archived'),
)
file_status = models.CharField(max_length=9, choices=STATUS_CHOICES, default=None, blank=False, verbose_name='File Status')
file_create_date = models.DateTimeField(verbose_name='File Create Date', auto_now_add=True)
file_upload = models.FileField(upload_to='uploads/%Y/%m/%d/', default=None, verbose_name='File Upload', blank=True)
class Meta:
ordering = ['-file_create_date']
constraints = [
models.UniqueConstraint(fields=['my_user','file_name'], name='Unique MyUser File')
]
def __str__(self):
return self.file_name
Pretty sure you forgot to add the enctype="multipart/form-data" data attribute to the form tag in your template.
To be sure, you would have to provide us with the Model, the Form and the template code.
after working on the view for some time, I was able to get the file to post via the following, using cleaned_data.
# Add required fields prior to posting form
def form_valid(self, form):
self.instance = form.save(commit=False)
self.instance.my_user = self.request.user
self.instance.file_status = 'ready'
self.instance.file_upload = form.cleaned_data['file_upload']
return super().form_valid(form)
i'm facing problem with show data from two models into single html page
i have two models - first called Course and second called Lesson okay , so i want add course then add lesson in the course and show data in one html page
models.py :
class Course(models.Model):
title = models.CharField(max_length=100,default="")
name = models.CharField(max_length=100,default="")
app_contect = RichTextField(blank=True,null=True)
app_image = models.ImageField(upload_to='images/',null=True, blank=True)
post_date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
post_tag = models.CharField(max_length=50,default="",choices = COURSE_SECTION)
objects = SearchManager()
slug = models.SlugField(default="",blank=True,unique=True,editable=True)
def save(self, *args, **kwargs):
if not self.id or not self.slug:
super(Course, self).save(*args, **kwargs)
self.slug = slugify(f"{self.title} {str(self.id)}")
super(Course, self).save(*args, **kwargs)
def get_image(self):
if self.app_image and hasattr(self.app_image, 'url'):
return self.app_image.url
else:
return '/path/to/default/image'
def __str__(self):
return self.name
class Meta:
ordering = ('-post_date',)
class Lesson(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
youtube_url = models.URLField()
def __str__(self):
return self.name
admin.py :
from django.contrib import admin
from blog_app.models import Course,Lesson
class InlineLessons(admin.StackedInline):
model = Lesson
class CourseAdmin(admin.ModelAdmin):
inlines = [ InlineLessons ]
admin.site.register(Lesson)
admin.site.register(Course,CourseAdmin)
so how to show data from course and lesson model into one html page ?
i tried do this but it's don't work , it just show data from Course model
views.py :
def course_posts(request,slug):
lesson = Lesson.objects.all()
course_posts = get_object_or_404(Course, slug=slug)
context = {'course_posts':course_posts}
return render(request,'course/course_posts_page.html', { 'course_posts': course_posts,'lesson':lesson })
html page :
<h1 id="font_control_for_header_in_all_pages"> {{course_posts.name}} </h1>
<div id="accordion">
<div class="card">
<div class="card-header" id="headingOne">
<h5 class="mb-0 text-center">
<button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
{{lesson.name}}
</button>
</h5>
</div>
<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordion">
<div class="card-body">
<iframe width="100%" height="400px" src="{{lesson.youtube_url}}" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div>
</div>
</div>
</div>
this don't work , it's show data from Course model not from lesson and course
It looks like you want to display all the lessons associated with a course, so you should modify your view to not made the lesson query.
def course_posts(request,slug):
course_posts = get_object_or_404(Course, slug=slug)
context = {'course_posts':course_posts}
return render(request,'course/course_posts_page.html', { 'course_posts': course_posts })
<h1 id="font_control_for_header_in_all_pages"> {{course_posts.name}} </h1>
<div id="accordion">
{% for lesson in course_posts.lesson_set.all %}
<div class="card">
<div class="card-header" id="headingOne">
<h5 class="mb-0 text-center">
<button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
{{lesson.name}}
</button>
</h5>
</div>
<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordion">
<div class="card-body">
<iframe width="100%" height="400px" src="{{lesson.youtube_url}}" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div>
</div>
</div>
{% endfor %}
</div>
I am learning django. I am working on a blog. When user reply to a comment it is showing time of its parent comment. It should show actual time of reply. I attached a picture with this post.Please have a look , you will better understand my question. How can I fix? I tried but all in vain. may be it is a silly mistake from me or i am not getting it. Thanks in advance
view.py
def blogPost(request, slug):
post = Post.objects.filter(slug=slug).first()
comments = BlogComment.objects.filter(post=post, parent=None)
replies = BlogComment.objects.filter(post=post).exclude(parent=None)
replyDict = {}
for reply in replies:
if reply.parent.sno not in replyDict.keys():
replyDict[reply.parent.sno] = [reply]
else:
replyDict[reply.parent.sno].append(reply)
context = {'post':post, 'comments':comments, 'user': request.user, 'replyDict': replyDict}
return render(request, 'blog/blogPost.html',context)
def postComments(request):
if request.method == 'POST':
comment = request.POST.get('comment')
user = request.user
postSno = request.POST.get('postSno')
post = Post.objects.get(sno=postSno)
parentSno = request.POST.get('parentSno')
if parentSno == "":
comments = BlogComment(comment=comment, user=user, post=post)
comments.save()
messages.success(request, 'Your Comment has been posted Successfully')
else:
parent = BlogComment.objects.get(sno=parentSno)
comments = BlogComment(comment=comment, user=user, post=post, parent=parent)
comments.save()
messages.success(request, 'Your reply has been posted Successfully')
return redirect(f"/blog/{post.slug}")
models.py
class Post(models.Model):
sno = models.AutoField(primary_key=True)
title = models.CharField(max_length=200)
content = models.TextField(max_length=10000)
author = models.CharField(max_length=20)
region = models.CharField(max_length=20)
slug = models.CharField(max_length=50, default="")
timestamp = models.DateTimeField(blank=True)
thumbnail = models.ImageField(upload_to="images", default="")
def __str__(self):
return self.title + 'by' + self.author
class BlogComment(models.Model):
sno = models.AutoField(primary_key=True)
comment = models.TextField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True) #it is pointing the value of blogcomment so we use 'self'
timestamp = models.DateTimeField(default=now)
replytimestamp = models.DateTimeField(default=now)
def __str__(self):
return self.comment[0:10] + "..." + "by " + self.user.username
blogPost.html
{% for comment in comments %}
<div class="row border border-dark mx-0 my-3">
<div class="col-md-1"><img src="/media/images/usr.png" height="55px" width="55px"></div>
<div class="col-md-11"><b> {{comment.user.username}} </b>
<span class="badge badge-secondary">{{comment.timestamp | naturaltime}}</span>
<!--this will show time in 2 hours ago or x hour ago like-->
<div>
<p class="font-italic">{{comment.comment}}</p>
</div>
<div class="reply mx-0">
<p>
{% if user.is_authenticated %}
<button class="btn btn-primary btn-sm" type="button" data-toggle="collapse"
data-target="#replyBox{{comment.sno}}" aria-expanded="false" aria-controls="collapseExample">
reply
</button>
</p>
<div class="collapse" id="replyBox{{comment.sno}}">
<div class="card card-body mb-2">
<form action="/blog/postComments" method="POST">{% csrf_token %}
<div class="form-group">
<label for="comment">Post a Reply</label>
<input type="text" class="form-control" id="comment" name="comment"
placeholder="Write a reply Here">
<input type="hidden" name="parentSno" value="{{comment.sno}}">
</div>
<input type="hidden" name="postSno" value="{{post.sno}}">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
{% endif %}
<div class="replies my-2">
{% for reply in replyDict|get_val:comment.sno %}
<!-- this will return replies associated with comment.sno in the replyDict[] -->
<div class="row my-2">
<div class="col-md-1"><img src="/media/images/usr.png" height="35px" width="35px"></div>
<div class="col-md-11">
<b> {{comment.user.username}} </b><span
class="badge badge-secondary">{{comment.timestamp | naturaltime}}</span>
<div>{{reply.comment}}</div>
</div>
<br>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
commentand reply pictures