Good evening, I have a problem while learning Django. The point is that I am doing a training news site, and there is such an item as "public" - whether the news is published or not. And to display only published news, use "def get_queryset" But I need to display news only with public = True and by the date the news was created
views.py
class news(ListView):
model = Post
template_name = 'flatpages/new.html'
context_object_name = 'news'
# paginate_by = 6
ordering = '-data'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['cate'] = Category.objects.all()
return context
def get_queryset(self):
return Post.objects.filter(public=True)
models.py
class Category(models.Model):
category_name = models.CharField(max_length=64, unique=True)
subscribers = models.ManyToManyField(User, blank=True, null=True)
class Meta:
verbose_name = 'Категория'
verbose_name_plural = 'Категории'
def __str__(self):
return self.category_name
class Post(models.Model):
PostAuthor = models.ForeignKey(Author, on_delete=models.CASCADE, verbose_name='Автор поста')
PostNews = 'PN'
PostArticle = 'PA'
# «статья» или «новость»
POSITIONS = [
(PostArticle, 'Статья'),
(PostNews, 'Новость'),
]
postCategory = models.ManyToManyField(Category, verbose_name='Категория поста', through='PostCategory')
title = models.CharField(max_length=50, verbose_name='Название')
positions = models.CharField(max_length=2, choices=POSITIONS, default=PostArticle, verbose_name='Тип поста')
category_id = models.ForeignKey(Category, verbose_name='Категория', null=True, on_delete=models.CASCADE, related_name='category_id')
data = models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')
data_update = models.DateTimeField(auto_now=True, verbose_name='Дата редактирования')
photo = models.ImageField(upload_to='photos/%Y/%m/%d/', verbose_name='Фото', blank=True, default='/photos/def/1.jpg/')
previewName = models.CharField(max_length=128, verbose_name='Превью поста')
text = models.TextField(verbose_name='Текст поста')
rating = models.SmallIntegerField(default=0, verbose_name='Рейтинг')
public = models.BooleanField(default=True, verbose_name='Опубликовано')
def like(self):
self.rating +=1
self.save()
def dislike(self):
self.rating -=1
self.save()
def preview(self):
return self.text[0:124] + '...'
def __str__(self):
return self.title
class Meta:
verbose_name = 'Пост'
verbose_name_plural = 'Посты'
def get_absolute_url(self):
return f'/news/{self.pk}'
html page
<div class="col-md-8">
{%for el in news%}
<div class="card mb-3">
<div class="card-header">
Категории: {{el.category_id}}
</div>
<br>
<div class="row g-0">
<div class="col-md-4">
{%if el.photo%}
<img src="{{el.photo.url}}" alt="" width="275" class="mr-3">
{%endif%}
</div>
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title"><a style="color: #000000;" href="{% url 'news_detail' el.id %}">{{ el.title|censor_filter }}</a></h5>
<p class="card-text">{{ el.text|censor_filter|truncatewords:150 }}</p> Читать полную новость
</div>
</div>
<br>
<div
class="card-footer text-muted " style="text-align: right;">Рейтинг статьи: {{el.rating}}<br>
Дата публикации {{ el.data|date:'d M Y H:m' }}
</div>
</div>
</div>
{%endfor%}
</div>
https://i.stack.imgur.com/BG56m.png
If you override the get_queryset, Django will no longer order the queryset, since that is implemented in the basic implementation of the view. You should order in the .get_queryset method with:
class news(ListView):
model = Post
template_name = 'flatpages/new.html'
context_object_name = 'news'
# paginate_by = 6
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['cate'] = Category.objects.all()
return context
def get_queryset(self):
# use order_by(…) ↓
return Post.objects.filter(public=True).order_by('-data')
Note: In Django, class-based views (CBV) often have a …View suffix, to avoid a clash with the model names.
Therefore you might consider renaming the view class to NewsView, instead of news.
Related
I want to put a filter on a page which shows videos selecting an album shows up on album page not all the videos but my current filter is showing all the published videos. I couldn't find a way to put a filter based on slug that if an album's slug is matching with the current url then shows the video selecting that album. For example:- Videos created by Gaurav should only visible on Gaurav’s album not anyone else. I am all confused help me.
models.py
from django.db import models
from django.urls import reverse
STATUS = (
(1, "Publish"),
(0, "Draft")
)
class WatchCategory(models.Model):
title = models.CharField(max_length=20)
slug = models.SlugField(max_length=2000, unique=True)
def __str__(self):
return self.title
class Genre(models.Model):
title = models.CharField(max_length=20)
slug = models.SlugField(max_length=2000, unique=True)
def __str__(self):
return self.title
class Album(models.Model):
title = models.CharField(max_length=2000)
slug = models.SlugField(max_length=2000, unique=True)
image = models.CharField(max_length=2000, blank=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('Watch:album', kwargs={
'slug': self.slug
})
class Video(models.Model):
title = models.CharField(max_length=2000)
slug = models.SlugField(max_length=2000, unique=True)
thumbnail = models.CharField(max_length=2000, unique=True)
updated_on = models.DateTimeField(auto_now=True)
file = models.CharField(max_length=2000)
time = models.CharField(max_length=2000, blank=True)
about = models.TextField(blank=True)
category = models.ManyToManyField(WatchCategory)
album = models.ManyToManyField(Album)
genre = models.ManyToManyField(Genre)
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=1)
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('Watch:video', kwargs={
'slug': self.slug
})
views.py
class Album(ListView):
queryset = Video.objects.filter(status=1).order_by('-created_on')
template_name = 'Watch/album.html'
paginate_by = 6
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = 'Explore & Watch your favourite'
return context
album.html
{% extends "Watch/layout.html" %}
{% load static %}
{% block content %}
<div class="video-block section-padding">
<div class="row">
{% for video in video_list %}
<div class="col-xl-3 col-sm-6 mb-3">
<div class="video-card">
<div class="video-card-image">
<a class="play-icon" href="{% url 'Watch:video' video.slug %}"><i class="fas fa-duotone fa-circle-play"></i></a>
<img class="img-fluid" src="{{ video.thumbnail }}" alt="">
<div class="time">{{ video.time }}</div>
</div>
<div class="video-card-body">
<div class="video-title">
{{ video.title }}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
Been stuck at this trying to delete data from the database, I'm clearly lost with the logic somewhere I'd grately appreciate any assistance.
resume-detail.html:
<div class="row">
{% if educations %}
{% for education in educations %}
<div class="col-lg-12 mt-4 pt-2">
<div class="component-wrapper rounded shadow">
<div class="p-4 border-bottom bg-light">
<h4 class="title mb-0">{{education.institution}}</h4>
</div>
<div class="p-4">
<div class="row">
<div class="col">
<p><strong>Qualification: </strong> {{education.qualification}}</p>
</div>
<div class="col">
<p><strong>Level of Qualification: </strong> {{education.level}}</p>
</div>
</div>
<div class="row">
<div class="col">
Delete Qualification
<!-- <button class="btn btn-danger">Delete Qualification</button> -->
</div>
</div>
</div>
</div>
</div>
{% endfor %}
{% endif %}
</div>
<div class="row">
<div class="col-lg-12 mt-4 pt-2">
<h4 class="text-dark"><button type="button" class="btn btn-secondary-outline btn-outline-success" data-toggle="modal" data-target="#addEducation"><span class="mr-2">+</span> Add Education</button></h4>
</div>
</div>
i'm using a modal to capture this data
<div class="modal fade" id="addEducation" tabindex="-1" aria-labelledby="addEducationLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<form action="" method="POST">
{% csrf_token %}....
urls.py
path('userapp/view/<slug:slug>/', user_views.resume_detail, name='resume-detail'),
path('delete/<str:id>/', user_views.delete_view, name='delete' )
views.py
def delete_view(request, id):
obj = Resume.objects.get(id = id)
if request.method =="POST":
obj.delete()
messages.success(request,"Information Deleted Successfully")
return redirect('resume-detail', id = id)
educations = Education.objects.get(resume = obj)
experiences = Experience.objects.get(resume = obj)
context = {}
context['object'] = obj
context['educations'] = educations
context['experiences'] = experiences
return render(request, 'resume-detail.html', context)
I would like to delete data for educations and experiences. Its the data I capture with the modals. What could I be doing wrong ?
models.py
class Resume(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE)
uniqueId = models.CharField(null=True, blank=True, max_length=200)
image = models.ImageField(default = 'default.jpg', upload_to='profile_images')
email_confirmed = models.BooleanField(default=False)
date_birth = models.DateField(blank=True, null=True)
sex = models.CharField(choices=SEX_CHOICES, default=OTHER, max_length=200)
marital_status = models.CharField(choices=MARITAL_CHOICES, default=SINGLE, max_length=200)
addressLine1 = models.CharField(null=True, blank=True, max_length=200)
addressLine2 = models.CharField(null=True, blank=True, max_length=200)
village = models.CharField(null=True,blank=True, max_length=200)
city = models.CharField(null=True, blank=True, choices=DISTRICT_CHOICES, default=KAMPALA, max_length=200)
district = models.CharField(choices=DISTRICT_CHOICES, default=KAMPALA, max_length=100)
phoneNumber = models.CharField(null=True, blank=True, max_length=200)
slug = models.SlugField(max_length=500, unique=True, blank=True, null=True)
date_created = models.DateTimeField(default= timezone.now)
last_updated = models.DateTimeField(blank=True, null=True)
cover_letter = models.FileField(upload_to='resumes', null=True, blank=True,)
cv = models.FileField(upload_to='resumes', null=True, blank=True,)
def __str__(self):
return '{} {} {}'.format(self.user.first_name, self.user.last_name, self.uniqueId)
def get_absolute_url(self):
return reverse('resume-detail', kwargs={'slug': self.slug})
def save(self, *args, **kwargs):
if self.uniqueId is None:
self.uniqueId = str(uuid4()).split('-')[0]
self.slug = slugify('{} {} {}'.format(self.user.first_name, self.user.last_name, self.uniqueId))
if self.image == 'default.jpg':
self.image = random.choice(self.IMAGES)
self.slug = slugify('{} {} {}'.format(self.user.first_name, self.user.last_name, self.uniqueId))
super(Resume, self).save(*args, **kwargs)
class Education(models.Model):
institution = models.CharField(null=True, max_length=200)
qualification = models.CharField(null=True, max_length=200)
level = models.CharField(choices=LEVEL_CHOICES, default=LEVEL5A, max_length=200)
start_date = models.DateField()
graduated = models.DateField()
major_subject = models.CharField(null=True, max_length=200)
date_created = models.DateTimeField(default = timezone.now)
resume = models.ForeignKey(Resume, on_delete=models.CASCADE)
def __str__(self):
return '{} for {} {}'.format(self.qualification, self.resume.user.first_name, self.resume.user.last_name)
class Experience(models.Model):
company = models.CharField(null = True, max_length=200)
position = models.CharField(null = True, max_length=200)
start_date = models.DateField()
end_date = models.DateField()
experience = models.TextField()
skills = models.TextField()
resume = models.ForeignKey(Resume, on_delete = models.CASCADE)
def __str__(self):
return '{} at {}'.format(self.position, self.company)
You need to give id which is primary key in the Education model, so:
<form action="{% url 'delete' educations.id %}" method="POST">
{% csrf_token %}....
Add education as ForeignKey in the model, so:
class Resume(models.Model):
education=models.ForeignKey(Education,on_delete=models.CASCADE)
Change the url as:
path('userapp/view/<int:id>/', user_views.resume_detail, name='resume-detail'),
path('delete/<int:id>/', user_views.delete_view, name='delete' )
Then in view, get the object through id then delete it.
from django.shortcuts import get_object_or_404
def delete_view(request, id):
education_instance=get_object_or_404(Education,id=id)
obj = get_object_or_404(Resume, education=education_instance)
if request.method =="POST":
obj.delete()
messages.success(request,"Information Deleted Successfully")
return redirect('resume-detail', id=id)
educations = get_object_or_404(Education, resume=obj)
experiences = get_object_or_404(Experience,resume=obj)
context = {}
context['object'] = obj
context['educations'] = educations
context['experiences'] = experiences
return render(request, 'resume-detail.html', context)
Note: Generally, it is better to use get_object_or_404() instead of get() as it calls get() on a given model manager, but it raises Http404 instead of the model’s DoesNotExist exception.
As #SunderamDubey said, if you need objects Education and Experience based by the Resume relation - edit your urls.py path to accept delete/<int:resume_pk> instead of delete/<str:slug>/.
Then:
# urls.py
path('delete/<int:resume_pk>/', user_views.delete_view, name='delete')
# views.py
def delete_view(request, resume_pk):
obj = Resume.objects.get(id=resume_pk)
...
educations = Education.objects.get(resume=obj)
experiences = Experience.objects.get(resume=obj)
...
# modal
<form action="{% url 'delete' resume_pk=obj.pk %}" method="POST">
I m trying to make a comment system on a blog website with using the slug instead of pk
im running into not NULL constraint failed: home_comment.post_id error
my error is coming in the form_valid function in the class based view
form.instance.post_id = self.kwargs['pk']
how do i do this ^ with the slug
form.instance.post__slug = self.kwargs['slug'] (this is showing an error)
views.py
class AddCommentView(CreateView):
model = Comment
form_class = AddCommentForm
template_name = "add_comment.html"
def form_valid(self, form):
form.instance.post__slug = self.kwargs["slug"]
form.instance.name = self.request.user
return super().form_valid(form)
models.py
class Post(models.Model):
title = models.CharField(max_length=1000, default="Title")
author = models.ForeignKey(User, on_delete=models.CASCADE)
category = models.CharField(max_length=1000, default="Category")
body = models.TextField(default="This is the Body of the Post.")
slug = models.SlugField(max_length=1000, null=True, blank=True)
created_time = models.DateTimeField(auto_now_add=True)
created_date = models.DateField(auto_now_add=True)
updated_time = models.DateTimeField(auto_now=True)
updated_date = models.DateField(auto_now=True)
likes = models.ManyToManyField(User, related_name="blog_posts_likes")
dislikes = models.ManyToManyField(User, related_name="blog_posts_dislikes")
class Meta:
verbose_name_plural = "Blogs & Posts"
def __str__(self):
return self.title
def save(self, *args, **kwargs):
self.slug = generate_slug(self.title)
super(Post, self).save(*args, **kwargs)
def get_absolute_url(self):
return f"/blogs/post/{self.slug}"
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="comments")
name = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField()
date_added = models.DateField(auto_now_add=True)
time_added = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = "Post Comments"
def __str__(self):
return "%s - %s" % (self.post.title, self.name.username)
def get_absolute_url(self):
return f"/blogs/post/{self.post.slug}"
html file
{% extends "base.html" %}
{% block content %}
{% if user.is_authenticated %}
<section class="text-gray-600 body-font relative">
<div class="container px-5 py-24 mx-auto">
<div class="flex flex-col text-center w-full mb-12">
<h1 class="sm:text-3xl text-2xl font-medium title-font mb-4 text-gray-900">Add A Comment</h1>
</div>
<div class="mx-auto">
<form method="post">
{% csrf_token %}
{{form}}
<div class="p-2 w-full">
<button
class="flex mx-auto text-white bg-indigo-500 border-0 py-2 px-8 focus:outline-none hover:bg-indigo-600 rounded text-lg">Add</button>
</div>
<div class="p-2 w-full pt-8 mt-8 border-t border-gray-200 text-center">
</div>
</form>
</div>
</div>
</section>
{% endif %}
{% endblock %}
try this
def form_valid(self, form):
form.instance.post = Post.objects.get(slug=self.kwargs["slug"])
form.instance.name = self.request.user
return super().form_valid(form)
Hello I justa want to ask this because Im new in django, my trouble is that i want to count how many comments have a post and put it in to the html template.
But the thing is that im using for to gather all the events in the db, but i just want to show only the count of comments that have every event that the "for" are showing.
this is my models, view, and template.
Thank you so much.
MODELS
class Event(TimeStampModel):
name = models.CharField(max_length=200, unique=True)
slug = models.SlugField(editable=False)
summary = models.TextField(max_length=255)
content = models.TextField()
category = models.ForeignKey(Category)
place = models.CharField(max_length=50)
start = models.DateTimeField()
finish = models.DateTimeField()
image = models.ImageField(upload_to = 'eventos')
is_free = models.BooleanField(default=True)
amount = models.DecimalField(max_digits=6, decimal_places=0, default=0)
views = models.PositiveIntegerField(default=0)
organizer = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True)
def save(self, *args, **kwargs):
if not self.id:
self.slug = slugify(self.name)
super(Event, self).save(*args, **kwargs)
def __unicode__(self):
return self.name
class Comments(TimeStampModel):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
event = models.ForeignKey(Event)
content = models.TextField()
def __unicode__(self):
return "%s %s" % (self.user.username, self.event.name)
VIEW
class IndexView(TemplateView):
template_name = 'eventos/index.html'
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['events'] = Event.objects.all().order_by('-created')[:6]
context['categories'] = Category.objects.all()
context['comments'] = Comments.objects.all()
return context
HTML TEMPLATE
{% for event in events %}
<li class="span4 ">
<div class="thumbnail thumbnail-1">
<h3 class="titulo-fix" >{{ event.name }}</h3>
<img class="center-cropped" src="{{ event.image.url }}" alt="">
<section>
<h3>{{ event.category }} </h3>
<div class="meta">
<time datetime="2012-11-09" class="date-1"><i class="icon-calendar"></i> {{ event.start }}</time>
<div class="name-author"><i class="icon-user"></i> {{ event.organizer }}</div>
<i class="icon-comment"></i> comments
</div>
<div class="clear"></div>
<p>{{ event.place }}</p>
Leer mas..
</section>
</div>
</li>
{% endfor %}
I want to show it just in that part of the html where it says comments.. with a tag of course, but i just dont know wich tag or how to do it.
You can create a helper method on the model which can help you show the number of comments.
Something like this:
class Event(TimeStampModel):
...
def comments_count(self):
#Your filter criteria can go here.
return self.comments_set.count()
and in the comments:
{{event.comments_count}}
More documentation on the reverse lookups can be found here
If you are not filtering, as, #MadWombat mentions, you could just do
{{event.comments_set.count}}
i got a problem with getting ManyToMany field values in template, here is the code:
models.py
class Client(models.Model):
name = models.CharField(max_length=18,help_text='Nazwa firmy klienta, musi być unikalna', verbose_name='Klienci')
slug = models.SlugField(max_length=255,help_text="Wartość sugerowana automatycznie na podstawie nazwy", unique=True, verbose_name='Odnośnik')
iconwhite = models.ImageField(upload_to='iconswhite', verbose_name='ikona na białym tle', blank=True)
class Meta:
ordering = ['name']
verbose_name = "Klient"
def __str__(self):
return self.name
def __unicode__(self):
return self.name
def get_absolute_url(self):
return '/clients/%s/' % self.slug
models.py
class Projects(models.Model):
def get_picture_path(instance, filename):
return os.path.join('picture', str(instance.id), filename)
client = models.ManyToManyField(Client, verbose_name='Klient')
title = models.CharField(max_length=255, verbose_name='Tytuł projektu')
slug = models.SlugField(max_length=255, unique=True, verbose_name='Odnośnik')
status = models.CharField(max_length=1, choices=STATUS_CHOICES, default='d')
picture = models.ImageField(upload_to=get_picture_path, blank=True, null=True, help_text='Miniatura widoczna na str głównej oraz w galerii projektow')
class Meta:
verbose_name = "Projekt"
def __str__(self):
return self.title
def __unicode__(self):
return self.title
def get_absolute_url(self):
return '/projects/' + self.slug + '/'
index.html
<div class="grid_4">
<div class="container_img">
<div><img src="site_media/media/{{i.picture}}" /></div>
<div class="client_icon">
{% for client in projects.client.all %}
<img src="site_media/media/{{client.iconwhite}}" />
{% endfor %}
</div>
</div>
<div class="project_description">
<p class="projects_title">{{ i.title }}</p>
<p class="projects_description">{{ i.description|safe|removetags:"p br div"|truncatewords:9 }} <span>see more »</span></p>
</div>
</div>
I checked other similar topics, dunno what am i missing here :(
If i is the variable holding an individual project (judging by the context in your HTML), you'd need:
{% for client in i.client.all %}
{{ client }}
{% endfor %}