Django CMS Aldryn NewsBlog delete Articles from the frontend - django

I'm trying to get the standard Aldryn Newsblog Buttons working in my Frontend Page. So every User can Add, Delete and Edit Articles(only the articles they created themselves but thats not the question). This is the Menu with the links:
Menu in the Toolbar
So i want to add a Button in my template wich triggers the edit, add or delete prompt: Delete prompt
I hope someone can help me. Thanks in advance.

If you really don't want all employees to see the toolbars, then you're taking on quite a bit of extra work. I would still consider this as an option, as you can apply permissions so that a user can only edit the content you allow, which means that users can take full advantage of Django CMS's built in functionality, which is great.
If you still don't want to take this route then you're going to have to build your own mini admin for your article model. Below I've quickly thrown together an idea for how you can approach this to hopefully help point you in the right direction.
First, your article view should be something like:
from django.views.generic import DetailView
from .models import Article
class ArticleView(DetailView):
context_object_name = 'article'
model = Article
template_name = 'path/to/article.html'
def get_context_data(self, **kwargs):
context = super(ArticleView, self).get_context_data(**kwargs)
context['show_controls'] = (self.request.user.is_authenticated() and
context[self.context_object_name].article == self.request.user)
return context
With the article template like:
<section>
{% if show_controls %}
<div class="controls">
Delete
Edit
</div>
{% endif %}
<article>
...
</article>
</section>
The path to delete view could be a confirm page like the Django admin. So you'd have a view like:
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from django.shortcuts import get_object_or_404, redirect, render
from .models import Article
#login_required
def delete_article(request, article_pk):
if request.method == "POST":
article = get_object_or_404(Article, pk=article_pk)
if request.user != article.author:
raise PermissionDenied
article.delete()
return redirect('/redirect/url')
else:
context = {}
...
return render(request, 'path/to/confirm/delete.html', context)
With a template along the lines of:
<section>
<form method="POST">
{% csrf_token %}
<p>Are you sure you want to delete?</p>
<input type="submit" value="Delete">
</form>
</section>
You'd then create a similar setup for the edit page, navigate the user to a page that has a form where the fields can be amended and submitted etc.

Related

CreateView form is not "rendering" in a template tag

Setup
I have successfully setup a CreateView class that allows user to create a Journal. You only have to enter the name and press the "Add" button.
views.py
...
class CreateToJournal(LoginRequiredMixin, CreateView):
model = to_journal
template_name = 'to_journals/to_journal_list.html'
fields = ('journal_name',)
def get_success_url(self):
return reverse('to-journals')
def form_valid(self, form):
form.instance.journal_user = self.request.user
return super(CreateToJournal, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(CreateToJournal, self).get_context_data(**kwargs)
context['to_journals'] = to_journal.objects.filter(journal_user=self.request.user)
return context
...
to_journal_list.html
...
<form class="" id="myForm" action="" method="post">
{% csrf_token %}
{{ form }}
<button type="submit" id="add-button">Add</button>
</form>
...
This creates a new Journal and reloads the page to reflect the changes made.
I am now trying to move the whole Journal creation process to the "home" page, using a template tag. Mostly it works fine and renders all user journals on the home page, but there is a problem with form rendering.
Problem
The new template tag does not render the form created by CreateView. The input field is not displayed here on the page with a template tag.
I couldn't find any specific information (or general, for that matter) regarding the relationship between forms and templatetags.
My setup for the template tag is the following:
...
├───pages
│ └───templatetags
│ └───__init__.py
│ └───journal_tags.py
...
├───templates
│ └───template_tags
│ └───journal_list.html
...
Where pages is the app for "static" pages.
journal_tags.py
from django import template
from to_journals.models import to_journal
register = template.Library()
#register.inclusion_tag('template_tags/journal_list.html', takes_context=True)
def get_journals(context):
journals = to_journal.objects.filter(journal_user=context['request'].user)
return {'journals': journals}
journal_list.html
...
<form class="" id="myForm" action="" method="post">
{% csrf_token %}
{{ form }}
<button type="submit" id="add-button">Add</button>
</form>
...
home.html
...
{% load journal_tags %}
{% get_journals %}
...
Thanks for taking the time to look at this question. Any help is appreciated.
If more information is needed I will happily provide.
Edit
I know realize that I have no reference to the view class created class CreateToJournal(LoginRequiredMixin, CreateView) in my template tag at all. I couldn't find any resource online that would help me figure it out. How can achieve this? I hope my explanations are celar. Thanks in advance.
Edit 2
Sorry for not being clear. Here is a little more in depth more clear explanation. Thanks.
Currently, my view class CreateToJournal(LoginRequiredMixin, CreateView) is rendered at http://127.0.0.1:8000/journals/ and looks like this:
Here you enter the name and press Add. Page reloads and the new journal is added to the list.
I want to achieve the same thing on http://127.0.0.1:8000/. I thought the best way to achieve this is with a templatetag. Below is the image of my current result. I am now able to pull all the journals on the home page, but the only thing that is not showing is the input field for the journal.
Ultimately, I want to have a few forms shoing on the home page in the future. I thought that templatetags is a good and sustainable way to do that.
Edit 3
I am now adding the actual view to the journal_tags.py
from django import template
from to_journals.models import to_journal
from to_journals.views import CreateToJournal
register = template.Library()
#register.inclusion_tag('template_tags/journal_list.html', takes_context=True)
def get_journals(context):
journals = to_journal.objects.filter(journal_user=context['request'].user)
return {'journals': journals,
'form': CreateToJournal(), #new
}
The output is not the actual form, rather the type of the object.

Django w/ Apache, CSRF Verification Failing

I have a bit of an issue with CSRF verification in my Django app. I have two other {% csrf_token %} tags in my app, in two different HTML templates. These work fine, and always have. When attempting to add a third in another new template though, I receive the '403 Forbidden' page. I've copied the style of the two working 'post' commands exactly, but for some reason this one will not work. Any suggestions?
The 'post' form contains a single select/drop-down object, and a submit button. Clicking the button should direct to a view to process the posted data, written again just like the first 2, but it throws the 403 error instead, with the reason for failure being 'CSRF token missing or incorrect'. I'm running Django 1.4.22 also, with User authentication enabled. Here is the not-working view:
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
...Other Views...
#login_required
def Process(request, id):
...
try:
choice = request.POST['choice']
except(KeyError, Item.DoesNotExist):
return render_to_response('app/home.html', context_instance=RequestContext(request))
else:
...Process posted data...
return HttpResponseRedirect(reverse('app.views.display', args=()))
Here is the working view:
#Same includes/imports as earlier, in same file
#login_required
def Submit(request, id, id_2, data):
try:
new_data = request.POST[data.name]
except(KeyError, DataPoint.DoesNotExist):
return render_to_response('app/home.html', context_instance=RequestContext(request))
else:
...Process new data...
return HttpResponseRedirect(reverse('app.views.Data_View', args=()))
And here is the HTML file:
<!DOCTYPE html>
...
<table>
<tr><td>
<form action="/app/page/to/redirect/to/" method="post">
{% csrf_token %}
<select name="choice">
<option name="yes" value="yes" selected>Yes</option>
<option name="no" value="no">No</option>
</select>
</form></td></tr>...</table>

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

Django: issue with a simple form

I'm new at django and I'm having problems with a simple form POST.I have a ModelForm in forms.py and when user enters information in html, views.py taks it and saves it. However, I keep getting an error saying it can't find the view doesn't exist in view.py. Please help me find the error. Thank you!
urls.py
urlpatterns = patterns('',
(r'^mypage/(?P<username>\w+)/$', 'recipeapp.views.my_view'),
forms.py
class NewRecipeForm(forms.ModelForm):
user_info = forms.ForeignKey(User)
title = forms.CharField(min_length=2,max_length=50,required=True,)
post_date = forms.DateField(auto_now=True)
ingredients = forms.TextField(widget=forms.Textarea(),)
picture = forms.ImageField(upload_to='photos/%Y/%m/%d',)
content = forms.TextField(widget=forms.Textarea(),)
views.py
#csrf_protect
from recipeapp.forms import NewRecipeForm
def my_view(request,username):
if request.method == 'POST':
form = NewRecipeForm(request.POST)
if form.is_valid():
form.save()
else:
form = NewRecipeForm()
return render_to_response('postlogin.html',{'username':username},{'form': form}, RequestContext(request))
postlogin.html
<form action="" method="post" id="form">
{% csrf_token %}
<div id="dish-name">
<label><p>Dish name</p></label>
{{form.title}}
</div>
<div id="ingredients">
<label><p>Ingredients</p></label>
{{form.ingredients}}
</div>
<div id="content">
<label><p>Content</p></label>
{{form.content}}
</div>
{{form.picture}}
</form>
Is that really your whole views.py? You have at least three issues:
Firstly, you haven't imported csrf_protect - like any name, a decorator needs to be defined before you can use it.
Secondly, you have to decorate an actual function, not a file. The decorator should go just before the function definition for my_view.
Thirdly, your indentation is broken - the def should not be indented at all.
Given all those, I expect that Python is failing to import your views because of syntax errors.
Also note that you shouldn't really use csrf_protect - you should enable CSRF protection in your middleware (it's on by default) and only use the csrf_exempt decorator, and then only on very very rare occasions.

User Context in Django

I am having problems with user authentication for my django site. I have a log-in screen that seems to work. When the user clicks log-in, I call the django.contrib.auth.login and it seems to work fine. However on subsequent pages have no knowledge that there is a user logged in. Example {% user.is_authenticated %} is false. There are also some menu functions that I want to be available for logged in users such as my-account and logout. Those functions are not available, except on the log-in page. Which is really strange.
This seems to be a user context problem. But I'm not sure how I am supposed to be passing a context around to ensure that my login is stable. Does anyone know at could be going on here? Any advice?
---------part of base.html------------
<!--- The following doesn't register even though I know I'm authenticated -->
{% if user.is_authenticated %}
<div id="menu">
<ul>
<li>My Customers</li>
<li>Customer Actions</li>
<li>My Account</li>
</ul>
</div>
{% endif %}
---------my views.py -----------------
# Should I be doing something to pass the user context here
def customer_list(request):
customer_list = Customer.objects.all().order_by('lastName')[:5]
c = Context({
'customer_list': customer_list,
})
t = loader.get_template(template)
return HttpResponse(t.render(cxt))
If you're using Django 1.3, you can use the render() shortcut, which automatically includes RequestContext for you.
from django.shortcuts import render
def customer_list(request):
customer_list = Customer.objects.all().order_by('lastName')[:5]
return render(request, "path_to/template.html",
{'customer_list': customer_list,})
In this case, you could go one step further, and use the generic ListView:
from django.views.generic import ListView
class CustomerList(Listview):
template_name = 'path_to/template.html'
queryset = Customer.objects.all().order_by('lastName')[:5]
Use a RequestContext.
As Daniel Suggested, use the RequestContext... or better, just use the render_to_response shortcut:
from django.template import RequestContext
from django.shortcuts import render_to_response
def customer_list(request):
customer_list = Customer.objects.all().order_by('lastName')[:5]
return render_to_response(
"path_to/template.html",
{'customer_list':customer_list,},
context_instance=RequestContext(request))