django URL doubled - python

when i clicked the anchor tag going to the detailed view of my product the url is doubled.
http://127.0.0.1:8000/products/products/t-shirt/
i think it is supposed to be like this:
http://127.0.0.1:8000/products/t-shirt/
List.html
{% for object in object_list %}
{{object.title}}
<br>
{{object.description}}
<br>
{{object.price}}
<br>
<br>
{% endfor %}
models.py
class Product(models.Model):
title = models.CharField(max_length=120)
slug = models.SlugField(blank=True, unique=True)
description = models.TextField()
price = models.DecimalField(decimal_places=2, max_digits=19, default=39.99)
image = models.ImageField(upload_to=upload_image_path, null=True, blank=True)
featured = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
# For url when you click a product
def get_absolute_url(self):
return "products/{slug}/".format(slug=self.slug)
def __str__(self):
return self.title
urls.py
from django.conf.urls import url
from products.views import (product_view,
product_detail_view,
product_featured_view,
)
urlpatterns = [
url(r'products/$', product_view),
url(r'products/(?P<slug>[\w-]+)/$', product_detail_view),
url(r'featured/$', product_featured_view),
]
view.py
from django.shortcuts import render, get_object_or_404, Http404
from .models import Product
def product_view(request):
queryset = Product.objects.all()
context = {
'object_list': queryset,
# 'featured': fqueryset
}
return render(request, 'products/list.html', context)
def product_detail_view(request, slug=None, *args, **kwargs):
try:
instance = get_object_or_404(Product, slug=slug)
except Product.DoesNotExist:
raise Http404("Not Found..")
except Product.MultipleObjectsReturned:
queryset = Product.objects.filter(slug=slug)
instance = queryset.first()
context = {
'object': instance
}
return render(request, 'products/detail.html', context)
def product_featured_view(request):
queryset = Product.objects.filter(featured=True)
context = {
'object_list': queryset
}
return render(request, 'products/featured-list.html', context)

You need to declare your Product.get_absolute_url differently:
def get_absolute_url(self):
return "/products/{slug}/".format(slug=self.slug)
I would also suggest you declare it via reverse as it says here get_abosolute_url.

Related

Exception Value: 'NoneType' object has no attribute 'add', Categories name dont show up Django

Im trying to let user create a post and select a category, but when it selects a category and I post it, it gives me the error: Exception Value: 'NoneType' object has no attribute 'add'.
If i go to my database, whatever I type, it is save except the category_id which is null.
This is my code
views.py:
#login_required(login_url='login')
def userposts_create_view(request):
form= UserPostForm(request.POST or None)
#print(request.POST)
if request.POST:# form.is_valid():
#data = form.cleaned_data
#print(data)
#categories = data.pop('categories', None)
categories = request.POST['categories']
content = request.POST['content']
title = request.POST['title']
public = False
if 'public' in request.POST and request.POST['public'] == 'on':
public = False
else:
public=True
#print(f"{categories}, {content}, {title}, {public}")
#user_post = UserPost.objects.create(**data, user=request.user)
user_post = UserPost.objects.create(content=content, title=title, public=public, user=request.user)#, categories=categories)
categories = Categories.objects.filter(name=Categories.name)
print(categories)
user_post.categories.get(categories)
return HttpResponseRedirect("/posted/")
context= {'form': form}
return render(request, 'posts/userposts-create-view.html', context)
#list view
#login_required(login_url='login')
def userposts_list_view(request):
allposts= UserPost.objects.all()
context= {'allposts': allposts,
}
return render(request, 'posts/userposts-list-view.html', context)
#detail view
#login_required(login_url='login')
def userposts_detail_view(request, id=None):
post= get_object_or_404(UserPost, id=id)
context= {'post': post,
}
return render(request, 'posts/userposts-detail-view.html', context)
I assume the error must be in the models but not sure...
Models.py
class Categories(models.Model):
name = models.CharField(max_length=100, verbose_name='Nombre')
def __str__(self):
return self.name
User= settings.AUTH_USER_MODEL
class UserPost(models.Model):
user= models.ForeignKey(User, null=False, editable=False, verbose_name='Usuario', on_delete=models.CASCADE)
title= models.CharField(max_length=500, null=False)
content= models.TextField(null=False)
categories = models.ForeignKey(Categories, null=True, blank=True, on_delete=models.CASCADE)
public = models.BooleanField(verbose_name='Privada?',default=True)
created_at = models.DateTimeField(auto_now_add=True, verbose_name='Creado el ')
updated_at = models.DateTimeField(auto_now=True, verbose_name='Actualizado el ')
def __str__(self):
return self.title + ' | ' + str(self.user)
def save(self, *args, **kwargs):
super(UserPost, self).save(*args, **kwargs)
Forms.py
from django import forms
from .models import UserPost
class UserPostForm(forms.ModelForm):
class Meta:
model= UserPost
fields= ["title", "content","categories","public"]
create_view.html
{%extends 'layouts/layout.html'%}
<html>
<head>
<meta charset="UTF-8">
{% block title %}
Post
{% endblock title %}
</head>
<body>
<h1>Create Post</h1>
{% block content %}
<form enctype="multipart/form-data" method="POST" action="">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Post"/>
</form>
{% endblock content %}
urls.py
from django.urls import path
from . import views
from django.conf.urls import url, include
urlpatterns = [
path('articulos/', views.list, name = "list_articles"), #se utilizaria page para el menu
path('categoria/<int:category_id>', views.category, name="category"),
path('articulo/<int:article_id>', views.article, name="article"),
path('create/', views.userposts_create_view, name='create'),
path('posted/', views.userposts_list_view, name='list_view'),
path('posted/<int:id>', views.userposts_detail_view, name='one_posts'),
path('tus_ideas', views.index_page, name='tus_ideas')
]
please try this:
#login_required(login_url='login')
def userposts_create_view(request):
form= UserPostForm(request.POST or None)
if request.POST:
categories = request.POST['categories']
content = request.POST['content']
title = request.POST['title']
public = False
if 'public' in request.POST and request.POST['public'] == 'on':
public = False
else:
public=True
user_post = UserPost.objects.create(content=content, title=title, public=public, user=request.user,categories_id=categories)
return HttpResponseRedirect("/posted/")
context= {'form': form}
return render(request, 'posts/userposts-create-view.html', context)
user_post.categories.add(*categories) would work if categories is a ManyToMany field in your UserPost model whereas it it a ForeignKey in your code.
Change your categories fields to :
class UserPost(models.Model):
...
categories = models.ManyToManyField('Categories', null=True, blank=True)

How covert function to listview?

This is my code,
I use django v3 and want convert the category functions in views.py to a list class(ListView) for use pagination.
How can do it?
Thank you alot
urls.py
from django.urls import path from .views import posts_category
urlpatterns = [
path('<slug:slug>/', posts_category, name="posts_category"),
]
model.py
class Category(models.Model):
parent = models.ForeignKey('self', blank=True, null=True, related_name='children', on_delete=models.CASCADE)
title = models.CharField(max_length=70, unique=True)
slug = models.SlugField(max_length=90, unique=True)
description = RichTextUploadingField(blank=True, null=True)
image = models.ImageField(blank=True, upload_to="imgs")
def __str__(self):
return self.title
class MPTTMeta:
order_insertion_by = ['title']
views.py
def posts_category(request, slug):
category = Category.objects.all()
post = Posts.objects.filter(category__slug=slug, status="p")
context = {
'category': category,
'post': post,
}
return render(request, 'posts_category.html', context)
I don't know if this is a good idea to show categories and products in the same page (because of the performance point of view) but you can use following code to convert your FBV to CBV:
from django.views.generic import ListView
class PostCategoryView(ListView):
template_name = 'posts_category.html'
def get_queryset(self):
slug = self.kwargs.get('slug')
return Posts.objects.filter(category__slug=slug, status="p")
def get_context_data(self, **kwargs):
context = super().get_context_data()
context['categories'] = Category.objects.all()
return context
And also change your urls to:
from django.urls import path
from .views import PostCategoryView
urlpatterns = [
path('<slug:slug>/', PostCategoryView.as_view(), name="posts_category"),
]
And finally you can use the context data in your template like the following code:
{% for obj in object_list %}
{{ obj.id }} - {{ obj.name }}</a><br>
{% endfor %}
Note that object_list is a list of your Post objects and you should change obj.name to other fields of your Post model. Finally you can use something like object_list (here we used categories) and loop through it to show the data of your categories or other things.

I am getting an error when I am updating the post. It displays in the comment section but not update the post

I am new to Django. I am making a simple blog site. But I am getting an error when I am updating the post. It displays in the comment section but not update the post.
Here is the code in_
View.py
from django.db.models import Count, Q
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render, get_object_or_404, redirect, reverse
from .forms import CommentForm, PostForm
from .models import Post, Author
from marketing.models import Signup
def get_author(user):
qs = Author.objects.filter(user=user)
if qs.exists():
return qs[0]
return None
def search(request):
queryset = Post.objects.all()
query = request.GET.get('q')
if query:
queryset = queryset.filter(
Q(title__icontains=query) |
Q(overview__icontains=query)
).distinct()
context = {
'queryset' : queryset
}
return render(request, 'search_results.html', context)
def get_category_count():
queryset = Post \
.objects \
.values('categories__title') \
.annotate(Count('categories__title'))
return queryset
def index(request):
featured = Post.objects.filter(featured=True)
latest = Post.objects.order_by('-timestamp')[0:3]
if request.method == 'POST':
email = request.POST['email']
new_signup = Signup()
new_signup.email = email
new_signup.save()
context = {
'object_list': featured,
'latest': latest
}
return render(request, 'index.html', context)
def blog(request):
category_count = get_category_count()
most_recent = Post.objects.order_by('-timestamp')[:5]
post_list = Post.objects.all()
paginator = Paginator(post_list, 4)
page_request_var = 'page'
page = request.GET.get(page_request_var)
try:
paginated_queryset = paginator.page(page)
except PageNotAnInteger:
paginated_queryset = paginator.page(1)
except EmptyPage:
paginated_queryset = paginator.page(paginator.num_pages)
context = {
'queryset' : paginated_queryset,
'most_recent' : most_recent,
'page_request_var' : page_request_var,
'category_count' : category_count
}
return render(request, 'blog.html', context)
def post(request, id):
category_count = get_category_count()
most_recent = Post.objects.order_by('-timestamp')[:5]
post = get_object_or_404(Post, id=id)
form = CommentForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
form.instance.user = request.user
form.instance.post = post
form.save()
return redirect(reverse('post-detail', kwargs={
'id': post.id
}))
context = {
'form' : form,
'post' : post,
'most_recent' : most_recent,
'category_count' : category_count,
}
return render(request, 'post.html', context)
def post_create(request):
title = 'Create'
form = PostForm(request.POST or None, request.FILES or None)
author = get_author(request.user)
if request.method == "POST":
if form.is_valid():
form.instance.author = author
form.save()
return redirect(reverse("post-detail", kwargs={
'id': form.instance.id
}))
context = {
'title': title,
'form': form
}
return render(request, "post_create.html", context)
def post_update(request, id):
title = 'Update'
post = get_object_or_404(Post, id=id)
form = PostForm(
request.POST or None,
request.FILES or None,
instance=post)
author = get_author(request.user)
if request.method == "POST":
if form.is_valid():
form.instance.author = author
form.save()
return redirect(reverse("post-detail", kwargs={
'id': form.instance.id
}))
context = {
'title': title,
'form': form
}
return render(request, "post_create.html", context)
def post_delete(request, id):
post = get_object_or_404(Post, id=id)
post.delete()
return redirect(reverse("post-list"))
In form.py:
class TinyMCEWidget(TinyMCE):
def use_required_attribute(self, *args):
return False
class PostForm(forms.ModelForm):
content = forms.CharField(
widget=TinyMCEWidget(
attrs={'required': False, 'cols': 30, 'rows': 10}
)
)
class Meta:
model = Post
fields = ('title', 'overview', 'content', 'thumbnail',
'categories', 'featured', 'previous_post', 'next_post')
class CommentForm(forms.ModelForm):
content = forms.CharField(widget=forms.Textarea(attrs={
'class' : 'form-control',
'placeholder' : 'Type your comment',
'id' : 'usercomment',
'rows' : '4',
}))
class Meta:
model = Comment
fields = ('content', )
In models.py:
from django.db import models
from tinymce import HTMLField
from django.contrib.auth import get_user_model
from django.urls import reverse
User = get_user_model()
class Author(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_picture = models.ImageField()
def __str__(self):
return self.user.username
class Category(models.Model):
title = models.CharField(max_length=100)
def __str__(self):
return self.title
class Post(models.Model):
title = models.CharField(max_length=200)
overview = models.TextField()
content = HTMLField()
timestamp = models.DateTimeField(auto_now_add=True)
comment_count = models.IntegerField(default = 0)
view_count = models.IntegerField(default = 0)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
thumbnail = models.ImageField()
categories = models.ManyToManyField(Category)
featured = models.BooleanField()
previous_post = models.ForeignKey('self', related_name='previous', on_delete=models.SET_NULL, blank=True, null=True)
next_post = models.ForeignKey('self', related_name='next', on_delete=models.SET_NULL, blank=True, null=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={
'id': self.id
})
def get_update_url(self):
return reverse('post-update', kwargs={
'id': self.id
})
def get_delete_url(self):
return reverse('post-delete', kwargs={
'id': self.id
})
#property
def get_comments(self):
return self.comments.all().order_by('-timestamp')
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True)
content = models.TextField()
post = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE)
def __str__(self):
return self.user.username
In urls.py:
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include
from posts.views import index, blog, post, search, post_create, post_update, post_delete
urlpatterns = [
path('admin/', admin.site.urls),
path('', index),
path('blog/', blog, name='post-list'),
path('search/', search, name='search'),
path('create/', post_create, name='post-create'),
path('post/<id>/', post, name='post-detail'),
path('post/<id>/update', post_update, name='post-update'),
path('post/<id>/delete', post_delete, name='post-delete'),
path('tinymce/', include('tinymce.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
In post_create.html:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="col-7 offset-3 mb-5 mt-5">
<h2>{{ title }} a new Post</h2>
{{ form.media }}
<form action="." method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-primary" type="submit">Submit</button>
</form>
</div>
{% endblock content %}
I would be happy if you please help me to solve the problem.
Thanks in Advance
Try to save your form to an instance of the model first, without saving it to the database, add author and finally save it:
if request.method == "POST":
if form.is_valid():
modelinstance = form.save(commit=FALSE)
modelinstance.author = Author.objects.get(user=request.user)
modelinstance.save()

How to render view from differents applications in the same template?

I have two applications (blog and category). On the post list template I would like to get the category blog name and description.
I have tried to put the import category model in the blog view, but nothing show up. So I have made two views rendering the same template, but it does not work.
Blog models:
from django.db import models
from django.utils import timezone
from autoslug import AutoSlugField
from category.models import Category
class Post(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE,
default = '')
title = models.CharField(max_length=200)
...
class Meta:
verbose_name = "Post"
verbose_name_plural = "Posts"
ordering = ['created_date']
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
category models:
class Category(models.Model):
name = models.CharField(max_length=200)
slug = AutoSlugField(populate_from='name', default='')
parent = models.ForeignKey('self', blank=True, null=True, related_name='children', on_delete=models.CASCADE)
description = models.TextField(max_length=200)
class Meta:
unique_together = ('slug', 'parent',) # Enforcing that there can not be two
verbose_name_plural = "categories" # categories under a parent with same
# slug
def __str__(self): # __str__ method elaborated later in
full_path = [self.name] # post. use __unicode__ in place of
# __str__ if you are using python 2
k = self.parent
while k is not None:
full_path.append(k.name)
k = k.parent
return ' -> '.join(full_path[::-1])
Blog view:
def post_list(request):
posts = Post.objects.all()
cat_blog = Category.objects.get(pk=1)
context = {
'posts': posts,
'cat_blog': cat_blog
}
return render(request, 'blog/post_list.html', context)
Category view:
def cat_blog(request):
cat_blog = Category.objects.get(pk=1)
return render(request, 'blog/post_list.html', {'cat_blog': cat_blog})
post_list.html:
<div class="section-header text-center">
{% for category in cat_blog %}
<h1>{{ category.name }}</h1>
<p class="tag">{{ category.description }}</p>
{% endfor %}
</div>
<div class="row py-5">
{% for post in posts %}
// This part is fine
{% endfor%}
The post loop is fine. How can't I get the category name and description in my section header?
One URL gives one View gives one template.
You use the View to give context to the template to render.
def post_list(request):
posts = Post.objects.all()
cat_blog = Category.objects.get(pk=1)
context = {
'posts': posts,
'cat_blog': cat_blog
}
return render(request, 'blog/post_list.html', context)
Your url.py file should point to the post_list view.

Using Django, How do I return all posts associated with a tag

I'm trying to return all posts associated with a tag using Django. I have searched for a solution but can't find one. I tried to code something but it didn't work. Heres my code
models.py
class Tag(models.Model):
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=200, unique=True)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("posts:tag_index", kwargs={"slug": self.slug})
class Meta:
ordering = ["-timestamp"]
class Post(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
slug = models.SlugField(unique=True)
title = models.CharField(max_length=120)
image = models.ImageField(upload_to=upload_location, null=True, blank=True,
width_field="width_field",
height_field="height_field")
height_field = models.IntegerField(default=0)
width_field = models.IntegerField(default=0)
content = models.TextField()
draft = models.BooleanField(default=False)
publish = models.DateField(auto_now=False, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
tags = models.ManyToManyField(Tag)
objects = PostManager()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("posts:detail", kwargs={"slug": self.slug})
class Meta:
ordering = ["-timestamp"]
posts/urls.py
from .views import post_list, post_create, post_detail, post_update, post_delete, sewp, tag_detail
urlpatterns = [
url(r'^$', post_list, name='list'),
url(r'^tag/(?P<slug>[\w-]+)/$', tag_detail, name="tag_index"),
url(r'^create/$', post_create, name='create'),
url(r'^sewp$', sewp, name='sewp'),
url(r'^(?P<slug>[\w-]+)/$', post_detail, name='detail'),
url(r'^(?P<slug>[\w-]+)/edit/$', post_update, name='update'),
url(r'^(?P<id>\d+)/delete/$', post_delete, name='delete'),
]
views.py
def tag_detail(request, slug=None):
query = slug
queryset_list = Post.objects.active()
tags_list = queryset_list.filter(tags__icontains=query).distinct()
instance = get_object_or_404(Tag, slug=slug)
context = {
"instance": instance,
"tags_list": tags_list
}
return render(request, "posts/tag_index.html", context)
tag_index.html
{% extends 'posts/base.html' %}
{% block content %}
{{ instance }}
{{ tags_list }}
{% endblock content %}
I just want to return all the tags and paginate it.
and can I modify the following code to paginate my results :
paginator = Paginator(queryset_list, 2) # Show 25 contacts per page
page_request_var = "page"
page = request.GET.get(page_request_var)
try:
queryset = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
queryset = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
queryset = paginator.page(paginator.num_pages)
context = {
"queryset": queryset,
"title": "Posts",
"page_request_var": page_request_var,
"today": today,
"queryset_list": queryset_list,
"paginator": paginator,
}
any guidance or help on this will be appreciated
If you want to find all Posts associated with a tag, simply use:
posts = Post.objects.filter(tag__title = query)
This will return all posts with the tag specified by the query string.
Read more about making queries here: https://docs.djangoproject.com/en/1.9/topics/db/queries/
I would use a generic ListView like so:
from django.views.generic.list import ListView
from django.shortcuts import get_object_or_404
class TagView(ListView):
template_name = 'posts/tag_index.html'
def get_queryset(self):
""" get the Tag object or return 404 """
self.tag = get_object_or_404(Tag, slug=self.kwargs['slug'])
return Post.objects.filter(tag=self.tag)
def get_context_data(self, **kwargs):
""" add a posts variable to context to use in template """
context = super(TagView, self).get_context_data(**kwargs)
context['posts'] = Post.objects.filter(tag=self.tag)
This is the syntax based on views.py structure
views.py:
def tag_index(request, slug=None):
instance = get_object_or_404(Tag, slug=slug)
ins = instance.post_set.all()
context = {
"instance": ins,
}
return render(request, "posts/tag_list.html", context)
then in the tags_list.html
{% for i in instance %}
{{ i.title }}
{{ i.content }}
{% endfor %}
hope this helps somebody

Categories