Django Slug Not Working In get_absolute_url - django

Whats wrong with this code? get_absolute_url is blank when rendered in my template, which means It's failing somewhere.
I suspect it's the slug as this is the first time I have tried to use it within Django:
Thanks
Model:
class Entry(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=255, unique=True)
def get_absolute_url(self):
return reverse("EntryDetail", kwargs={"slug": self.slug})
URL:
url(r'^entry/(?P<slug>[^\.]+).html',
blog_views.EntryDetail.as_view(),
name='blog_entry'),
View:
class EntryDetail(DetailView):
context_object_name = 'entry'
template_name = "blog.entry.html"
slug_field = 'slug'
def get_object(self):
return get_object_or_404(Entry, url=self.slug_field)

Based on what #Peter DeGlopper stated in comments: It looks like your trying to get the absolute URL using a Class Based View. Don't use reverse here, instead you should always give your URLs a name, and then refer to that.
For example this is how it should look:
model
#models.permalink
def get_absolute_url(self):
return 'blog_entry', (), {'slug': self.slug}
urls
url(r'^entry/(?P<slug>[^\.]+).html',
blog_views.EntryDetail.as_view(),
name='blog_entry'),

Related

How can I make Django slug and id work together?

I want my URL to contain both id and slug like StackOverflow, but the slug is not working properly. Instead of being like this:
www.example.com/games/155/far-cry-5
the URL is like this:
www.example.com/games/155/<bound%20method%20Game.slug%20of%20<Game:%20Far%20Cry%205>>
My models.py :
class Game(models.Model):
name = models.CharField(max_length=140)
def slug(self):
return slugify(self.name)
def get_absolute_url(self):
return reverse('core:gamedetail', kwargs={'pk': self.id, 'slug': self.slug})
My views.py :
class GameDetail(DetailView):
model = Game
template_name = 'core/game_detail.html'
context_object_name = 'game_detail'
My urls.py :
path('<int:pk>/<slug>', views.GameDetail.as_view(), name='gamedetail')
Call the slug() method to get the value.
return reverse('core:gamedetail', kwargs={'pk': self.id, 'slug': self.slug()})
Or define it as a propery of the class
#property
def slug(self):
...

Django DetailView with few url parameters

Let's say I have next models:
class Category(models.Model):
cat_name = models.CharField(u'name',max_length=50, unique=True)
slug = models.SlugField(u'URL',unique=True)
class News(models.Model):
title = models.CharField(max_length=250)
slug = models.SlugField(unique=True)
category = models.ForeignKey(Category,null=True,on_delete=models.SET_NULL)
And my get_absolute_url function looks like that:
def get_absolute_url(self):
return ('news:detail',(), {'slug':self.slug})
And url looks like /article/<slug>
If I want to have URL like <category.slug><news.slug> ? How can I do that?
You can do that:
# models.py
def get_absolute_url(self):
return ('news:detail', (), {
'category_slug': self.category.slug,
'slug': self.slug,
})
# views.py
class NewsDetail(DetailView):
model = News
slug_field = 'slug'
slug_url_kwarg = 'slug'
def get_queryset(self):
return News.objects.filter(category__slug=self.kwargs['category_slug'])
# urls.py
url(r'(?P<category_slug>[a-z0-9\-]+)/(?P<slug>[a-z0-9\-]+)/$', NewsDetail.as_view(), name='news')
So the idea is to add 2 parameters to your url definition. Last one is usual to query a news row and the first one will used by get_queryset to filter the news by the specified category.
More about parameters in urls in docs - https://docs.djangoproject.com/en/1.9/topics/http/urls/#named-groups

Class meta got invalid attributes

Please help to fix this Meta class value as I gave up after detailed research.
I am getting back error while trying to handle template urls with "get_absolute_url" as it responds with following error.
TypeError: 'class Meta' got invalid attribute(s): sale_price,get_absolute_url.
Below is my code.
class Meta:
db_table = 'products'
ordering = ['-created_at']
def __unicode__(self):
return self.name
#models.permalink
def get_absolute_url(self):
return ('catalog_product', (), {'product_slug': self.slug})
def sale_price(self):
if self.old_price > self.price:
return self.price
else:
return None
Thanks.
You are misunderstanding how models are defined. You add your methods and attributes to the actual Model class and use the Meta class to specify options upon the class:
class MyModel(models.Model):
old_price = ...
price = ...
slug = ...
created_at = ...
...
def __unicode__(self):
return self.name
#models.permalink
def get_absolute_url(self):
return ('catalog_product', (), {'product_slug': self.slug})
def sale_price(self):
if self.old_price > self.price:
return self.price
else:
return None
class Meta:
db_table = 'products'
ordering = ['-created_at']
Have a read of the Model documentation and pay attention to the section on Meta options
EDIT
Also, don't use the permalink decorator as it's no longer recommended:
https://docs.djangoproject.com/en/1.6/ref/models/instances/#the-permalink-decorator
The permalink decorator is no longer recommended. You should use reverse() in the body of your get_absolute_url method instead.

Foreign key lookups - slug URL with Django generic list view

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 %}

How do I write a write a view in django that gets an object_list based on a field?

I have a simple tag model and a simple project model.
In the project model I have a m2m to the tag model.
I want to return all the projects with a tag. I'm almost there.
Right now the view below returns invalid literal for int() with base 10: 'cheap'
So, it has the right slug, and it's making the query, but it's trying to get the list of projects based on the id of the m2m tag.
Any suggestion much appreciated.
My Tag Model:
class Tag(models.Model):
"""
A basic tag model for projects
"""
name = models.CharField(max_length=100, unique=True)
slug = models.CharField(max_length=100)
description = models.TextField(blank=True)
class Meta:
ordering = ('name',)
verbose_name = _('Tag')
verbose_name_plural = _('Tags')
def __unicode__(self):
return self.name
#models.permalink
def get_url_path(self):
return ('TagDetail', (), {'slug': self.slug})
My url:
# tags/<slug>/ The detail view for an archived project
url(regex=r'^tags/(?P<slug>[\w-]+)/$',
view=TagDetail.as_view(),
name='tag_detail',
),
My view I'm trying to figure out:
class TagDetail(ListView):
""" Get all projects for a tag """
template_name = "projects/TagDetail.html"
def get_queryset(self):
tags = get_list_or_404(Project, tags=self.kwargs['slug'], displayed=True)
paginate_by = 10
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(TagDetail, self).dispatch(*args, **kwargs)
Assuming your Project model looks like this
class Project( models.Model ):
tags=models.ManyToManyField( Tag )
match to the tag's slug
def get_queryset( self ):
return get_list_or_404(Project, tags__slug=self.kwargs['slug'], displayed=True)
the only change being tags__slug.