Django duplicates my entry when I store something - python

When I try to save a post, the post is saved, but current user is not registered and the post is duplicated with a blank entry and the current user is not stored.
For adding the post I use not the admin app but a personal template and form.
See the problem:
This is my view code:
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from .forms import NewAdminPostForm
from .models import Post, Category
# Create your views here.
def home(request):
posts = Post.objects.all()
categories = Category.objects.all()
posts_last = Post.objects.order_by('-created_at')[0:3]
return render(request, 'front/blog-list.html', {'posts': posts,
'categories': categories, 'posts_last': posts_last})
#login_required
def newadminpost(request):
if request.method == 'POST':
form = NewAdminPostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
Post.objects.create(
message=form.cleaned_data.get('message'),
category_id=post.category_id,
created_by=request.user
)
#post.save()
return redirect('listadminpost')
else:
form = NewAdminPostForm()
return render(request, 'back/new-post-blog.html', {'form': form})
#login_required
def listadminpost(request):
posts = Post.objects.all()
return render(request, 'back/list-post-blog.html', {'posts': posts})
Form of my Blog:
from django import forms
from .models import Post, Category
class NewAdminPostForm(forms.ModelForm):
title = forms.CharField(label="Titre de l'article", max_length=255,)
message = forms.CharField(widget=forms.Textarea(),
max_length=4000,
help_text="Contenu de l'article")
pre_message = forms.CharField(label="Message de prévisu",
widget=forms.Textarea(),
max_length=4000,
help_text="Contenu de l'article")
class Meta:
model = Post
fields = ['title','meta_desc','message','pre_message','category']
Model of my Blog:
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=255, unique=True)
description = models.TextField(max_length=1000)
def __str__(self):
return self.name
def get_categories_count(self):
return Category.objects.filter(post__category=self).count()
class Post(models.Model):
title = models.CharField(max_length=255)
meta_desc = models.TextField(max_length=320, null=True)
pre_message = models.TextField(max_length=4000, null=True)
message = models.TextField(max_length=4000)
category = models.ForeignKey(Category, on_delete='cascade')
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(User, on_delete=models.CASCADE,
blank=True, null=True)
def __str__(self):
return self.title

https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.create
your code:
post.save()...Post.objects.create(
from the link above:
A convenience method for creating an object and saving it all in one step. Thus:
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
and:
p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)
are equivalent.
So what you do in your code:
you save post object created from form
you create and save another Post instance by calling create method
choose any of them, just one, and this will avoid duplicates.

Instead of doing this:
#login_required
def newadminpost(request):
if request.method == 'POST':
form = NewAdminPostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
Post.objects.create(
message=form.cleaned_data.get('message'),
category_id=post.category_id,
created_by=request.user
)
#post.save()
return redirect('listadminpost')
else:
form = NewAdminPostForm()
return render(request, 'back/new-post-blog.html', {'form': form})
You could do this: cleaner, easier to read, more up-to-date, and easier to maintain:
class AdminCreateView(LoginRequiredMixin, generic.CreateView):
model = Request
form_class = RequestForm
def form_valid(self, form):
result = super(AdminCreateView, self).form_valid(form)
title = form.cleaned_data.get('title')
meta_desc = form.cleaned_data.get('meta_desc')
message = form.cleaned_data.get('message')
# and so on. if there's something you refuse (ex title empty) do this:
if not title:
form.add_error('title', _("Precise the title"))
return self.form_invalid(form)
Post.objects.create(message=message,
meta_desc=meta_desc,
title=title,) # and so on
return result

Related

How set username to ForeignKey

I want to set value, but i don't know how do it.
Error:
RelatedObjectDoesNotExist at /comments/
commentsTabl has no avtor.
Request Method: GET
Request URL: http://localhost:8000/comments/
Django Version: 4.0.2
Exception Type: RelatedObjectDoesNotExist
Exception Value:
commentsTabl has no avtor.
Exception Location: D:\python39\lib\site-packages\django\db\models\fields\related_descriptors.py, line 197, in get
Python Executable: D:\python39\python.exe
Python Version: 3.9.6
Python Path:
['D:\Django\ForumXT\first',
'D:\python39\python39.zip',
'D:\python39\DLLs',
'D:\python39\lib',
'D:\python39',
'D:\python39\lib\site-packages']
Server time: Thu, 07 Apr 2022 12:20:35 +0000
models.py
class commentsTabl(models.Model):
Text = models.TextField(verbose_name='Text')
date = models.DateTimeField(default=timezone.now, verbose_name='date')
avtor = models.ForeignKey(User, verbose_name='avtor', on_delete=models.CASCADE, to_field="username")
def __str__(self):
return f'Comment {self.avtor} at {self.date}'
class Meta:
verbose_name = "Comment"
verbose_name_plural = "Comments"
views.py
def comments(request):
data = {
'com': reversed(commentsTabl.objects.all())
}
if request.method =="POST":
form = commentsTabl(request.POST)
if form.is_valid():
form.save()
else:
form = commentsTabl()
return render(request, 'home/comments.html', data, {'form':form})
In models.py
class Comment(models.Model):
Text = models.TextField(verbose_name='Text')
date = models.DateTimeField(auto_add_now=True, verbose_name='date')
avtor = models.ForeignKey(User, verbose_name='avtor', on_delete=models.CASCADE)
def __str__(self):
return 'Comment {} at {}'.format(self.avtor, self.date)
class Meta:
# Order comments in reverse order
# ordering = ["-id"]
In views.py
from .forms import CommentForm
from .models import Comments
from django.http import HttpResponseRedirect
from django.urls import reverse
def comments(request):
# Retrive all comments from database
comments = Comment.objects.all()
# Reverse ...
comments = reversed(comments)
# Form with no data (unbound form)
form = CustomerForm()
context = {"comments": comments, "form": form}
# when method is post
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
# Don't save the form to database
comment = form.save(commit=False)
# Add user to the comment
comment.avtor = request.user
# Save comment to database
comment.save()
return HttpResponseRedirect(reverse('some url name'))
# when form is invalid
else:
# Re-render the form with errors and data
context["form"] = form
return render(request, "home/comments.html", context)
# when method is not post
else:
return render(request, "home/comments.html", context)
In forms.py
from django.forms import ModelForm
from .models import Comment
# Create your forms here
class CommentForm(ModelForm):
class Meta:
model = Comment
fields = ("Text", "date",)
# or
# exclude = ("avtor",)
# fields = "__all__"
Important
python manage.py makemigrations
python manage.py migrate
In comments.html you will have access to form and comments

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.

I want to show my articles - latest article should appear first

hi i want to show my articles latest article should appear first i used class Meta in models but its not working it does not show any error but it it shows old articles on top. if anyone can please help that would be very helpfull
models.py
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
class Article(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField()
body = models.TextField()
date = models.DateTimeField(default=timezone.now)
thumb = models.ImageField(default='default.png', blank=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, default=None)
class Meta:
ordering = ['-date']
def __str__(self):
return self.title
def snippet(self):
return self.body[:100]+'...'
views.py
from django.http import HttpResponse
from django.shortcuts import render, redirect
from .models import Article
from django.contrib.auth.decorators import login_required
from . import forms
def article_list(request):
articles = Article.objects.all().order_by('date')
return render(request, 'articles/article_list.html', {'articles': articles})
def article_detail(request, slug):
# return HttpResponse(slug)
article = Article.objects.get(slug=slug)
return render(request, 'articles/article_detail.html', {'article': article})
#login_required(login_url="/accounts/login/")
def article_create(request):
if request.method == 'POST':
form = forms.CreateArticle(request.POST, request.FILES)
if form.is_valid():
# save article to db
instance = form.save(commit=False)
instance.author = request.user
instance.save()
return redirect('articles:list')
else:
form = forms.CreateArticle()
return render(request, 'articles/article_create.html', {'form': form})
In your view, you order in ascending order, you should prepend date with a minus (-):
def article_list(request):
articles = Article.objects.order_by('-date')
return render(request, 'articles/article_list.html', {'articles': articles})
or if you do not specify an order, then the ordering defined in Meta will be applied:
def article_list(request):
articles = Article.objects..all()
return render(request, 'articles/article_list.html', {'articles': articles})

NOT NULL constraint failed: community_comment.posts_id?

how can I fix this issue?
the page runs perfectly. when I do post the post. it posts but when I want to type the comment and send by 'GET' I get this error. so, how can I ignore this error this my first question?
- also, I need anyone to give me the best way to make a relationship between post and comment
models.py
from django.db import models
from django.contrib.auth.models import User
class Publication(models.Model):
title = models.CharField(max_length=30)
class Meta:
ordering = ['title']
def __str__(self):
return self.title
class Article(models.Model):
publications = models.ManyToManyField(Publication)
headline = models.CharField(max_length=100)
class Meta:
ordering = ['headline']
def __str__(self):
return self.headline
class Post(models.Model):
users = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
question = models.TextField(max_length=500)
def __str__(self):
return self.title
class Comment(models.Model):
posts = models.ForeignKey(Post, on_delete=models.CASCADE)
comment = models.TextField(max_length=500)
def __str__(self):
return self.comment
views.py
from django.shortcuts import render, redirect
from django.contrib.auth.models import User
from .models import Post, Comment
from .forms import PostForm, CommentForm
def index(request):
# All questions
posts = Post.objects.all()
return render(request, 'community/index.html', {'posts': posts})
def post_view(request):
post_form = PostForm
context = {'posted': post_form}
# Create post
if request.method == 'GET':
post_form = PostForm(request.GET)
if post_form.is_valid():
user_post = post_form.save(commit=False)
user_post.title = post_form.cleaned_data['title']
user_post.question = post_form.cleaned_data['question']
post = Post.objects.create(users=User.objects.get(username=request.user), title=user_post.title, question=user_post.question)
post.save()
return redirect('community:index')
return render(request, 'community/post.html', context)
def answers(request, post_id):
# Specific post
posts = Post.objects.get(id=post_id)
# Create comment
comment_form = CommentForm
context = {'posts': posts, 'comment_form': comment_form}
if request.method == 'GET':
comment_form = CommentForm(request.GET)
if comment_form.is_valid():
user_comment = comment_form.save(commit=False)
user_comment.comment = comment_form.cleaned_data['comment']
user_comment.save()
return render(request, 'community/answers.html', context)
urls.py
from django.urls import path
from . import views
app_name = 'community'
urlpatterns = [
path('', views.index, name='index'),
path('post/', views.post_view, name='post'),
path('answers/<int:post_id>', views.answers, name='answers'),
]
forms.py
from .models import Post, Comment
from django import forms
from django.contrib.auth.models import User
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = '__all__'
exclude = ['users']
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = '__all__'
exclude = ['users', 'posts']
You forgot to assign the post, or the post_id of the comment you created:
def answers(request, post_id):
# Specific post
posts = Post.objects.get(id=post_id)
# Create comment
comment_form = CommentForm
context = {'posts': posts, 'comment_form': comment_form}
if request.method == 'GET':
comment_form = CommentForm(request.GET)
if comment_form.is_valid():
comment_form.instance.post_id = post_id
user_comment = comment_form.save()
# …
That being said, the above view does not really respect the HTTP assumptions. A view that makes a GET request is not supposed to change entities, so if you want to create a comment, you need to do that through a POST request. Furthemore in order to implement the Post/Redirect/Get pattern [wiki] a successful POST request should return a redirect response.

Django - How to allow only the owner of a new post to edit or delete the post?

I will be really grateful if anyone can help to resolve the issue below.
I have the following Django project coding. The problem is: when the browser was given "/posts/remove/<post_id>/" or "/posts/edit/(<post_id>/" as the url, it will allow the second user (not owner) to perform the remove and edit jobs, respectively.
How can I allow only the owner of a new post to edit or delete the post?
account.models.py:
from django.db import models
from django.conf import settings
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
def __str__(self):
return 'Profile for user {}'.format(self.user.username)
posts.models.py:
from django.db import models
from django.conf import settings
from django.utils import timezone
from django.utils.text import slugify
from django.core.urlresolvers import reverse
from taggit.managers import TaggableManager
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager, self).get_queryset().filter(status='published')
class Post(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
related_name='posts_created')
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique_for_date='created')
image = models.ImageField(upload_to='images/%Y/%m/%d', null=True, blank=True)
description = models.TextField(blank=True)
created = models.DateTimeField(default=timezone.now,
db_index=True)
updated = models.DateTimeField(auto_now=True)
users_like = models.ManyToManyField(settings.AUTH_USER_MODEL,
related_name='posts_voted',
blank=True)
status = models.CharField(max_length=10, default='published')
objects = models.Manager() # The default manager.
published = PublishedManager() # The Dahl-specific manager.
tags = TaggableManager()
class Meta:
ordering = ('-created',)
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('posts:detail', args=[self.id, self.slug])
posts.view.py:
from django.views.decorators.http import require_POST
from django.shortcuts import render, redirect, get_object_or_404, render_to_response
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.conf import settings
from django.core.context_processors import csrf
from .forms import PostCreateForm, EmailPostForm, CommentForm, SearchForm
from .models import Post
from actions.utils import create_action
#login_required
def post_create(request):
"""
View for creating a new post.
"""
if request.method == 'POST':
# form is sent
form = PostCreateForm(data=request.POST, files=request.FILES)
if form.is_valid():
cd = form.cleaned_data
new_item = form.save(commit=False)
# assign current user to the item
new_item.user = request.user
tags = form.cleaned_data['tags']
new_item.save()
for tag in tags:
new_item.tags.add(tag)
new_item.save()
create_action(request.user, 'created a post:', new_item)
messages.success(request, 'Post added successfully')
form = PostCreateForm()
else:
messages.error(request, 'Error adding new post')
else:
# build form
form = PostCreateForm(data=request.GET)
return render(request, 'posts/post/create.html', {'section': 'posts',
'form': form})
#login_required
def post_remove(request, post_id):
Post.objects.filter(id=post_id).delete()
return redirect('posts:mypost')
#login_required
def post_edit(request, post_id):
item = Post.objects.get(pk=post_id)
if request.method == 'POST':
form = PostCreateForm(request.POST, instance=item)
if form.is_valid():
form.save()
return redirect('posts:mypost')
else:
form = PostCreateForm(instance=item)
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('posts/post/post_edit.html', args)
posts.urls.py
from django.conf.urls import url
from . import views
from .feeds import LatestPostsFeed
urlpatterns = [
url(r'^create/$', views.post_create, name='create'),
url(r'^remove/(?P<post_id>\d+)/$', views.post_remove, name='post_remove'),
url(r'^edit/(?P<post_id>\d+)/$', views.post_edit, name='post_edit'),
]
Add request.user == item.user check inside your method.
#login_required
def post_remove(request, post_id):
item = Post.objects.get(pk=post_id)
if request.user == item.user:
Post.objects.filter(id=post_id).delete()
return redirect('posts:mypost')
#login_required
def post_edit(request, post_id):
item = Post.objects.get(pk=post_id)
if request.user == item.user:
...
//write your code here

Categories

Resources