I working on a blog using Django 1.7.
I want to include a comment form with each blog post but unsure how to do that.
Here is my code:
Models:
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
def __unicode__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=100, unique=True)
slug = models.SlugField(max_length=100, unique=True)
body = models.TextField()
posted = models.DateTimeField(db_index=True, auto_now_add=True)
category = models.ForeignKey(Category)
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
def __unicode__(self):
return '%s' % self.title
class Comment (models.Model):
comment_body = models.TextField()
commented_on = models.DateTimeField(db_index=True,auto_now=True)
commenter = models.ForeignKey(User)
post = models.ForeignKey(Post)
def __unicode__(self):
return '%s' % self.comment_body
class Tag (models.Model):
title = models.CharField(max_length=100, unique=True)
slug = models.SlugField(max_length=100, unique=True)
post = models.ManyToManyField(Post)
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Tag, self).save(*args, **kwargs)
def __unicode__(self):
return '%s' % self.title
Views:
def blog_post(request, blog_post_slug):
post_detail = Post.objects.get(slug=blog_post_slug)
comments = Comment.objects.filter(post=post_detail.id)
tags = Tag.objects.filter(post=post_detail.id)
context_dict = {'post': post_detail, 'slug': blog_post_slug, 'comments':comments, 'tags':tags}
response = render(request,'blog/blog_post.html', context_dict)
return response
Template:
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}{{ post.title }}{% endblock %}
{% block body_block %}
<div class="container">
<div class="post-preview">
{% if post %}
<div>
<h2>{{ post.title }}</h2>
<small>{{ post.category }}</small>
<p class="post-meta">{{ post.posted }}</p>
<p>{{ post.body }}</p>
<h3>Comments</h3>
{% if comments %}
{% for comment in comments %}
<h5> {{ comment.commenter | capfirst }}</h5>
<p> {{ comment.comment_body }}</p>
<small>{{ comment.commented_on }}</small>
<hr>
{% endfor %}
{% else %}
<small>No comments Yet </small>
{% endif %}
<h3>Tags</h3>
{% if tags %}
{% for tag in tags %}
<span> {{ tag.title }},</span>
{% endfor %}
{% else %}
<small>Without Tags! </small>
{% endif %}
</div>
{% else %}
<strong>No such post</strong>
{% endif %}
</div>
</div>
{% endblock %}
I am using form.py to generate forms but unsure what to do in this scenario.
I just want that viewer can submit his comments on the page of blog post.
(This is answer was probably based off the Django tutorials at djangoproject.com and maybe elsewhere)
You can simply define a form for commenting in form.py, make a new instance of it in your blog_post() function, and include the newly minted form in context_dict. Then in the template, use {{ thenameyougiveyourforminthecontext }} to include a simple version of the form.
Then, in the blog_post() method in views.py, handle the form's submission. The Django website (specifically this page) describes how to handle the form's submission. In the form handling, you can create a new Comment object with the dictionary entries in form.cleaned_data (assuming you have validated it using form.is_valid() first) and save it.
This is a very brief overview of how to do this. Please look at the url I linked to truly understand how to do this.
Related
Data from database to html is not rendering. The static data is rendering but unfortunately the database data is not rendering no error occurs, and page is also rendering but data is not rendering from database to the page.
Html doc
{% extends "base.html" %}
{% load static %}
{% block title %}
All Tractors
{% endblock %}
{% block content%}
<section id="all_events">
<h1>All Tractors</h1>
<h1>{{posts.implementation}} hi</h1>
<br>
<ul>
{% for posts in post %}
{% include "tractor/includes/singlePost.html" %}
{% endfor %}
</ul>
</section>
{% endblock %}
Vews.py
from django import forms
from django.contrib.auth.models import User
from django.shortcuts import render, redirect
from .models import Post, Farmer
# Create your views here.
from django.http import HttpResponseRedirect
# Create your views here.
def starting_page(request):
return render(request,"tractor/index.html")
def posts(request):
qs = Post.objects.all()
context = {"posts":qs}
return render(request,"tractor/all-post.html",context)
This is the Models.py file:
from django.db import models
from django.core.validators import MinLengthValidator
from django.db.models.signals import pre_save
# Create your models here.
from .utils import unique_slug_generator
class Farmer(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
phone =models.CharField(max_length=10)
address = models.TextField(max_length=200)
email_address = models.EmailField()
def full_name(self):
return f"{self.first_name} {self.last_name}"
def __str__(self):
return self.full_name()
class Post(models.Model):
tractor_price = models.IntegerField(max_length=150)
implementation = models.CharField(max_length=50)
purchase_date = models.DateField(auto_now=False)
slug = models.SlugField(unique=True, db_index=True, null=True,blank=True)
tractor_company = models.CharField(max_length=50)
tractor_model = models.CharField(max_length=50)
description = models.TextField(validators=[MinLengthValidator(10)])
date = models.DateField(auto_now=False)
farmer = models.ForeignKey(
Farmer, on_delete=models.SET_NULL, null=True, related_name="posts")
def __str__(self):
return self.implementation
Try this:
{% load static %}
{% block title %}
All Tractors
{% endblock %}
{% block content%}
<section id="all_events">
<h1>All Tractors</h1>
<ul>
{% for post in posts %}
<h1>{{post.implementation}} hi</h1>
<br>
{% include "tractor/includes/singlePost.html" %}
{% endfor %}
</ul>
</section>
{% endblock %}
It should be {% for post in posts %}
I'm new to Django, I repeat after the tutorial, but I just can not display comments even from the database in html.
urls.py
static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
settings
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
models.py
from django.db import models
class Post(models.Model):
photo = models.ImageField(upload_to='media/photos/',null=True, blank=True)
name_barber = models.CharField(max_length=30)
description = models.TextField(blank=True, null=True)
def __str__(self):
return self.description[:10]
class Comment(models.Model):
post = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE)
name = models.CharField(max_length=255)
body = models.TextField()
date_add = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s - %s' % (self.post, self.name)
html file
} </style>
{% for post in posts %}
<img src="{{MEDIA_URL}}{{post.photo.url}}" width="800" />
<h3>{{ post.name_barber}}</h3>
<p>{{ post.description}}</p>
{% endfor %}
<h3> Comments.. </h3>
{% if not post.comments.all %}
no comments yet...Add one
{% else %}
{% for comment in post.comments.all %}
<strong>
{{ comment.name }}
{{ comment.date_add }}
</strong>
{{comment.body }}
{% endfor %}
{% endif %}
after adding a comment through the admin panel, the page displays: no comments yet..
What is the problem please tell me??
Remove the if/else condition and use the {% empty %} tag with your forloop.
{% for comment in post.comments.all %}
<strong>
{{ comment.name }}
{{ comment.date_add }}
</strong>
{{comment.body }}
{% empty %}
no comments yet...Add one
{% endfor %}
I am trying to include a profile feature in a simple blog site. I have created a profile model using the one to one link for the user field, also created a function view for the profile detail with corresponding template name but i keep getting a 404 error.
user = models.OneToOneField(User, on_delete=models.SET_NULL, null=True)
username = models.CharField(max_length=15, default='Anonymous')
dp = models.ImageField(null=True)
country = models.CharField(max_length=20, null=True)
age = models.IntegerField(null=True)
joined = models.DateTimeField( auto_now_add=True)
class Meta:
ordering = ['joined']
def __str__(self):
return self.username
def get_absolute_url(self):
return reverse('profile_detail', args=[str(self.id)])
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()```
views.py
def profile_detail(request, pk):
user = get_object_or_404(User, pk=pk)
context = {'user': user}
return render(request, 'milk/profile_detail.html', context)
profile_detail.html
{% extends 'milk/base.html' %}
{% block title %}
{% endblock %}
{% block content %}
<h2>{{ user.get_full_name }}</h2>
<ul>
<li>Username: {{ user.username }}</li>
<li>Location: {{ user.profile.country }}</li>
<li>Age: {{ user.profile.age }}</li>
</ul>
{% endblock %}
template referencing
<em>{{user.get_username }}</em>
urls.py
path('profile/<int:pk>/', views.profile_detail, name='profile_detail'),
you can display current user info like this without passing through context
{% extends 'milk/base.html' %}
{% block title %}
{% endblock %}
{% block content %}
<h2>{{ request.user.profile.get_full_name }}</h2>
<ul>
<li>Username: {{ request.user }}</li>
<li>Location: {{ request.user.profile.profile.country }}</li>
<li>Age: {{ request.user.profile.profile.age }}</li>
</ul>
{% endblock %}
or
instead of 'get_object_or_404' try
user = User.objects.get(id=pk)
I have a model 'Post' and this has a function 'total_likes' that counts all the likes on a post. How can i access this function inside my template to show the number of likes? Thank you!
Model:
class Post(models.Model):
created_date = models.DateTimeField()
title = models.CharField(max_length=100)
profile_image = models.ImageField(upload_to='poze', blank=True, null=True)
text = models.CharField(max_length=1000, default='Nimic', blank=True)
user = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
likes=models.ManyToManyField(UserProfile,related_name='likes',blank=True )
def total_likes(self):
return self.likes.count()
View:
class ShowPosts(APIView):
renderer_classes = [TemplateHTMLRenderer]
template_name = 'mainPage.html'
def get(self, request):
posts = Post.objects.all()
serializer = PostSerializer(posts, many=True)
return Response({'posts': serializer.data})
Template:
{% extends 'base2.html' %}
{% load static %}
{% load rest_framework %}
{% load crispy_forms_tags %}
<form action="{% url 'like_post' %}" method="post">
{% csrf_token %}
<button type="submit" name="post_id" value="{{ post.id}}">Like {{"How can I access the 'total_likes' function ?'}}</button>
</form>
{% endfor %}
{% endblock %}
Just reference the method like any other attribute. Since it didn't take any parameters, Django will call it automatically.
{{ post.total_likes }}
Just like you passed {{post.id}}, call the function before you render the template, and pass the arg to it
I am stuck with this issues for a while now. It goes like this: I have a model with lectures. I want that for every lecture to be able to upload multiple files, so I created a model that has FileField. So in my template, I want that for every lecture, the files would be displayed and downloadable as well. The Issue is that every lecture displays all the files that have ever been uploaded in the admin panel. Here is my code:
class Lecture(models.Model):
course = models.ForeignKey('Course', on_delete=models.CASCADE, default='', related_name='lectures')
lecture_category = models.IntegerField(choices=((0, "Classes "),
(1, "Seminars"),
), default=0)
lecture_title = models.CharField(max_length=100)
content = models.TextField()
files = models.OneToOneField('FileUpload', on_delete=models.CASCADE, null=True, blank=True, )
def __str__(self):
return str(self.lecture_category)
class FileUpload(models.Model):
files = models.FileField(upload_to='documents', null=True, blank=True)
def __str__(self):
return str(self.files)
def file_link(self):
if self.files:
return "<a href='%s'>download</a>" % (self.files.url,)
else:
return "No attachment"
file_link.allow_tags = True
file_link.short_description = 'File Download'
<ul>
{% regroup lectures by get_lecture_category_display as category_list %}
<h3>Lectures</h3>
<ul>
{% for category in category_list %}
<strong>
<li>{{ category.grouper }}</li>
</strong>
<ul>
{% for c in category.list %}
.............
<li>{{ c.lecture_title }}</li>
<li>{{ c.content }}</li>
{% for file in files %}
{% if file.files %}
<li><a href='{{ MEDIA_URL }}{{ file.files.url }}'>download</a></li>
{% endif %}
{% endfor %}
{% endfor %}
</ul>
{% endfor %}
</ul>
</ul>
def courses(request, slug):
query = Course.objects.get(slug=slug)
context = {'courses': Course.objects.filter(slug=slug),
'lectures': query.lectures.order_by('lecture_category'),
'files': FileUpload.objects.all(),
}
return render(request, 'courses/courses.html', context)
Here is the current output: https://i.imgur.com/Hu2NcHJ.png
Stop fetching the files as a separate queryset:
def courses(request, slug):
query = Course.objects.get(slug=slug)
context = {'courses': Course.objects.filter(slug=slug),
'lectures': query.lectures.order_by('lecture_category'),
}
return render(request, 'courses/courses.html', context)
You can then follow the one-to-one field from lecture to files.
{% for lecture in category.list %}
<li>{{ lecture.lecture_title }}</li>
<li>{{ lecture.content }}</li>
{% if lecture.files %}
<li><a href='{{ MEDIA_URL }}{{ lecture.files.files.url }}'>download</a></li>
{% endif %}
{% endfor %}
Since it's a one-to-one field to a single file upload, it would make more sense to name the field file instead of files:
file = models.OneToOneField('FileUpload', on_delete=models.CASCADE, null=True, blank=True)
You would then have to update the template to use lecture.file instead.