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.
Related
I am trying to allow user to post answer and comments to a particular bloq question
Q&A
Error displayed:
ValueError at /adding-url-patterns-for-views
Cannot assign "<SimpleLazyObject<django.contrib.auth.models.AnonymousUser object at 0x04A5B370>>": "PostAnswer.user" must be a "CustomUser" instance.
Here is my model
class PostQuestion(models.Model):
""" Model for posting questions """
title = models.CharField(max_length=100, unique=True)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE, null=True, blank=True)
slug = models.SlugField(unique=True, null=True, max_length=250)
created_on = models.DateTimeField('date published',
auto_now_add=True)
text_content = models.TextField()
tags = TaggableManager()
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('detail_view', kwargs={'slug': self.slug})
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
return super().save(*args, **kwargs)
class PostAnswer(models.Model):
""" Model for answering questions"""
question = models.ForeignKey(
PostQuestion,
on_delete=models.CASCADE,
related_name='comments',
)
text_content = models.TextField()
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
)
approved_comment = models.BooleanField(default=False)
created_on = models.DateTimeField('published', auto_now_add=True)
class Meta:
ordering = ['created_on']
def approve(self):
self.approved_comment = True
self.save()
def __str__(self):
return 'comment by {} on {}'.format(self.user, self.question)
Here is my views.py on an app
class Index(ListView):
queryset = PostQuestion.objects.all()
template_name = 'index.html'
context_object_name = 'posts'
paginate_by = 10
def detail(request, slug):
post = get_object_or_404(PostQuestion, slug=slug)
comments = post.comments.all()
# comment posted
if request.method == 'POST':
form = CommentForm(data=request.POST)
if form.is_valid():
form.instance.question = post
form.instance.user = request.user
form.save()
return redirect('post_detail', slug=slug)
else:
form = CommentForm()
context = {'post': post,
'comments': comments,
'form': form}
return render(request, 'detail.html', context)
My App form:
class CommentForm(forms.ModelForm):
text_content = forms.CharField(widget=PagedownWidget())
class Meta:
model = PostAnswer
fields = ['text_content']
My urls.py view for the app
from .views import detail, ask, Index
from django.urls import path
urlpatterns = [
# path('<slug:slug>/comment', add_comment_to_post, name='add_comment_to_post'),
path('ask/', ask, name='ask'),
path('<slug:slug>', detail, name='detail_view'),
path('', Index.as_view(), name='index'),
]
Here is the html template for the comment
<!--------Display a form for users to add a new comment------->
<h3>Leave a comment</h3>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary btn-sm">Add Comment</button>
</form>
This is all of code that I think you need to know the problem. I don't know if the problem can be caused for database or why are not all instructions in the views.
If you can help me, thanks you in advance.
The name of the field is question, not post, so you should rewrite the logic to:
new_comment.question = post
This will however still raise an error, since the user field is not filled in either.
Using commit=False is however not a good idea, since then the form can no longer save many-to-many fields. As far as I can see, there are at the moment no many-to-many fields, but nevertheless, if you later add such fields, you have to rewrite the logic. You can improve the view to:
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
#login_required
def detail(request, slug):
post = get_object_or_404(PostQuestion, slug=slug)
comments = post.comments.all()
if request.method == 'POST':
form = CommentForm(data=request.POST)
if form.is_valid():
form.instance.question = post
form.instance.user = request.user
form.save()
return redirect('page:detail_view', slug=slug)
else:
form = CommentForm()
context = {
'post': post,
'comments': comments,
'form': form
}
return render(request, 'detail.html', context)
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
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})
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
I am using django 1.11.6 and python 3.6.2
I'm new to django and there is no one to help me where i live so you guys are all my hope
in my django application in the add song section i faced an error
error message =
IntegrityError at /music/album/5/AddSong/ NOT NULL constraint failed:
music_song.album_id
here is my views file:
from django.views import generic
from django.views.generic import View
from .forms import UserForm
from django.views.generic.edit import CreateView,UpdateView,DeleteView
from django.shortcuts import render,redirect
from django.contrib.auth import authenticate, login
from .models import Album, Song
from django.core.urlresolvers import reverse_lazy
class IndexView(generic.ListView):
template_name = 'music/index.html'
context_object_name = 'all_albums'
def get_queryset(self):
return Album.objects.all()
class DetailView(generic.DetailView):
model = Album
template_name = 'music/detail.html'
context_object_name = 'album'
class AlbumCreate(CreateView):
model = Album
fields = ['artist', 'album_title', 'genre', 'album_logo']
class SongCreate(CreateView):
model = Song
fields = ['song_title', 'file_type']
class AlbumUpdate(UpdateView):
model = Album
fields = ['artist', 'album_title', 'genre', 'album_logo']
class AlbumDelete(DeleteView):
model = Album
success_url = reverse_lazy('music:index')
class UserFormView(View):
form_class = UserForm
template_name = 'music/registration_form.html'
#display a blank form
def get(self,request):
form = self.form_class(None)
return render(request,self.template_name, {"form": form})
#procces form data
def post(self,request):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
#cleaned (normalized) data
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user.set_password(password)
user.save()
#returns User objects if credentials are correct
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request,user)
return redirect('music:index')
return render(request,self.template_name, {"form": form})
and here is my models.py :
from django.db import models
from django.core.urlresolvers import reverse
class Album(models.Model):
artist = models.CharField(max_length=250)
album_title = models.CharField(max_length=500)
genre = models.CharField(max_length=100)
album_logo = models.FileField()
def get_absolute_url(self):
return reverse('music:detail', kwargs={'pk': self.pk})
def __str__(self):
return self.album_title + ' - ' + self.artist
class Song(models.Model):
album = models.ForeignKey(Album, on_delete=models.CASCADE)
file_type = models.CharField(max_length=10)
song_title = models.CharField(max_length=250)
is_favorite = models.BooleanField(default=False)
# song_file = models.FileField(null=True)
def __str__(self):
return self.song_title
def get_absolute_url(self):
return reverse('music:detail', kwargs={'pk': self.album.id})
urls.py:
from django.conf.urls import url
from . import views
app_name = 'music'
urlpatterns = [
# /music/
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^register/$', views.UserFormView.as_view(), name='register'),
# /music/album/54
url(r'^album/(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
# music/album/add
url(r'album/add/$', views.AlbumCreate.as_view(), name='album-add'),
# music/album/3/AddSong
url(r'album/(?P<pk>[0-9]+)/AddSong/$', views.SongCreate.as_view(), name='song-add'),
# music/album/2/update/
url(r'album/(?P<pk>[0-9]+)/AlbumUpdate/$', views.AlbumUpdate.as_view(), name='album-update'),
# music/album/2/delete/
url(r'album/(?P<pk>[0-9]+)/AlbumDelete/$', views.AlbumDelete.as_view(), name='album-delete'),
]
For creating forms I used Django built-in forms,I had to create one for adding albums and another for adding the album's songs
Here is my album_form.html screenshot
and here is my form-template.html screenshot:
and here is my song_form.html screenshot
In the form_valid method, you should fetch the album pk from the url kwargs and set the album on the form instance.
from. django.shortcuts import get_object_or_404
class SongCreate(CreateView):
model = Song
fields = ['song_title', 'file_type']
def form_valid(self, form):
album = get_object_or_404(Album, pk=self.kwargs['pk']
form.instance.album = album
return super(SongCreate, self).form_valid(form)
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