I have a model 'Playlist' with an attribute 'private' that can be True or False (and therefore private or public). I want to use the #login_required decorator only if 'private = False', but can't figure out how to achieve this result. Here is my models.py file:
class Playlist(models.Model):
"""Allow a user to create a customized list of songs."""
name = models.CharField(max_length=100)
image = models.ImageField(upload_to='playlists/%Y/%m/%d', blank=True, null=True)
songs = models.ManyToManyField('Song')
description = models.TextField(blank=True, null=True, max_length=1000)
date_added = models.DateTimeField(auto_now_add=True)
private = models.BooleanField()
def __str__(self):
"""String for representing the model object."""
return self.name
def get_absolute_url(self):
"""Returns the url to access a detail record for this song."""
return reverse('playlist-detail', args=[str(self.id)])
And my views.py file:
def playlist(request, playlist_id):
"""Show a single playlist and associated data."""
playlist = Playlist.objects.get(id=playlist_id)
songs = playlist.songs.all()
for song in songs:
if song.url:
song.video_id = song.url.replace("https://www.youtube.com/watch?v=", "")
context = {'playlist': playlist, "playlist_songs": songs}
return render(request, 'great_songs_app/playlist.html', context)
I stumbled across a similar thread but there was no answer to the problem:Conditionally apply login_required decorator in Django
I imagine code looking something like what the OP posted, with the view function being preceded by:
if playlist.private == True:
#login_required
...
But obviously that won't work. Any ideas?
Rather than trying to apply #login_required, you could simply let the view undecorated and do something like the following, checking whether the user is authenticated:
from django.shortcuts import redirect
from django.conf import settings
def playlist(request, playlist_id):
"""Show a single playlist and associated data if user is authenticated."""
playlist = Playlist.objects.get(id=playlist_id)
if not playlist.private or (playlist.private and request.user.is_authenticated):
songs = playlist.songs.all()
for song in songs:
if song.url:
song.video_id = song.url.replace("https://www.youtube.com/watch?v=", "")
context = {'playlist': playlist, "playlist_songs": songs}
return render(request, 'great_songs_app/playlist.html', context)
else:
redirect(settings.LOGIN_URL)
Related
I am a newbee in django. In my website, when the user logs in, he is redirected to a page with a dropdown menu where he has to choose a contract on which he wants to work. After selecting the contract he is redirected to the specific homepage define with a ID in the url. The ID value comes from the ID of the contract in the database.
What
How can I check by a function or a decorator that the user has the rights to be on this contract. Because any user could right the numbers in the url and access to a page where he should not have access. By example, an user has the right to the contracts 109 and 144, so he can go on the urls "home/109" and "home/144", but if is change the value in the url to another one, he should not have access
Here is my view of the dropdown menu :
#authenticated_user
def selectcontrat(request) :
context = initialize_context(request)
form_client = SelectClient(request.POST, user=request.user)
if form_client.is_valid():
id_contrat = request.POST.get("ID_Customer")
return redirect(reverse('home', args=(id_contrat,)))
context['form_client'] = form_client
return render(request, 'base/selectcontrat.html', context)
Here the views of the home page :
#authenticated_user
def home(request, id_contrat=None):
context = initialize_context(request)
return render(request, 'home.html', context)
The urls :
from django.urls import path
from . import views
urlpatterns = [
path('home/<int:id_contrat>/', views.home, name="home"),
path('', views.loginAD, name="login"),
path('signin', views.sign_in, name='signin'),
path('callback', views.callback, name='callback'),
path('selectcontrat', views.selectcontrat, name='selectcontrat')
The model is the relation between a user and a group. which group the user has righs.
class Groups(models.Model):
ID = models.AutoField(primary_key=True) # Field name made lowercase.
IDCustomer = models.IntegerField(blank=True, null=True) # Field name made lowercase.
GroupName = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
CreatedOn = models.DateTimeField(blank=True, null=True) # Field name made lowercase.
class AADJNTGroup(models.Model):
ID = models.AutoField(primary_key=True)
ID_User = models.ForeignKey(User, on_delete=models.CASCADE)
ID_Group = models.ForeignKey(Groups, on_delete=models.CASCADE)
CreatedOn = models.DateTimeField(auto_now_add=True)
CreatedBy = models.CharField(max_length=255)
To do that, I tried to do a decorator, but I do not know how to get the id_contrac value that is redirected after the form. How can I get this value in a decorator, like that then I could check the rights on the database.
The decorator not working :
def check_pk(view_func) :
def wrapper_func(request, *args, **kwargs):
list_user_rights = AADJNTGroup.objects.filter(ID_group_id=args[0]).values_list('ID_User_id', flat=True)
print(list_user_rights)
return wrapper_func
Anyone has an idea ?
If using class based views you can use UserPassesTestMixin
from django.contrib.auth.mixins import UserPassesTestMixin
class MyView(UserPassesTestMixin, View):
def test_func(self):
return self.request.user.email.endswith('#example.com')
if using function views you can use the user_passes_test decorator.
from django.contrib.auth.decorators import user_passes_test
def email_check(user):
return user.email.endswith('#example.com')
#user_passes_test(email_check)
def my_view(request):
...
I did a decorator, that requests the different database to check the rights
Here is the decorator
def check_user_rights():
def wrapper_func(view_func):
#wraps(view_func)
def wrapper(request, *args, **kwargs):
# THE ID THAT I CAN COLLECT
ID_contrat = kwargs["id_contrat"]
User_ID = request.user.id
# THE SQL REQUEST TO GET THE VALUE
list_user_rights = AADJNTGroup.objects.filter(ID_User_id=User_ID).values_list('ID_Group_id', flat=True)
ID_contrat_list = list(list_user_rights)
Contrat_right = Groups.objects.all().filter(ID__in=ID_contrat_list).values_list('IDCustomer', flat=True)
# Compare the rights
if ID_contrat in Contrat_right :
return view_func(request, *args, **kwargs)
else :
return HttpResponse("<h1> page not found</H1>")
return wrapper
return wrapper_func
I have 2 models but I want to show the name of the artist in my output
class Musician(models.Model):
name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
name = models.CharField(max_length=100)
artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
num_stars = models.IntegerField()
I want to show musician name by HttpResponse function
class Musician_list(Musician, Album):
def get(self, request):
query = Musician.objects.all().values_list("name").order_by("name")
return HttpResponse(query)
but this code doesn't show anything - please help me.
from django.http import JsonResponse
def get(self, request):
names = Musician.objects.values_list("name",flat=True)
return JsonResponse(names, safe=False)
You can read more about JsonResponse from the doc here
Your Usecase
I'm confused about how to pull in related information from two different tables.
If I go to localhost:8000/user/username, it should display the users profile and user reviews below. because the username is being passed through the URL into the views function. Is that correct?
Also, is it required that I use foreign key to accomplish this? I've read the docs and I'm still not completely sure how a foreign key would help me accomplish my goal here.
Models
from django.db import models
class User(models.Model):
name = models.CharField(max_length=20)
reviewer = models.CharField(max_length=20)
password = models.TextField()
zipcode = models.Charfield(max_length=100)
email = models.EmailField()
def __str__(self): # __unicode__ on Python 2
return self.name
class UserReview(models.Model):
name = models.ForeignKey(User)
author = models.CharField(max_length=50)
pub_date = models.DateField()
stars = models.IntegerField(max_length=5)
comment = models.CharField(max_length=100)
def __str__(self): # __unicode__ on Python 2
return self.name
Views
from django.shortcuts import render
def index(request):
profile_info = User.objects.filter(name=username)
context = {‘profile_info’: profile_info}
latest_reviews = UserReview.objects.filter(name=username).order_by('-pub_date')[:5]
context = {‘profile_info’: profile_info, 'latest_reviews': latest_reviews}
return render(request, 'randomtemplate.html', context)
URLS
urlpatterns = patterns('',
url(r'^user/(?P<username>\w+)/', 'index'),
)
There's a couple things you need to do. The first is that you need to pass the parameter into the view function, and then you'll need to display the ratings in the template.
#view
def index(request, username):
profile_info = User.objects.filter(name=username)
latest_reviews = UserReview.objects.filter(name=username).order_by('-pub_date')[:5]
context = {‘profile_info’: profile_info, 'latest_reviews': latest_reviews}
return render(request, 'randomtemplate.html', context)
# randomtemplate.html
{{ username }}
{{ latest_reviews }}
I have been searching here and reading the documentation and experimenting in python, but I can't find a solution to my particular mess. I did the Django tutorial, but I'm still confused as to how to pass stuff thru the URL in django when starting to use foreign keys, I'm sure it's pretty simple. I'm a new django user and this is my first post. I have the models Playlist, and PlaylistEntry with mixed relationships to user and videos (not posted). I'm trying to show a detail view that uses a slug of a playlist title, to pull out entries in the playlist. Eg. In python, I can do
entries = PlaylistEntry.objects.filter(playlist__slug='django')
which returns all my entries in the playlist 'Django' correctly.
Here are my models...
class Playlist(models.Model):
class Meta:
verbose_name_plural = 'playliztz'
title = models.CharField(blank=True,
help_text=u'Title of playlist',
max_length=64,
)
user = models.ForeignKey('userprofile.UserProfile',
blank=False,
help_text=u'owns this playlist',
null=False, )
slug = models.SlugField(u'slug',
max_length=160,
blank=True,
editable=False
)
created = models.DateTimeField(editable=False)
modified = models.DateTimeField(editable=False)
def __unicode__(self):
return self.title
def get_absolute_url(self):
return reverse('playlist-detail', kwargs={'pk': self.pk})
def save(self):
self.slug = slugify(self.title)
if not self.id:
self.created = datetime.datetime.today()
self.modified = datetime.datetime.today()
super(Playlist,self).save()
class PlaylistEntry(models.Model):
class Meta:
verbose_name_plural = "playlist entries"
video = models.ForeignKey('video.Video',
blank=True,
default=None,
help_text=u'the video title',
null=True, )
playlist = models.ForeignKey('Playlist',
blank=True,
default=None,
help_text=u'Belongs to this playlist',
null=True,)
def __unicode__(self):
return self.video.video_title
My URLS looks like this...
url(r'^playlist/$', PlaylistList.as_view(), name='user_playlists'),
url(r'^playlist/(?P<slug>[0-9A-Za-z-_.//]+)/$', PlaylistDetail.as_view(), name='playlist_entries'),
And my Views.py looks like this...
class PlaylistList(LoggedInMixin, ListView): # shows a list of playlists
template_name = 'userprofile/playlist_list.html'
model = Playlist
context_object_name = 'playlist_list'
def get_queryset(self):
"""Return currently users playlists."""
return Playlist.objects.filter(user__user=self.request.user)
def get_context_data(self, **kwargs):
context = super(PlaylistList, self).get_context_data(**kwargs)
if not self.get_queryset():
context['error'] = "You don't have any playlists yet."
return context
else:
return context
class PlaylistDetail(LoggedInMixin, DetailView):
model = PlaylistEntry
template_name = 'userprofile/playlist_detail.html'
def get_queryset(self):
self.current_playlist = get_object_or_404(Playlist, slug=self.kwargs['slug'])
# CHECK - Prints out correct entries for playlist in slugfield (current_playlist)
self.entries = PlaylistEntry.objects.filter(playlist__title=self.current_playlist.title)
print self.entries
# Should expect to return the same queryset?
return PlaylistEntry.objects.filter(playlist__title=self.current_playlist.title)
def get_context_data(self, **kwargs):
context = super(PlaylistEntry, self).get_context_data(**kwargs)
context['entries'] = PlaylistEntry.objects.all()
return context
self.entries prints the correct entries for this playlist in the Check bit.
In my playlist template I am using a link sending the playlist.slug - the url looks correct like this /user/playlist/this-particular-playlist-slug.
the error is...
Cannot resolve keyword u'slug' into field. Choices are: id, playlist, video
You've made things much more complicated than they need to be.
The model for your detail view should still be Playlist, not PlaylistEntry. The reason you're getting that error is that the slug is on the Playlist model, but you've told the view to filter on PlaylistEntry.
What you actually want to to is to pass the single Playlist identified by the slug into the template. From there, you can easily iterate through the detail objects associated with that playlist via the reverse relation.
So, change that model setting, and drop both get_context_data and get_queryset from the detail view: you don't need them. Then in the template you can simply do:
{% for entry in playlist.playlistentry_set.all %}
I create a modelForm with instance to existing model (Book). I am not able to update the Books record. Adding a new record is fine but when I attempt to update, it appears to be unable to find the publisher (which is a foreign key). Error is "No Publisher matches the given query."
models.py
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
def __unicode__(self):
return self.name
class Meta:
ordering = ["name"]
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField(blank=True, verbose_name='e-mail')
objects = models.Manager()
sel_objects=AuthorManager()
def __unicode__(self):
return self.first_name+' '+ self.last_name
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField(blank=True, null=True)
num_pages = models.IntegerField(blank=True, null=True)
class BookForm(ModelForm):
class Meta:
model = Book
views.py
def authorcontactupd(request,id):
if request.method == 'POST':
a=Author.objects.get(pk=int(id))
form = AuthorForm(request.POST, instance=a)
if form.is_valid():
form.save()
return HttpResponseRedirect('/contact/created')
else:
a=Author.objects.get(pk=int(id))
form = AuthorForm(instance=a)
return render_to_response('author_form.html', {'form': form})
error msg
Page not found (404)
Request Method: POST
Request URL: http://127.0.0.1:8000/books/bookupd/
No Publisher matches the given query.
You're seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.
urls.py
from django.conf.urls.defaults import *
from django.views.generic.simple import direct_to_template
from mysite10.books.views import about_pages, books_by_publisher, authorcontact,bookcontact, booklisting, authorcontactupd
from django.views.generic import list_detail
from mysite10.books.models import Publisher, Book
from django.contrib import admin
admin.autodiscover()
def get_books():
return Book.objects.all()
publisher_info = {
'queryset': Publisher.objects.all(),
'template_name':'books/publisher_publisher_list_page.html',
'template_object_name': 'publisher',
'extra_context': {'book_list': Book.objects.all},
}
book_info = {
'queryset': Book.objects.order_by('-publication_date'),
'template_name':'books/publisher_publisher_list_page.html',
'template_object_name': 'book',
'extra_context': {'publisher_list': Publisher.objects.all},
}
oreilly_books = {
'queryset': Book.objects.filter(publisher__name="O'Reilly"),
'template_name':'books/publisher_publisher_list_page.html',
'template_object_name': 'book',
'extra_context': {'publisher_list': Publisher.objects.all},
}
urlpatterns = patterns('',
(r'^admin/(.*)', admin.site.root),
(r'^polls/', include('mysite10.polls.urls')),
(r'^search-form/$', 'mysite10.views.search_form'),
(r'^search/$', 'mysite10.views.search'),
(r'^contact/$', 'mysite10.contact.views.contact'),
(r'^contact/thanks2/(\d+)$', 'mysite10.contact.views.thanks2'),
(r'^contact/thanks/$', 'mysite10.contact.views.thanks'),
(r'^publishers/$', list_detail.object_list, publisher_info),
(r'^books/$', list_detail.object_list, book_info),
(r'^books/oreilly/$', list_detail.object_list, oreilly_books),
(r'^books/(\w+)/$', books_by_publisher),
(r'^author/$', authorcontact),
(r'^authorupd/(\d+)/$', authorcontactupd),
(r'^contact/created/$', 'mysite10.books.views.created'),
(r'^bookform/$', bookcontact),
(r'^contact/bookscreated/$', 'mysite10.books.views.books_created'),
(r'^booklist/$', 'mysite10.books.views.booklisting'),
(r'^books/bookupd/(\d+)$', 'mysite10.books.views.book_upd'),
)
-------------------------------------------------
I finally got it working with below codes.
error in urls.py because of missing forward slash before $.
Amended to (r'^books/bookupd/(\d+)/$'
views.py
def book_upd(request,id):
if request.method == 'POST':
a=Book.objects.get(pk=int(id))
form = BookForm(request.POST, instance=a)
if form.is_valid():
form.save()
return HttpResponseRedirect('/contact/bookscreated')
else:
a=Book.objects.get(pk=int(id))
form = BookForm(instance=a)
return render_to_response('book_form.html', {'form': form})
urls.py
(r'^books/bookupd/(\d+)/$', 'mysite10.books.views.book_upd'),
There's some missing information like what you have in your urls.py. Can you post it as well? Did you check in the database that the record was actually not updated? (the error might be a result of processing the redirect)
Your edit is not sufficient:
- did you check the databse to see if the record is updated?
- Please paste the entire urls.py as for example it is interesting to see what /contact/created is mapped to in case it did succeed, or whether you have some publisher.get() methods in it
In addition the traceback can also provide lots of useful information as to the source of the problem.
did you check if the object is updated in the database even though you get the error?
Can you try removing the "oreilly_books" section (or at least the queryset part) and try doing the same without it?