Django display hyperlink only to the creator of the object - django

I'm working on an project that let users create blogs and allow other users to comment on each other blogs.When a user creates a blog , their are certain ability that the blog owner can do such as deleting their own comments and the way I'm deleting comments is via hyperlink passing value id .
Everyone can see each other blogs but I want to only show the deletion hyperlink to the owner of the blog , so only the user who created the blog. How can I do this? via template
My models
class Blog(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
created = models.DateTimeField(auto_now_add=True)
description = models.TextField()
def Bloglook(request ,animal_id):
Blog = Blog.objects.get(pk=animal_id)
return render(request,'blog.html',{blog':blog})
my blog.html
{% if blog %}
{{blog.name%}}
{% endif %}
How Can I only show this link to the person who created the blog?
Delete blog

Use RequestContext to pass to template which passes request.user variable to template, which you can use to check for owner of blog.
Change your view to use RequestContext as
def Bloglook(request ,animal_id):
Blog = Blog.objects.get(pk=animal_id)
return render_to_response('blog.html',{blog':blog},
context_instance = RequestContext(request))
Then in template do
{% if blog.owner == request.user %}
Delete blog
{%endif%}

{% if request.user==blog.user %} Delete blog{% endif %}
Edited:
This will also be hidden from unautenticated users. Only if user is the owner then he will see the deletion link
Also, you can continue using render, there is no need to change to render_to_response.

Related

How to define permission on django views?

I have these models:
class Author(Model):
user = OneToOneField(User, on_delete=CASCADE)
# Fields
class Post(Model):
author = ForeignKey(Author, on_delete=CASCADE)
title = models.CharField(max_length=200)
text = models.TextField()
and a few views as below:
def authors(request)
authors = Authors.objects.all()
return render(request, 'authors.html', {'authors': authors})
The authors' view has a corresponding url path as below:
path('authors/', authors, name='authors')
in authors.html I loop over authors and for each one, I have a link that
sends the author primary key to the author url and view:
{% for author in authors%}
<a href="{% url 'author' author_pk=author.pk %}"{{author.user.email}}</a><br><br>
{% endfor %}
Ok; Everybody is able to see the list of authors.
I then have author url path as below:
path('authors/<int:author_pk>/', author, name='author')
path('authors/<int:author_pk>/<int:post_pk>/delete/', author_delete_post, name='author_delete_post')
And I have the author view in which I show the posts each author has published and a button to delete it.
def author(request, author_pk)
author=get_object_or_404(Author, pk=author_pk)
author_posts = Post.objects.filter(author=author)
return render(request, 'author.html', {'author_posts': author_posts}
#login_required
def author_delete_post(request, author_pk, post_pk):
author=get_object_or_404(Author, pk=author_pk)
author_post = Post.objects.get(author=author, pk=post_pk) # I know that author=author is redundent but it makes no problem
author_post.delete()
return redirect(author, author_pk)
This author template:
{% for author_post in author_posts %}
{{author_post.title}}<br>
{% if user.is_authenticated and author.user == user %}
Delete<br><br><br>
{% endif %}
{% endfor %}
I am letting those authors who are logged in and are in their own page to be able to see the delete button. This is something like facebook that a user is able to delete just his/her posts, not other's.
My problem:
Suppose there is an other having pk=1 and is logged in.
Although he/she cannot see delete button when he/she is in this page:
'/authors/2/'
he/she can play with the url and delete a post of another user having pk=2
'authors/2/10/delete/'
How can I solve this problem?
You can use the request.user to check if the object belongs to the logged in user
Also you should not need to add the author_pk. You can get the author with author = get_object_or_404(Author, user=request.user)
#login_required
def author_delete_post(request, post_pk):
author = get_object_or_404(Author, user=request.user)
author_post = Post.objects.get(author=author, pk=post_pk) # I know that author=author is redundent but it makes no problem
# check if the post belongs to the logged in user
if author_post.author.user == request.user:
# delete here
return redirect(author, author.pk)

how do I make a query of a user's uploaded files

I'm a django newbie trying to finish a upload/download app. I am Using django-registration-redux for user reg/auth and have the following simple model. I've read the docs but haven't been able figure out how to query on a User's related fields namely, fields of a model with foreignkey to User.
here's my model:
from django.contrib.auth.models import User
FileUploads(models.Model):
owner = models.ForeignKey(User)
docfile = models.FileField(nul=True)
docfileuuid = models.UUID()
My question being: Having a specific username, How can I query the list of his/her docfiles?
What I want to accomplish is when the user logs in and navigates through a view let's call it 'localhost:/yourfiles', s/he can be provided a list of his files.
In case of having no owner with foreign key to user, I used the following code to retreive the path to the all uploaded files:
obj = FileUploads.objects.all
uploads = [i.docfile for i in]
Now instead of all the docfiles, I want the ones that belong to the logged-in user.
I read the docs and tried things like:
obj = User.objects.all()
obj.fileuploads_set.all()
But no luck
When a user logs in your application, you do have user object in request.user
In your views.py,
def file_list_view(request):
# This gives you list of file objects.
files = FileUploads.objects.filter(owner=request.user)
return render_to_response('my_template.html', {'files': files})
In your template file
<ul>
{% for file in files %}
<li>{{ file.file_name }}</li>
{% endfor %}
</ul>
Hope this helps.
To get all files belong to a user by querying the username, do:
FileUploads.objects.filter(owner__usename='amir')
In your views.py, you would do:
uploads = FileUploads.objects.filter(owner=request.user)
You can create a simple function view with a context dictionary. Filter the files in your model by the current user logged in which you can get by request.user. And then in your template use a for loop to print all file urls that user has, and by using the {% empty %} template tag to show a message whenever a user doesn't have any files uploaded.
views.py
#login_required
def userfiles(request):
context_dict = {}
files = FileUploads.objects.filter(owner=request.user)
context_dict['files'] = files
return render(request, 'users_files.html', context_dict, )
the template:
{% for file in files %}
file.docfile.url
{% empty %}
You don't have any files uploaded yet.
{% endfor %}

how can I ensure a user will not delete another user object in my website [Django]

I wrote a function that allows the user to delete his article on a blog website. The problem is, if he plays a little with the url, he can access to another article and delete it.
What is the common strategy to avoid such cases with django?
here are the codes I wrote for the fonction:
views.py
def delete_article(request, id):
deleted = False
logged_user = get_logged_user_from_request(request) #that line allow to ensure that the user is connected. I use the session to achieve that instead of extending the User model
offer = get_object_or_404(Offer, id=id)
if request.method == 'POST':
offer.delete()
deleted = True
return render(request, 'offers/delete_article.html', locals())
urls.py
urlpatterns = patterns('article.views',
url(r'^send_article$', 'send_article', name='send_article'),
url(r'^my_articles$', 'show_my_articles', name='my_articles'),
url(r'^article/(?P<id>\d+)$', 'read', name='read'),
url(r'^articles$', 'show_articles', name='articles'),
url(r'^search_article$', 'search', name='search'),
url(r'^delete_article/(?P<id>\d+)$', 'delete_offer', name='delete_offer'),
)
delete_article.html
{% if not deleted %}
Hey, are you sure you want to delete {{ article.title }}?
<form method="POST">
{% csrf_token %}
<button type="submit" class="deleting_offer_button">delete</button>
</form>
{% elif deleted %}
<p>the article was successfully deleted</p>
get back to the homepage<br />
{% endif %}
As you can see, if the user change the numer of the id in the url, he can delete other article when he is directed to the confirmation of deleting page.
What webmasters are doing to ensure users cannot interfere with objects of other users?
HttpResponseForbidden can be used here which uses a 403 status code. A 403 response generally used when authentication was provided, but the authenticated user is not permitted to perform the requested operation.
Assuming you have author as an foreign key in Offer model, you can change your views like this:
In your views.py you have to import :
from django.http import HttpResponseForbidden
And then in your delete_article method use this code
offer = get_object_or_404(Offer, id=id)
if offer.author != request.user:
return HttpResponseForbidden()
When you get the article/offer. Make sure that the owner of that article is the authenticated user.
I'm not sure what your models look like but it would be something like
offer = get_object_or_404(Offer, id=id, author=logged_user)
This way if they don't own the article, it will 404

How to use models associated with a user in Django when rendering an HTML page

I'm in the learning stages of django. I just dived into a project to learn the framework and am having a series of questions throughout the process.
I basically want to have individual pages for users who create a task list and have them post tasks to their own page.
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class UserProfile(models.Model):
# This line is required. Links UserProfile to a User model instance.
user = models.OneToOneField(User)
# The additional attributes we wish to include.
website = models.URLField(blank = True)
# Override the __unicode__() method to return out something meaningful!
def __unicode__(self):
return self.user.username
class TaskItem(models.Model):
taskn = models.CharField(max_length = 400)
usern = models.ForeignKey(User)
In my template, if the user has their task entered, how do I call it to render onto the page?
My View:
def profile_page(request, username):
user = User.objects.get(username=username)
taskitems = user.taskn_set.all()
return render_to_response('profile.html', {}, context)
Current issue:
'User' object has no attribute 'taskn_set'
{{ request.user.taskitem_set.all }} would give you all the related task items. Now, to display it in your template:
{% for task_item in user.taskitem_set.all %}
{{ task_item.task_n }}
{% endfor %}
would display the list of tasks.
Here is the documentation on reverse-queries on foreign key (related_name) Also, read this
you would do something like this:
{% for task in user.taskitem_set.all %}
{{ task.task_n }}
{% endfor %}
This will fetch all TaskItem instances related to your user. (notice the extra database query)
While i don't know how your view works, i will assume that you are making the right checks to make sure that every user can only see his own tasks.
One performance trick you will find most useful is to use prefetch_related('taskitem_set'), this will prefetch the TaskItem instances as long as your UserProfile instance with one query:
user = User.objects.filter(id=user_id).prefetch_related('taskitem_set')
You can tune the code to match your preferences.
Hope this helps!

Why won't date_based.archive_month in Django 1.3 work to show my blog posts?

I'm just trying to list my blog posts for a certain month in a certain year, but none of my posts are showing. When I type in the correct url: 2011/nov, no posts show up and I have Nov. 2011 posts saved in my admin.
Also, for some reason, my css file isn't being taken into account. When I go to the url, 2011/nov, I just get html with no styling and none of my posts. What am I doing wrong here?
#models.py
class Post(models.Model):
title = models.CharField(max_length=120)
slug = models.SlugField(max_length=120, unique = True)
body = models.TextField()
published = models.DateTimeField(default=datetime.now)
categories = models.ManyToManyField(Category)
def __unicode__(self):
return self.title
#urls.py
info_dict = {
'queryset': Post.objects.all(),
'date_field': 'published',
}
urlpatterns = patterns('',
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$',
date_based.archive_month,
dict(info_dict, template_name='blog/archive.html',)),
#blog/archive.html
<link href="../static/style.css" rel="stylesheet" type="text/css" media="screen" />
.
.
.
{% for post in post_list %}
<h3 class="title">{{post.title}}
</h3>
{% endfor %}
The CSS is not showing because you define it relatively to be ../static/style.css. When the address is /2011/jan the browser tries to get the css from /2011/static/style.css. Fix: Set the path to be absolute: /static/style.css.
You should be looping through object called object_list instead of post_list.
{% for post in object_list %}
The context variable that holds the post is called object_list not post_list so you should have:
{% for post in object_list %}
...
{% endfor %}
https://docs.djangoproject.com/en/dev/ref/generic-views/?from=olddocs#django-views-generic-date-based-archive-month
Your css file should be:
and if you are developing locally you need to set up the development server to server your media for you:
https://docs.djangoproject.com/en/dev/howto/static-files/#using-django-contrib-staticfiles
In addition to what pastylegs wrote above, you should also change this line
published = models.DateTimeField(default=datetime.now)
to this:
published = models.DateTimeField(auto_now_add=True)
In Python, named arguments are only evaluated once. This means that the default published value is the time your server last compiled the models.py file. Django offers a solution to this: setting the parameter auto_now_add=True, makes django use the actual current time for the field, when it's first created. Similarly, setting auto_now=True makes django set the current time for the field whenever it's saved.