I am creating a Fixture webapp with Django. I have written the class below, which displays a list of first team fixtures. Can I rewrite it as TeamView, then pass the team_id?
class FirstView(generic.ListView):
template_name = 'fixtureapp/team.html'
context_object_name = 'fixtures'
def get_queryset(self):
"""return all first team matches"""
return Match.objects.filter(team_id=1).order_by('date')
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
data['page_title'] = '1st Team Fixtures'
return data
I have the following urls, how would I rewrite these to match?
urlpatterns = [
path('', views.HomeView.as_view(), name='home'),
path('first', views.FirstView.as_view(), name='first'),
path('second', views.SecondView.as_view(), name='second'),
as you can see I have currently created a second class called SecondView this is almost a carbon copy of FirstView, not very DRY
I can give you a brief of how it works, you can apply rest of the logic. Basic idea is to use slug.
In your html you can give the slug name with the url:
In urls.py, get that slug :
path('team/<slug:teamid_slug>/', views.TeamView.as_view(), name='team_by_id'),
Your Views should filter the query based on this slug, if no slug given it will give all the Match record. You can apply some other logic what fits to you.
class TeamView(generic.ListView):
queryset = Match.objects.all().order_by('date')
template_name = 'fixtureapp/team.html'
context_object_name = 'fixtures'
def get_queryset(self):
"""return all team_id team matches"""
return Match.objects.filter(team_id__slug=self.kwargs.get('teamid_slug')).order_by('date')
Also please have a look at this documentation of Dynamic Filtering
Related
I want all djaango urls use slug field without any parameter before or after, by default
just one url can use this metod
Views.py
class ArticleDetail(DetailView):
def get_object(self):
slug = self.kwargs.get('slug')
article = get_object_or_404(Article.objects.published(), slug=slug)
ip_address = self.request.user.ip_address
if ip_address not in article.hits.all():
article.hits.add(ip_address)
return article
class CategoryList(ListView):
paginate_by = 5
template_name = 'blog/category_list.html'
def get_queryset(self):
global category
slug = self.kwargs.get('slug')
category = get_object_or_404(Category.objects.active(), slug=slug)
return category.articles.published()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['category'] = category
return context
urls.py
urlpatterns = [
path('<slug:slug>', ArticleDetail.as_view(), name="detail"),
path('<slug:slug>', CategoryList.as_view(), name="category"),
]
This is my django blog codes,
I don't want write article or category & ... in urls, just slug
mysite .com/article-slug
...
mysite .com/category-slug
It will always trigger the Article view, regardless if there is an Article for that slug. You thus should make the URL patterns non-overlapping such that the other views can be triggered, for example with:
path('article/<slug:slug>/', Article.as_View(), name="articledetail"),
path('category/<slug:slug>/', Category.as_View(), name="category"),
path('product/<slug:slug>/', Product.as_View(), name="productdetail"),
If you want a path that accepts a single slug, you should define a view that looks if there is an Article with that slug, if that is not the case a Category and if that is not the case a Product you thus implement that logic in the view, not in the URL patterns.
#WillemVanOlsem is right, you will have to write a view like this:
from django.http import HttpResponseNotFound
def slug_router(request, slug):
if Category.objects.filter(slug=slug).exists():
return CategoryList.as_view()(request, slug=slug)
elif Article.objects.filter(slug=slug).exists():
return ArticleDetail.as_view()(request, slug=slug)
else:
return HttpResponseNotFound('404 Page not found')
And then
urlpatterns = [
path('<slug:slug>', slug_router, name="slug"),
]
... if I'm not mistaken. This should be the jist of it.
I didn't test this code, just typed it in here, so let me know if it doesn't work, I'll help to fix it.
Note that you'll have a preference if there are Articles with the same slug as some Categories.
So I have a simple model called Pages. Every Page belongs to a certain category, since this is a ForeignKey relation, a Page can only belong to a single category.
Besides categories we also use tags to furthermore filter the different pages.
We use a category view to display all pages belonging to a certain category, easy peasy.
The thing is, we use django-filters to filter the pages by selecting different tags. The list of tags is increasing by the amount of pages. Therefore I would like to only show related tags to the category.
urls.py
path('<slug:category_slug>/', views.PageByCategoryView.as_view(), name='page_by_category'),
views.py
class PageByCategoryView(FilterView):
logger.info("Category view is called")
model = Page
filterset_class = PageByCategoryFilter
strict = False
queryset = Page.published_objects.all()
template_name = 'pages/page_by_category.html'
filters.py
class PageByCategoryFilter(django_filters.FilterSet):
tags = django_filters.ModelMultipleChoiceFilter(
queryset=Tag.objects.filter(page__category_id='2'), <-- actually works!
conjoined=True,
widget=forms.CheckboxSelectMultiple()
)
class Meta:
model = Page
fields = [
'tags__slug'
]
So the tags used in the filter actually get filtered by page__category_id = 2, this is exactly what I want to achieve though I want to do this dynamically. I tried to define the qs like so;
#property
def qs(self):
queryset = super(PageByCategoryFilter, self).qs
current_category = self.request.GET.get('category_slug')
if current_category:
logger.info("Current category is in url")
return queryset.filter(category__slug=current_category)
return queryset
This just doesn't seem to be working, how can i get the current_category from the url?
Alright, what I did below does actually work but it look kinda hackish..
Doe anyone have a better answer on solving this issue?
def category_filter(request):
path = request.path
category_slug = re.sub('\/+', r'', path)
current_category = category_slug
return Tag.objects.filter(page__category__slug=current_category).distinct()
With best regards,
Kevin
Your original view function should be able to take a parameter category_slug where the category slug of the URL is passed in, like in this example from the Django docs (notice how num is declarad as an int in the URL and then passed as an argument to page):
In urls.py
path('blog/page<int:num>/', views.page),
In your view function
def page(request, num=1):
...
If you're using Django REST, you should be able to get the URL parameter your kwargs member attribute, like so:
In urls.py
url('^purchases/(?P<username>.+)/$', PurchaseList.as_view()),
In your view classes:
class PurchaseList(generics.ListAPIView):
serializer_class = PurchaseSerializer
def get_queryset(self):
"""
This view should return a list of all the purchases for
the user as determined by the username portion of the URL.
"""
username = self.kwargs['username'] # this is what you're after
return Purchase.objects.filter(purchaser__username=username)
I am trying to filter a list of my customers stored and return a specific one
when I try (xxx/api/customers/fred) it returns all customers and whatever is entered after the customers/ has no effect on the JSON returned
Views
class CustomerListAPIView(generics.ListAPIView):
queryset = Customer.objects.all()
serializer_class = CustomerSerializer
class CustomerRetrieveAPIView(generics.RetrieveAPIView):
queryset = Customer.objects.all()
serializer_class = CustomerSerializer
lookup_field= "name"
Serializers
class CustomerSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Customer
fields = ['name' , 'address', 'phonenumber']
Urls
url(r'^api/customers/', views.CustomerListAPIView.as_view(), name = "customer_list"),
url(r'^(?P<slug>[\w-]+)/$', views.CustomerRetrieveAPIView.as_view(), name='retrieve'),
ive also tried to override def get_queryset(self, *args, **kwargs): but this method doesn't seem to get triggered when a url is entered
Put more detailed urls before more general to avoid ambiguity, add $ to the end of customer_list URL pattern, add missing prefix to retrieve URL pattern:
url(r'^api/customers/(?P<slug>[\w-]+)/$', views.CustomerRetrieveAPIView.as_view(), name='retrieve'),
url(r'^api/customers/$', views.CustomerListAPIView.as_view(), name = "customer_list"),
all of your requests were handled by first pattern - because both (list and detail) URLs start with api/customers/.
I have a blog app that uses django_taggit. My HomePageView subclasses ArchiveIndexView and works well.
Now I'd like the following link to work: http://mysite.com/tag/yellow and I'd like to use the ArchiveIndexView generic class and pass in a modified queryset that filters on tag_slug. I want to do this because I want to use the same template as the homepage.
My urls.py is
url(r'^$', HomePageView.as_view(paginate_by=5, date_field='pub_date',template_name='homepage.html'),
),
url(r'^tag/(?P<tag_slug>[-\w]+)/$', 'tag_view'), # I know this is wrong
My views.py is
class HomePageView(ArchiveIndexView):
"""Extends the detail view to add Events to the context"""
model = Entry
def get_context_data(self, **kwargs):
context = super(HomePageView, self).get_context_data(**kwargs)
context['events'] = Event.objects.filter(end_time__gte=datetime.datetime.now()
).order_by('start_time')[:5]
context['comments'] = Comment.objects.filter(allow=True).order_by('created').reverse()[:4]
return context
I realize I'm lost here, and would like some help in finding out how to create a new class TagViewPage() that modifies the queryset by filtering on tag_slug.
The key thing is to override the get_queryset method, so that the queryset only includes returns entries with the chosen tag. I have made TagListView inherit from HomePageView, so that it includes the same context data - if that's not important, you could subclass ArchiveIndexView instead.
class TagListView(HomePageView):
"""
Archive view for a given tag
"""
# It probably makes more sense to set date_field here than in the url config
# Ideally, set it in the parent HomePageView class instead of here.
date_field = 'pub_date'
def get_queryset(self):
"""
Only include entries tagged with the selected tag
"""
return Entry.objects.filter(tags__name=self.kwargs['tag_slug'])
def get_context_data(self, **kwargs):
"""
Include the tag in the context
"""
context_data = super(TagListView, self).get_context_data(self, **kwargs)
context_data['tag'] = get_object_or_404(Tag, slug=self.kwargs['tag_slug'])
return context_data
# urls.py
url(r'^tag/(?P<tag_slug>[-\w]+)/$', TagListView.as_view(paginate_by=5, template_name='homepage.html')),
I'm currently learning how to use the class-based views in django 1.3. I'm trying to update an application to use them, but I still don't uderstand very well how they work (and I read the entire class-based views reference like two or three times EVERY day).
To the question, I have an space index page that needs some extra context data, the url parameter is a name (no pk, and that can't be changed, it's the expected behaviour) and the users that don't have that space selected in their profiles can't enter it.
My function-based code (working fine):
def view_space_index(request, space_name):
place = get_object_or_404(Space, url=space_name)
extra_context = {
'entities': Entity.objects.filter(space=place.id),
'documents': Document.objects.filter(space=place.id),
'proposals': Proposal.objects.filter(space=place.id).order_by('-pub_date'),
'publication': Post.objects.filter(post_space=place.id).order_by('-post_pubdate'),
}
for i in request.user.profile.spaces.all():
if i.url == space_name:
return object_detail(request,
queryset = Space.objects.all(),
object_id = place.id,
template_name = 'spaces/space_index.html',
template_object_name = 'get_place',
extra_context = extra_context,
)
return render_to_response('not_allowed.html', {'get_place': place},
context_instance=RequestContext(request))
My class-based view (not working, and no idea how to continue):
class ViewSpaceIndex(DetailView):
# Gets all the objects in a model
queryset = Space.objects.all()
# Get the url parameter intead of matching the PK
slug_field = 'space_name'
# Defines the context name in the template
context_object_name = 'get_place'
# Template to render
template_name = 'spaces/space_index.html'
def get_object(self):
return get_object_or_404(Space, url=slug_field)
# Get extra context data
def get_context_data(self, **kwargs):
context = super(ViewSpaceIndex, self).get_context_data(**kwargs)
place = self.get_object()
context['entities'] = Entity.objects.filter(space=place.id)
context['documents'] = Document.objects.filter(space=place.id)
context['proposals'] = Proposal.objects.filter(space=place.id).order_by('-pub_date')
context['publication'] = Post.objects.filter(post_space=place.id).order_by('-post_pubdate')
return context
urls.py
from e_cidadania.apps.spaces.views import GoToSpace, ViewSpaceIndex
urlpatterns = patterns('',
(r'^(?P<space_name>\w+)/', ViewSpaceIndex.as_view()),
)
What am I missing for the DetailView to work?
The only problem I see in your code is that your url's slug parameter is named 'space_name' instead of 'slug'. The view's slug_field attribute refers to the model field that will be used for slug lookup, not the url capture name. In the url, you must name the parameter 'slug' (or 'pk', when it's used instead).
Also, if you're defining a get_object method, you don't need the attributes queryset, model or slug_field, unless you use them in your get_object or somewhere else.
In the case above, you could either use your get_object as you wrote or define the following, only:
model = Space
slug_field = 'space_name'