name 'get_object_or_404' is not defined - python

I am following this tutorial: https://tutorial-extensions.djangogirls.org/en/homework_create_more_models/
Which i am adding onto a simple blog I made so i can add comments
Me error:
name 'get_object_or_404' is not defined
From this method in views.py
def add_comment_to_post(request, pk):
post = get_object_or_404(Post, pk=pk)
# post = Post
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('post_detail', pk=post.pk)
else:
form = CommentForm()
return render(request, 'add_comment_to_post.html', {'form': form})
As you see the #hashed out line. This allows me to get to the comment view but then then I get the error that Cannot assign "<class 'blog.models.Post'>": "Comment.post" must be a "Post" instance.
That makes sense but wanted to point that out.
I assume this is a database issue?
my models.py:
from django.db import models
from django.contrib.auth.models import User
STATUS = (
(0,"Draft"),
(1,"Publish")
)
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(User, on_delete= models.CASCADE,related_name='blog_posts')
updated_on = models.DateTimeField(auto_now= True)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=0)
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
class Comment(models.Model):
comment = models.CharField(max_length=100)
created_on = models.DateTimeField(auto_now_add=True)
post = models.ForeignKey('blog.Post', on_delete=models.CASCADE, related_name='comments')
def __str__(self):
return self.comment
class Meta:
ordering = ['created_on']
Everything in the tutorial has been followed to a T. I even went through it 3 times, and re copy and pasted everything in, re migrated, etc.
Is there something I am missing the point of?

For the error
name 'get_object_or_404' is not defined
I looked around the blog, and they don't seem to import get_object_or_404. Add to the top of your code:
from django.shortcuts import get_object_or_404
Here is documentation on it.

Related

'ReverseManyToOneDescriptor' object has no attribute 'filter'

'ReverseManyToOneDescriptor' object has no attribute 'filter'
why?)
I'm trying to create a blog in django, got to the stage of adding comments and categories and got stuck
I get an error.
views.py
from django.shortcuts import render,
get_object_or_404
from .models import Post, Comment
from django.views import generic
from django.http import HttpResponse
from .forms import CommentForm
def blog_list(request):
post = Post.objects.all().order_by('-date')
return render(request,'blog/blog_list.html', {'posts':post})
def blog_detail(request, slug):
#return HttpResponse(slug)
detail_post = Post.objects.get(slug=slug)
comments = Post.comments.filter(active=True)
new_comment = None
# Comment posted
if request.method == 'POST':
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
# Create Comment object but don't save to database yet
new_comment = comment_form.save(commit=False)
# Assign the current post to the comment
new_comment.post = post
# Save the comment to the database
new_comment.save()
else:
comment_form = CommentForm()
return render(request,'blog/blog_detail.html', {'detail_post':detail_post, 'comments':comments, 'new_comment': new_comment, 'comment_form': comment_form})
I hope someone helps, also with the problem of adding a category
14.comments = Post.comments.filter(active=True) …
▶ Local vars
here is my
models.py
from django.db import models
from django.contrib.auth.models import User
class Post(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField()
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
first_src = models.CharField('первоисточник', blank=True, max_length=100)
author = models.ForeignKey(User, on_delete= models.CASCADE )
thumb = models.ImageField(default='default.png', blank=True)
# add AND GO TO MIGRATE AND MAKEMIGRATIONS !!!
class Meta:
ordering = ['-date']
def __str__(self):
return self.title
def snippet(self):
return self.body[:50]+'...'
"""def get_absolute_url(self):
from django.urls import reverse
return reverse("post_detail", kwargs={"slug": str(self.slug)})"""
class Comment(models.Model):
post = models.ForeignKey(Post,
on_delete=models.CASCADE,
related_name='comments')
name = models.CharField(max_length=80)
email = models.EmailField()
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True)
class Meta:
ordering = ('created',)
def __str__(self):
return 'Comment by {} on {}'.format(self.name, self.post)
What's wrong?
I hope someone helps, also with the problem of adding a category
You're trying to filter on the class (Post), but want to filter on the specific model (detail_post):
comments = detail_post.comments.filter(active=True)

get_absolute_url() missing 1 required positional argument: 'self'

I imagine the solution to this can be found i similar topics, however, it seems a little bit different from problems I have seen.
The redirect, in add_post view, should send me to the Post class, where I have a get_absolute_url.
But it happens that I get the following error message: get_absolute_url() missing 1 required positional argument: 'self'
I literally copied the coded form the "Django Projects Cookbook" in case you wanna check it out and try the code yourself.
Thank you.
from django.contrib.auth.decorators import user_passes_test
from django.shortcuts import redirect, render_to_response, get_object_or_404, render
from .models import Post
from .forms import PostForm, CommentForm
#user_passes_test(lambda u: u.is_superuser)
def add_post(request):
form = PostForm(request.POST or None)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.save()
return redirect(Post) # redirect to Post class
return render(request, 'blog/add_post.html',{ 'form': form })
def view_post(request, slug):
post = get_object_or_404(Post, slug=slug)
form = CommentForm(request.POST or None)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect(request.path)
return render(request, 'blog/blog_post.html',{'post': post,'form': form,})
from django.db import models
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
class Post(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
text = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __unicode__(self):
return self.title
#models.permalink
def get_absolute_url(self): # get_absolute_url
return ('blog_post_detail', (), { 'slug' :self.slug, })
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
class Comment(models.Model):
name = models.CharField(max_length=42)
email = models.EmailField(max_length=75)
website = models.URLField(max_length=200, null=True, blank=True)
text = models.TextField()
post = models.ForeignKey(Post, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return self.text
You use the Post class, not its object to redirect. You thus need to use post in:
#user_passes_test(lambda u: u.is_superuser)
def add_post(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.instance.author = request.user
post = form.save()
return redirect(post)
return render(request, 'blog/add_post.html',{ 'form': form })
The #permalink decorator was removed in Django-2.1, it is advised to use reverse [Django-doc] instead:
from django.urls import reverse
class Post(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
text = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __unicode__(self):
return self.title
def get_absolute_url(self):
return reverse('blog_post_detail', kwargs={'slug': self.slug})
Furthermore python-2.x is no longer supported since January 1, 2020; so you might want to update to django-3.x in a python-3.x environment.

Trying to resolve no such column: blog_comment.url

Once a user had logged into my site he could write a post and update it.
Then I was making progress in adding functionality which allowed people to make comments. I was at the stage where I could add comments from the back end and they would be accurately displayed on the front end.
Now when I try and update posts I get an error message. Originally I thought the problem was because I had not included a slug field and made the appropriate migrations. I then deleted the specific section of the code which was highlighted in the error message but it just meant the next line of code got flagged up instead.
models.py
from django.db import models
from django.utils.text import slugify
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now())
author = models.ForeignKey(User, on_delete=models.CASCADE)
url= models.SlugField(max_length=500, unique=True, blank=True)
def save(self, *args, **kwargs):
self.url= slugify(self.title)
super().save(*args, **kwargs)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('article_detail', kwargs={'slug': self.slug})
class Comment(models.Model):
post = models.ForeignKey(Post,on_delete=models.CASCADE,related_name='comments')
name = models.CharField(max_length=80)
email = models.EmailField()
body = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
active = models.BooleanField(default=False)
url= models.SlugField(max_length=500, unique=True, blank=True)
class Meta:
ordering = ['created_on']
def __str__(self):
return 'Comment {} by {}'.format(self.body, self.name)
def save(self, *args, **kwargs):
self.url= slugify(self.post)
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('article_detail', kwargs={'slug': self.slug})
views.py
def post_detail(request, pk):
template_name = 'post_detail.html'
comments = Comment.objects.filter(post=pk ,active=True)
post = Post.objects.get(pk=pk)
new_comment = None
# Comment posted
if request.method == 'POST':
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
# Create Comment object but don't save to database yet
new_comment = comment_form.save(commit=False)
# Assign the current post to the comment
new_comment.post = post
# Save the comment to the database
new_comment.save()
else:
comment_form = CommentForm()
return render(request, template_name, {'post': post,
'comments': comments,
'new_comment': new_comment,
'comment_form': comment_form})
Update - Migrations
I have now made (or attempted to make) the necessary migrations.
WARNINGS:
?: (2_0.W001) Your URL pattern '^activate/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$' [name='activate'] has a route that contains '(?P<', begins with a '^', or ends with a '$'. This was likely an oversight when migrating to django.urls.path().
blog.Post.date_posted: (fields.W161) Fixed default value provided.
HINT: It seems you set a fixed date / time / datetime value as default for this field. This may not be what you want. If you want to have the current date as default, use `django.utils.timezone.now`
Migrations for 'blog':
blog\migrations\0014_auto_20200420_2034.py
- Add field url to comment
- Alter field date_posted on post
Update - Modified created_on
class Comment(models.Model):
post = models.ForeignKey(Post,on_delete=models.CASCADE,related_name='comments')
name = models.CharField(max_length=80)
email = models.EmailField()
body = models.TextField()
created_on= models.DateTimeField(default = timezone.now())
active = models.BooleanField(default=False)
url= models.SlugField(max_length=500, unique=True, blank=True)
Change the field to following :
created_on= models.DateTimeField(default = timezone.now())
Please study the documentation:
1.https://docs.djangoproject.com/en/3.0/ref/models/fields/

Automatic field creation on form submission

I am writing a simple blog app and I'm currently in the position where I need to implement comments on a blog post. So, I have two models:
from django.db import models
from django.shortcuts import reverse
# Create your models here.
class Article(models.Model):
title = models.CharField(max_length=120)
author = models.CharField(max_length=50)
content = models.TextField()
date = models.DateField(auto_now=True)
def get_absolute_url(self):
return reverse('articles:article-detail', kwargs={'id': self.id})
class Comment(models.Model):
author = models.CharField(max_length=50)
content = models.TextField()
date = models.DateField(auto_now=True)
post_id = models.IntegerField()
and a ModelForm:
from django import forms
from .models import Article, Comment
class CommentModelForm(forms.ModelForm):
class Meta:
model = Comment
fields = [
'content',
'author',
]
...when I submit the form, I want my Comment's post_id field to be automatically generated and correspond to my Article's id, i.e. the comment should be located on the page where it was submitted.
Here is my views.py:
def article_detail_view(request, id):
obj = get_object_or_404(Article, id=id)
comments = Comment.objects.filter(post_id=id)
comment_form = CommentModelForm(request.POST or None)
if comment_form.is_valid():
comment_form.save()
comment_form = CommentModelForm()
context = {
'object': obj,
'comments': comments,
'comment_form': comment_form
}
return render(request, 'articles/article_detail.html', context)
Any ideas how can I do that?
I suggest to change the Comment model in order to replace post_id with a foreignkey field. It allows to keep a better link between comments and articles.
class Comment(models.Model):
author = models.CharField(max_length=50)
content = models.TextField()
date = models.DateField(auto_now=True)
post_id = models.ForeignKey(Article, on_delete=models.CASCADE) # cascade will delete the comments if the article is deleted.
Then you only have to change the comment_form validation :
if comment_form.is_valid():
comment = comment_form.save(commit=False)
comment.post_id = obj
comment.save()
comment_form = CommentModelForm()
save(commit=False) allows to create the Comment instance without saving it to database and allow us to specify the post_id with the article instance obj defined above. Then comes the final commit comment.save().
If you prefer to not change your model, you can follow the same logic and replace
comment.post_id = obj by comment.post_id = id.

Django how to change forms or views.py?

i create simple page where i can add article (title, text and category). When i do it on 'site administration everything is ok', but when i add it on page i can't choose category.
http://i.stack.imgur.com/4Nxzb.jpg
I choose category, for example like on this screen but my article do not have this category after i save it (article is uncategorized).
I created forms.py file and i done it like this:
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('title', 'text', 'categories')
How must i change 'categories' here to make it usable?
models.py:
from django.db import models
from django.utils import timezone
class Category(models.Model):
name = models.CharField('Nazwa Kategorii', max_length=100)
slug = models.SlugField('Odnośnik', max_length=100)
icon = models.ImageField('Ikonka Kategorii', upload_to='icons',
blank=True)
class Meta:
verbose_name = "Kategoria"
verbose_name_plural = "Kategorie"
def __unicode__(self):
return self.name
class Post(models.Model):
author = models.CharField(max_length=25, blank=True, null=True)
title = models.CharField(max_length=200)
slug = models.SlugField('Odnośnik', max_length=255)
text = models.TextField()
published_date = models.DateTimeField(
default=timezone.now)
categories = models.ManyToManyField(Category, verbose_name='Kategorie')
def publish(self):
self.published_date = timezone.now()
self.save()
def __unicode__(self):
return self.title
And from views.py my view
def post_new(request):
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.save()
return redirect('blog.views.post_detail', pk=post.pk)
else:
form = PostForm()
return render(request, 'blog/post_edit.html', {'form': form})
When you save a form using commit=False you should call the save_m2m() method of the form:
post = form.save(commit=False)
post.author = request.user
post.save()
form.save_m2m()
Another, more elegant, solution is to pass the instance with preset field to the form's constructor. Is this case you don't need to use the commit=False argument:
form = PostForm(request.POST, instance=Post(author=request.user))
if form.is_valid():
post = form.save()
return redirect('blog.views.post_detail', pk=post.pk)

Categories

Resources