Restrict users to read exclusively one's own articles - django

I have the following article_detail view which restrict that only users logged in could read the details.
#login_required(login_url="/user/login/")
def article_detail(request, pk):
article = get_object_or_404(Article, pk=pk)
total_views = r.incr("article:{}:views".format(article.id))
page_number = request.GET.get('page_number', 1)
#mimic SO's 100 per-page
per_page = request.GET.get("per_page", 30)
....
How could I set that each user can exclusively read contents posted by oneself?
The article model
class Article(models.Model):
STATUS = (
(1, 'normal'),
(0, 'deleted'),
)
tags = models.ManyToManyField(Tag, blank=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
block = models.ForeignKey(Block, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
content = models.TextField() # set the widget
status = models.IntegerField(choices=STATUS, default=1)
date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ("-date_created",)
def __str__(self):
return self.title

Just add one more criteria (owner) in your query:
article = get_object_or_404(Article, pk=pk, owner=request.user)
If the request user is NOT the article owner, then 404 will be returned.
You can also return 403 permission denied error with following codes which is more meaningful to the client:
from from django.http.response import HttpResponseForbidden
article = get_object_or_404(Article, pk=pk)
if article.owner.pk != request.user.pk:
return HttpResponseForbidden()
... # permission checking pass, so other code goes here

Related

how to handle concurrency of bookmark system in django?

I tried to implement bookmark system for product,
when users click bookmark button, it will be recorded in his bookmark table,
and update bookmark count field in Product Model. However I faced DB Lock
when there is too many request at the same time. Also, I realized that when users
add or delete bookmark at the same time, there will be concurency issues like,
users can not read Product Information or Bookmark count or DB Lock..
How to handle concurrency in my situation? I know the exclusive lock but
it will lower the performance.. please help me..
here are my codes
class Bookmark(models.Model):
_id = models.AutoField(primary_key=True, editable=False)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='bookmark_user')
def __str__(self):
return str(self.user)
class BookmarkItems(models.Model):
_id = models.AutoField(primary_key=True, editable=False)
user = models.CharField(max_length=255, null=True, blank=True)
image = models.CharField(max_length=255, null=True, blank=True)
bookmark = models.ForeignKey(Bookmark, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
def image_preview(self):
if self.image:
return mark_safe('<img src="{0}" width="75" height="75" />'.format(self.image))
else:
return '(No image)'
def __str__(self):
return str(self.product)
#api_view(['POST'])
#permission_classes([IsAuthenticated])
def addBookmark(request):
user = request.user
user_id = request.data['user']
product_id = request.data['product_id']
image = request.data['image']
product = Product.objects.get(_id=product_id)
with transaction.atomic():
bookmark = Bookmark.objects.get_or_create(user=user)
Product.objects.filter(_id=product_id).update(
bookmark_count = F('bookmark_count') + 1
)
BookmarkItems.objects.create(
user = user_id,
image = image,
bookmark=bookmark[0],
product=product,
)
return Response({'success':'The bookmark has been created.'})
#api_view(['DELETE'])
#permission_classes([IsAuthenticated])
def deleteBookmark(request, pk):
user =request.user.id
with transaction.atomic():
Product.objects.filter(_id=pk).update(
bookmark_count = F('bookmark_count') - 1
)
BookmarkItems.objects.filter(user=user, product=pk).delete()
return Response({'success': 'The bookmark has been deleted.'})

How can I send Message.info from admin to another user in Django

When someone user tries to publish an article. The user must wait for the approval/disapproval of this article from the admin.
after approving/disapproving their articles, the users must get Message.info. But these messages showed on the admin page, not on a user page
the disapproved message:
this is model.py
class Article(models.Model):
auther = models.ForeignKey(User, on_delete= models.CASCADE)
title = models.CharField(max_length= 200, null = False)
bio = models.CharField(max_length = 450, null = False)
tags = TaggableManager()
body = RichTextField()
created_at = models.DateTimeField(auto_now_add = True)
updated_at = models.DateTimeField(auto_now = True)
approved = models.BooleanField('approved', default = 'False')
def __str__(self):
return self.title
this viws.py :
from django.contrib.auth.models import User
from article.models import Article
def delete_article(request, pk):
model_article = apps.get_model('article','Article')
if request.user.is_superuser:
id_user = model_article.objects.get(pk = pk).auther_id
model_article.objects.get(pk = pk).delete()
messages.info(request,' تم تنفيذ العملية بنجاح!' )
for x in User.objects.all():
if(x.id == id_user):
messages.info(request,
'تم حذف مقالك الجديد لأنه يخالف سياسة الموقع !')
return redirect('main')
But i want the message shwon to user who want to publish an article

LIke functoin view keep throwing DoesNotExist at /group/3/ after a second user in the group post when liked by another user

I am currently challenge with a like functionality on a group page for that I'm creating, the problem is that when a first user of the group post on the group page other users can comment and like at his post, but as soon as a second user of the same group post, then when the post get liked or commented on, it throws thess error DoesNotExist at /group/3/. i wonder why am getting this error, because when the first user posted it didn't throw that error, when his post got liked or commented on, but the error only shows up when a another user on the same group post and it got like or commented on. I would appreciate some help. Here is my like function view.
def like(request, pk):
user = request.user
post = Post.objects.get(pk=pk)
group = GroupEx.objects.get(group=pk)
liked= False
like = Like.objects.filter(username=user, post=post,group=group)
if like:
like.delete()
else:
liked = True
Like.objects.create(username=user, post=post, group=group)
resp = {
'liked':liked
}
response = json.dumps(resp)
return redirect('group:main', pk=pk)
return HttpResponse(response,content_type = "application/json")
Here is my comment view.
def comment(request, pk):
context = {}
user = request.user
post = get_object_or_404(Post, pk=pk)
group = get_object_or_404(GroupEx,pk=pk)
if request.method == 'POST':
form = NewCommentForm(request.POST)
if form.is_valid():
data = form.save(commit=False)
data.post = post
data.group = group
data.username = user
data.save()
return redirect('group:main', pk=pk)
else:
form = NewCommentForm()
context['form'] = form
return render(request,'group/grouptimeline.html',context)
Here this model for the group post .
class Post(models.Model):
group = models.ForeignKey(GroupEx, on_delete=models.CASCADE, related_name="group_post")
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE ,related_name="group_user")
description = models.TextField(max_length=500, blank=True)
pic = models.ImageField(upload_to='path/post/img' ,blank=True)
date_posted = models.DateTimeField(auto_now_add=True)
tags = models.CharField(max_length=100, blank=True)
class Comment(models.Model):
group = models.ForeignKey(GroupEx, on_delete=models.CASCADE, related_name="group_comment")
post = models.ForeignKey(Post, related_name='g_comments', on_delete=models.CASCADE, null=True, blank=True)
username = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='g_comments', on_delete=models.CASCADE,null=True)
comment = models.CharField(max_length=5000)
class Like(models.Model):
group = models.ForeignKey(GroupEx, on_delete=models.CASCADE, related_name="group_liker")
username = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='g_likes', on_delete=models.CASCADE)
post = models.ForeignKey(Post, related_name='g_likes', on_delete=models.CASCADE)
like_date = models.DateTimeField(auto_now=True)
comment_date = models.DateTimeField(auto_now_add=True)

`This field required error` though it's not defined in Model data table

I try to create a new article with model data:
class Article(models.Model):
STATUS = (
(0, 'normal'),
(-1, 'deleted'),
)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
block = models.ForeignKey(Block, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
content = models.TextField() # set the widget
status = models.IntegerField(choices=STATUS)
date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
However, when I submitted data from browser, it prompted that comment field is required thought it's not one of Article's fields.
I add a test command print(form.errors.as_data()) in CBV class ArticleCreateView(View):
Starting development server at http://127.0.0.1:8001/
Quit the server with CONTROL-C.
{'comment': [ValidationError(['This field is required.'])]}
[09/Jun/2018 22:50:16] "POST /article/create/1 HTTP/1.1" 200 3694
I have other table Comment whose ForeignKey is article
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(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.comment
The views.py
class ArticleCreateView(View):
template_name = "article/article_create.html"
def get(self, request, block_id):
block = Block.objects.get(id=block_id)
context = {'b':block}
return render(request, self.template_name,context)
def post(self, request, block_id):
block = Block.objects.get(id=block_id)
form = CommentForm(request.POST)
if form.is_valid():
article = form.save(commit=False)
article.owner = request.user
article.block = block
article.status = 0
article.save()
return redirect(f"/article/list/{ block_id }")
else:
print(form.errors.as_data())
context = {'b':block,
"form":form}
return render(request, self.template_name, context)
I had no idea why it throw such an error?
In your view, it says CommentForm.
class ArticleCreateView(View):
def post(self, request, block_id):
...
form = CommentForm(request.POST)
Maybe you wanted to use something like ArticleForm or whatever you have in your code?

Django admin does not show all entities

I've inherited an app created with Django. There is a problem with it: in admin interface, the page lists not all entities (videos), but some (16 of 25). I have no idea, what is this.
Then I run python manage.py shell, and there Video.objects.all(), there are all 25 objects (counted them using len and by iterating them with for loop).
I have found no managers or whatever (maybe I just don't know where to look for them).
On the bottom of admin page: 25 videos, while there are only 16 rows.
Then I add to VideoModelAdmin class list_per_page = 10, paginator show three pages, but only first two of them has any Videos, third shows no rows.
Here are some code.
# admin.py
class VideoModelAdmin(admin.ModelAdmin):
list_display = ['title', 'short_desc', 'author', 'redactor_choise', 'views_num', 'rating', 'is_published']
list_filter = ['is_published', 'redactor_choise']
list_per_page = 10
actions = ['make_published', 'update_comments_count']
exclude = ('file_lq', 'file_hq', )#'thumb',)
def make_published(self, request, queryset):
queryset.update(is_published=1)
make_published.short_description = "Опубликовать выделенные"
def save_model(self, request, obj, form, change):
instance = form.save(commit=False)
instance.author = request.user
instance.save()
return instance
def update_comments_count(self, request, queryset):
for video in queryset:
video.update_comments_count()
update_comments_count.short_description = "Пересчитать комментарии!"
# later there
admin.site.register(Video, VideoModelAdmin)
# models.py
class Video(models.Model):
def make_upload_path(instance, filename):
return 'video/thumbs/' + generate_random_name(filename)
category = models.ManyToManyField(Category, limit_choices_to = {'is_published': 1})
title = models.CharField(max_length=128)
short_desc = models.CharField(max_length=255)
long_desc = tinymce_models.HTMLField(blank=True)
file_lq = models.FileField(upload_to='video/lq/', null=True, blank=True)
file_hq = models.FileField(upload_to='video/hq/', null=True, blank=True)
thumb = models.FileField(upload_to=make_upload_path, blank=True, null=True)
#thumb = fields.ThumbnailField(upload_to=make_upload_path, sizes=settings.VIDEO_THUMB_SIZE, blank=True, null=True)
author = models.ForeignKey(User, editable=False)
redactor_choise = models.BooleanField(default=False)
views_num = models.SmallIntegerField(default=0, editable=False)
comments_num = models.SmallIntegerField(default=0, editable=False)
rating = models.SmallIntegerField(default=0, editable=False)
voters = fields.PickledObjectField(blank=True, editable=False)
created = models.DateTimeField(auto_now_add=True)
is_published = models.BooleanField(default=False)
def get_absolute_url(self):
return "/video/%d" % self.id
def views_num_plus(self):
cursor = connection.cursor()
cursor.execute('update soctv_video set views_num=views_num+1 where id=%d', [self.id])
cursor.close()
def update_comments_count(self):
from threadedcomments.models import ThreadedComment as Comment
self.comments_num = Comment.objects.filter(video=self).count()
self.save()
#cursor = connection.cursor()
#cursor.execute('update soctv_video set comments_num = (select count(*) from soctv_comment where video_id = %s) where id = %s', [self.id, self.id])
#cursor.close()
def update_categories_counts(self):
cursor = connection.cursor()
cursor.execute('update soctv_category set num_items = (select count(*) from soctv_video_category where category_id = soctv_category.id)')
cursor.close()
def is_user_voted(self, uid):
try:
if self.voters[uid]:
return self.voters[uid]
except Exception:
return False
def increment_view_count(self, token):
import md5
token = md5.new(token).hexdigest()
if VideoView.objects.filter(uniquetoken=token).count() == 0:
VideoView(uniquetoken = token, video = self).save()
def view_count(self):
return self.views_num + VideoView.objects.filter(video=self).count()
def __unicode__(self):
return unicode(self.title)
The problem can be that some FK in some of your videos points to something that does not exist.
I had the same problem and this was the reason.
Django will silently fail if the value is not there in the foreign key column.
Add both null and blank attribute to the column
null=True, blank=True
Make sure that you are logged in to the correct account aswell.
In my case, My account did not have permissions to modify <Model>