I am trying to get users ip address for a blog project view counts, and when the user isn't logged in a get this error
integrityError at /article/another-post-to-test-things-out/
NOT NULL constraint failed: cms_viewcount.session
Here is my views.py
# regular blog details
def blog_detail(request, slug):
template_name = 'cms/single.html'
blog = Blog.objects.get(slug=slug)
msg = False
form = CommentForm()
ip=request.META['REMOTE_ADDR']
if not ViewCount.objects.filter(blogview=blog, session=request.session.session_key):
view=ViewCount(blogview=blog, ip_address=ip, session=request.session.session_key)
view.save()
blog_views=ViewCount.objects.filter(blogview=blog).count()
if request.user.is_authenticated:
user = request.user
if blog.likes.filter(id=user.id).exists():
msg = True
context = {'blog': blog, 'msg':msg, 'form':form, "view_count":blog_views,}
try:
if request.method == 'POST':
form = CommentForm(request.POST)
comment = form.save(commit=False)
comment.blog = blog
comment.owner = request.user
comment.save()
messages.success(request, 'Your review was successfully submitted!')
return redirect('blog-detail', slug=blog.slug)
if not request.user or not request.user.is_authenticated:
return render(request, template_name, context)
else:
return render(request, template_name, context)
except:
return render(request, "cms/login-prompt.html", context)
Here is the error on my browser also
view.save() …
Local vars
Variable Value
blog
<Blog: Another Post to test things out>
form
<CommentForm bound=False, valid=Unknown, fields=(body)>
msg
False
request
<WSGIRequest: GET '/article/another-post-to-test-things-out/'>
slug
'another-post-to-test-things-out'
template_name
'cms/single.html'
view
<ViewCount:>
PLease how can I fix this error , note everthing works fine when the user is logged in
models.py
#views count models
class ViewCount(models.Model):
blogview=models.ForeignKey(Blog, related_name="view_count", on_delete=models.CASCADE)
ip_address=models.CharField(max_length=50)
session=models.CharField(max_length=50)
def __str__(self):
return str(self.ip_address)
#comment model
class Comment(models.Model):
owner= models.ForeignKey(User, on_delete=models.CASCADE, null=True)
blog= models.ForeignKey(Blog, on_delete=models.CASCADE)
body = models.TextField(null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True,editable=False)
class Meta:
ordering = ['-created']
def __str__(self):
return str(self.blog)
forms.py if need be
#comment form
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['body']
labels = {
'body': 'Add a comment'
}
def __init__(self, *args, **kwargs):
super(CommentForm, self).__init__(*args, **kwargs)
for name, field in self.fields.items():
field.widget.attrs.update({'class': 'input'})
Here is the error again
IntegrityError at /article/another-post-to-test-things-out/
NOT NULL constraint failed: cms_viewcount.session
You aren't passing the required session argument in this line:
view=ViewCount(blogview=blog, ip_address=ip, session=request.session.session_key)
Since the user isn't logged in, the value is Null.
Allow the value to be Null:
`session=models.CharField(max_length=50, null = True)`
Or generate a session for an anonymous user.
Related
Im trying to handle the existing name of a Category, so that users wont be allowed to create 2 categories with the same name, but at the moment its taking all categories from the database, not only for the logged-in user. I dont know how and where to implement request.user.
I`m building an inventory app where everyone creates their own categories and adds items.
Thank you.
This is my model:
class Category(models.Model):
user = models.ForeignKey(User, default=1, on_delete=models.CASCADE,
related_name='category', null=True)
name = models.CharField(max_length=100, null=False, blank=False)
slug = models.SlugField(max_length=100)
created_on = models.DateTimeField(auto_now_add=True)
timestamp = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-timestamp']
verbose_name = 'category'
verbose_name_plural = 'categories'
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('category_detail', kwargs={'slug': self.slug})
This is my form:
class CategoryForm(forms.ModelForm):
add_category = forms.BooleanField(widget=forms.HiddenInput, initial=True)
class Meta:
model = Category
fields = ['name']
def clean_name(self):
name = self.cleaned_data.get('name')
if (name == ""):
raise forms.ValidationError('This field cannot be left blank')
for instance in Category.objects.all():
if instance.name == name:
raise forms.ValidationError('There is a category with the name ' + name)
return name
This is my view:
#login_required
def index(request):
categories = Category.objects.filter(user=request.user)
items = Item.objects.all()
add_item = ItemForm()
add_category = CategoryForm()
query = None
if request.method == 'POST':
if 'add_item' in request.POST:
add_item = ItemForm(request.POST)
if add_item.is_valid():
form = add_item.save(commit=False)
form.category = get_object_or_404(
Category, name=request.POST.get('category'),
user=request.user)
add_item.save()
return redirect('home')
else:
add_category = CategoryForm(request.POST)
if add_category.is_valid():
category_form = add_category.save(commit=False)
category_form.save()
messages.success(request, f'{name} has been added')
return redirect('home')
Edit Category View
#login_required
def category_edit(request, pk):
category = Category.objects.get(id=pk)
if request.method == 'POST':
form = CategoryForm(request.POST, instance=category)
if form.is_valid():
form.save()
messages.info(request, f'{category.name} has been updated!')
return redirect('home')
else:
form = CategoryForm(instance=category, user=request.user)
context = {
'form': form,
}
return render(request, 'category_edit.html', context)
Ive tried adding user = request.user in the form class, but that resulted in an error Ive tried adding category_form.user = request.user before saving the form but that was still taking names from every other user
Pass the request's user to the form:
class CategoryForm(forms.ModelForm):
add_category = forms.BooleanField(widget=forms.HiddenInput, initial=True)
def __init__(self, user, *args, **kwargs):
self.user = user
super().__init__(*args, **kwargs)
class Meta:
model = Category
fields = ['name']
def clean_name(self):
name = self.cleaned_data.get('name')
if (name == ""):
raise forms.ValidationError('This field cannot be left blank')
qs = Category.objects.filter(user=self.user, name=name)
if self.instance.pk:
# EXCLUDE CURRENT INSTANCE TO ENABLE EDIT
qs = qs.exclude(pk=self.instance.pk)
if qs.exists():
raise forms.ValidationError('There is a category with the name ' + name)
return name
then in the view you need to pass the user:
#login_required
def index(request):
categories = Category.objects.filter(user=request.user)
items = Item.objects.all()
add_item = ItemForm()
add_category = CategoryForm(user=request.user)
query = None
if request.method == 'POST':
if 'add_item' in request.POST:
add_item = ItemForm(request.POST)
if add_item.is_valid():
form = add_item.save(commit=False)
form.category = get_object_or_404(
Category, name=request.POST.get('category'),
user=request.user)
add_item.save()
return redirect('home')
else:
add_category = CategoryForm(user=request.user, data=request.POST)
if add_category.is_valid():
category_form = add_category.save(commit=False)
category_form.save()
messages.success(request, f'{name} has been added')
return redirect('home')
I have a feed and in this feed have posts and each post have comments, Now I can submit a comment for just the first post but when I try to come to the second or third post and submit comment this error rise
ValueError: The view videos.views.add_comment_post didn't return an HttpResponse object. It returned None instead.
I thought that the problem with the posts id conflict with each other so I passed all the comment fields to the template and the same error still happen. "this problem happen with any post except the first one"
My comments view
comment_form = PostCommentForm(request.POST )
if comment_form.is_valid():
user_comment = comment_form.save(commit=False)
user_comment.author = request.user
user_comment.save()
result = comment_form.cleaned_data.get('content')
user = request.user.username
return JsonResponse({'result': result, 'user': user})
My Post model
class Post(models.Model):
author = models.ForeignKey(Account, on_delete=models.CASCADE)
article = models.TextField(null=True, blank=True)
photo_article = models.ImageField(max_length=255, upload_to=get_poster_filepath)
created_date = models.DateTimeField(auto_now_add=True)
My comments model
class PostCommentIDE(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='ide_com')
author = models.ForeignKey(Account, on_delete=models.CASCADE)
content = models.TextField()
created_date = models.DateTimeField(auto_now_add=True)
My comments Form
class PostCommentForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
class Meta:
model = PostCommentIDF
fields = {'post', 'content'}
widgets = {
'content': forms.Textarea(attrs={'class': 'rounded-0 form-control', 'rows': '1', 'placeholder': 'Comment', 'required': 'True', })
}
def save(self, *args, **kwargs):
PostCommentIDF.objects.rebuild()
return super(PostCommentForm, self).save(*args, **kwargs)
when form is not valid the form is returning None.
you should return something(for example returning error messages) when form is not valid.
comment_form = PostCommentForm(request.POST)
if comment_form.is_valid():
user_comment = comment_form.save(commit=False)
user_comment.author = request.user
user_comment.save()
result = comment_form.cleaned_data.get('content')
user = request.user.username
return JsonResponse({'result': result, 'user': user})
else:
# do stuff here if form is not valid
return JsonResponse({'result': 'Something went wrong.'})
I am working on a simple blog which has a model Post. I am trying to create a form for adding blog posts (or adding comments to posts for that matter) so that end users don't have to fill out a form box asking the end user for a username. I would like to be able to just ask for a title and body text for a blog post, and when hit post, it will be posted as the authenticated user.
I tried not including 'user' field in fields in forms, but it seems to be mandatory. Maybe I need to just make it hidden somehow using widgets? In templates, I could maybe write the following:
{% if user.is_authenticated %}
<p>Posting as {{request.user}}</p>
{% else %}
<p><a href={% url 'register' %}Please register to add a blog post</a></p>
{% endif %}
Though I am not sure, I think it would make more sense to have logic in my views.py file.
Here's my 'blog.models' file:
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
text = models.TextField()
published_date = models.DateTimeField(auto_now=True)
# pip install Pillow
image = models.ImageField(null=True, blank=True,
upload_to='photos/%Y/%m/%d/',)
def summary(self):
"""Return a summary for very long posts to
get a glimpse from admin panel"""
return self.text[:100]
def _get_unique_slug(self):
"""Assigns a number to the end of a given slug field to prevent
duplicated slug error. if title of a post is 'ayancik', and another
user creates another post with the same title, second posts' slug
is assigned a value: 'ayancik-2'"""
slug = slugify(self.title)
unique_slug = slug
num = 1
while Post.objects.filter(slug=unique_slug).exists():
unique_slug = '{}-{}'.format(slug, num)
num += 1
return unique_slug
def save(self, *args, **kwargs):
"""Automatically assign slug to objects
by overriding save method"""
self.slug = self._get_unique_slug()
super().save(*args, **kwargs)
def pub_date_pretty(self):
return self.published_date.strftime('%b %e, %Y')
def __str__(self):
"""String representation"""
return self.title
def get_absolute_url(self):
# what does kwargs={'slug':self.slug} really achieve here?
# where would we use 'key-value' pair?
"""Returns the url to access a detailed post"""
return reverse('post-detail', kwargs={"slug": self.slug})
class Meta:
ordering = ['-published_date',]
class Comment(models.Model):
post = models.ForeignKey('blog.Post', on_delete=models.CASCADE,
related_name='comments')
user = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
approved_comment = models.BooleanField(default=False)
def approve_comment(self):
self.approved_comment = True
self.save()
def __str__(self):
return self.text
'blog.forms' file:
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['user', 'title', 'text', 'image']
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('user', 'text',)
and 'blog.views' file:
#login_required
def create_post(request):
if request.method == 'POST':
post_form = PostForm(request.POST)
if post_form.is_valid():
post = post_form.save(request)
post.save()
else:
print(post_form.errors)
else:
# when not POST request, display the empty form
# meaning -> if request.method=='GET':
post_form = PostForm()
context = {
'post_form': post_form,
}
return render(request, 'blog/addpost.html', context)
def add_comment_to_post(request, slug):
post = get_object_or_404(Post, slug=slug)
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', slug=slug)
else:
form = CommentForm()
template_name = 'blog/add_comment_to_post.html'
return render(request, template_name , {'form': form })
You omit the user in the PostForm:
class PostForm(forms.ModelForm):
class Meta:
model = Post
# no user
fields = ['title', 'text', 'image']
or we can display all fields except 'user' like:
class PostForm(forms.ModelForm):
class Meta:
model = Post
exclude = ('user', )
and then you add the user to the instance in your view:
from django.shortcuts import redirect
#login_required
def create_post(request):
if request.method == 'POST':
post_form = PostForm(request.POST, request.FILES)
if post_form.is_valid():
post = post_form.save(commit=False)
post.user = request.user
post.save()
return redirect('some_view')
else:
post_form = PostForm()
context = {
'post_form': post_form,
}
return render(request, 'blog/addpost.html', context)
The commit=False thus prevents the from from saving the Post object to the database.
Since you want to upload an image, you should pass request.FILES [Django-doc] to the PostForm as well, otherwise you will not process uploaded files. You furthermore need to specify that you use enctype="multipart/form-data" in your form:
<form enctype="multipart/form-data" method="POST" action="{% url 'create_post' %}">
...
</form>
It is better to use a redirect [Django-doc] in case of a successful POST request, since this is the Post/Redirect/Get pattern [wiki]. By rendering a new form, if the user refreshes the page, he/she would create a second post, which is probably not what you want.
I am trying to give a user the option to change his/her first/last name through a ModelForm. When I press submit, I get hit with the UNIQUE constraint failed: auth_user.username error. Here are my codes:
students/forms.py:
class EditProfileForm(UserChangeForm):
def clean_password(self):
# Overriding the default method because I dont want user to change
# password
pass
class Meta:
model = User
fields = (
'first_name',
'last_name',
)
students/views.py:
User = get_user_model()
def student_profile_view(request, slug):
if request.method == 'GET':
# forms
edit_name_form = EditProfileForm(instance=request.user)
context = {
'edit_name_form': edit_name_form,
}
return render(request, "students/profile.html", context)
class ChangeNameView(SuccessMessageMixin, UpdateView):
template_name = 'students/edit_profile.html'
model = User
form_class = EditProfileForm
success_message = "Your name has been updated"
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
form.instance.student_profile = StudentProfile.objects.get(slug=request.user.student_profile.slug)
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
"""If the form is valid, save the associated model."""
form.instance.username = self.request.user
self.object = form.save(commit=False)
return super().form_valid(form)
def get_success_url(self):
return reverse('students:student_profile_view', kwargs={'slug': self.object.student_profile.slug})
also fyi, User model is foreign key with StudentProfile.
students/models.py:
class StudentProfile(models.Model):
user = models.OneToOneField(User, related_name='student_profile', on_delete=models.CASCADE)
slug = models.SlugField(blank=True, unique=True)
avatar = models.ImageField(upload_to='student_profile/', null=True, blank=True)
description = models.CharField(max_length=120, null=True, blank=True)
objects = models.Manager()
def __str__(self):
return self.user.username
def get_absolute_url(self):
return reverse("students:student_profile_view", kwargs={"slug": self.slug})
I am pretty new to class based view so maybe I'm doing something wrong there?
I assume you do not have the user within the form so you need the form
def get_context_data (self, *args, **kwargs)
ctx = super().get_context_data(*args, **kwargs)
if self.request.method == 'POST':
ctx['form'] = EditProfileForm(instance=self.request.user)
and remove def form_valid()
I input qualified content to form but was checked as invalid by form.is_valid,
Here is my views:
I add print(request.POST) # test input to check posted successfully, and print("form is invalid.") #assert invalid to check if it's a valid form,
class CommentCreateView(View):
template_name = "article/article_detail.html"
def get(self, request, pk):
return redirect(f"/article/detail/{ pk }")
def post(self, request, pk):
self.article = Article.objects.get(id=pk)
form = CommentForm(request.POST)
print(request.POST) # test input
if form.is_valid():
print("form is valid.") #assert valid
comment = form.save(commit=False)
print(f"Comment: {form.cleaned_data}")
comment.owner = request.user
comment.article = self.article
comment.status = 0
comment.save()
return redirect(f"/article/detail/{ pk }")
else:
print("form is invalid.") #assert invalid
comments = (Comment.objects
.filter(article=self.article, status=0)
)
context = {'article': self.article,
'comments':comments,
"form": form}
return render(request, self.template_name, context)
The Comment model data`:
class Comment(models.Model):
STATUS = (
(0, 'normal'),
(-1, 'deleted'),
)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
article = models.ForeignKey(Article, on_delete=models.CASCADE)
comment = models.TextField() # set the widget
status = models.IntegerField(choices=STATUS)
date_created = models.DateTimeField(default=datetime.now)
date_updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.comment
And the forms.py
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['comment', 'date_created']
widgets = {'comment': forms.Textarea(attrs={'cols': 80})}
The error report:
Django version 1.11.13, using settings 'forum.settings'
Starting development server at http: // 127.0.0.1: 8001/
Quit the server with CONTROL-C.
<QueryDict: {'csrfmiddlewaretoken': ['jL9aDh0cSNgvlmGWtI5sogFlruIvLh4rHqt0jll2V3H70Bel35IDFq6cgkWhAJHK'], 'comment': ['issue a test']} >
form is invalid.
[09/Jun/2018 13:12:32] "POST /article/comment/create/17 HTTP/1.1" 200 4183
It checked that the form is invalid.
How to solve such a problem?