Django DetailView + urls with custom parameters - python

Simplified version of forum app in Django. What I want to do is have an url in the form of forum/forum_slug/thread_slug/. I have no idea how to define and pass the custom forum_slug to urlpatterns.
# models.py
class Forum(models.Model):
title = models.CharField(max_length=60)
slug = models.CharField(max_length=60)
# ...
def threads(self):
_threads = Thread.objects.filter(forum=self)
return _threads
class Thread(models.Model):
title = models.CharField(max_length=60)
slug = models.CharField(max_length=60)
forum = models.ForeignKey(Forum)
# ...
def get_absolute_url(self):
return '/%s/%s' % (self.forum.slug, self.slug)
class Post(models.Model):
title = models.CharField('Title', max_length=60)
thread = models.ForeignKey(Thread)
# ...
# ******************************************************
# views.py
# ******************************************************
class ForumDetail(MetadataMixin, DetailView):
model = Forum
context_object_name = 'forum'
template_name = 'forum/forum.html'
name='forum'
# meta...
class ThreadDetail(MetadataMixin, DetailView):
model = Thread
context_object_name = 'thread'
template_name = 'forum/thread.html'
name = 'thread'
# meta...
# ******************************************************
# urls.py
# ******************************************************
urlpatterns = patterns('',
url(r'^$',
'forum.views.index',
name='index'
),
url(r'^(?P<slug>[a-zA-Z0-9-]+)/?$',
ForumDetail.as_view()),
# here it comes
url(r'^(?P<forum_slug>[a-zA-Z0-9-]+/?P<slug>[a-zA-Z0-9-]+)/?$',
ThreadDetail.as_view()),
)

I assume that you want URL pattern for slugs. Below is the example you can try.
# URL example: /forum/this-is-a-forum-1/this-is-a-thread-1/
url(r'^forum/(?P<forum_slug>[\w-]+)/(?P<thread_slug>[\w-]+)$', ThreadDetail.as_view()),
Hope this helps.

#rayy: Thanks. No, this is not what I was looking for -- I simply do not know how to define forum_slug in it. That's what I was asking for. :-) Well, I figured out kinda more verbose solution but, frankly, I do not like it:
# models.py
from django.core.urlresolvers import reverse
class Thread(models.Model):
#... like before
def get_absolute_url(self):
return reverse('thread_url', (), {'forum_slug': self.forum.slug, 'slug': self.slug})
# urls.py
urlpatterns = patterns('',
# ...
url(r'^(?P<forum_slug>[\w-]+)/(?P<slug>[\w-]+)/$', ThreadDetail.as_view(), name='thread_url'),)
# index.html / forum.html (in a loop)
{{thread.title}}

Related

Getting an empty list when using filter - Django REST

I have my API in Django REST Framework:
Here is my models.py:
class myModel(models.Model):
user_email = models.CharField(max_length= 200, null= False)
Here is my views.py:
class GetItemsByEmail(generics.ListAPIView):
def get_queryset(self):
email_items = self.request.query_params.get("user_email")
if(email_items is not None):
itemsReturned = myModel.objects.all().filter(user_email = email_items)
return Response(data= itemsReturned)
Here is my urls.py:
url_patterns = [
path('users/account=<str:id>/shipments', GetItemsByEmail.as_view()),
]
My Question:
I am getting an empty list, getting nothing from making an API call to the above endpoint.
I want to get all the items in the database associated with a particular email?
In your views.py:
from rest_framework import generics
from .models import * # noqa
from .serializers import *
class GetItemsByEmail(generics.ListAPIView):
queryset = MyModel.objects.all() # noqa
serializer_class = MyModelSerializer
def get_queryset(self):
if self.kwargs.get('user_email_pk'):
return self.queryset.filter(id=self.kwargs.get('user_email_pk'))
return self.queryset.all()
In models.py I had to create another model to have the result that you want (get all database by a specific user_email!):
from django.db import models
class MyModel(models.Model):
user_email = models.CharField(max_length=200, null=False)
def __str__(self):
return self.user_email
class ServicesModel(models.Model):
# Just an example to emulate the expected result, do not worry about it!
name = models.CharField('Name', max_length=200)
user_email_service = models.ForeignKey(MyModel, related_name='services', on_delete=models.CASCADE) # Just an example to emulate the expected result, do not worry about it!
def __str__(self):
return self.name
In serializers.py:
from rest_framework import serializers
from .models import MyModel, ServicesModel
class ServiceModelSerializer(serializers.ModelSerializer):
class Meta:
model = ServicesModel
fields = (
'name',
)
class MyModelSerializer(serializers.ModelSerializer):
services = ServiceModelSerializer(many=True, read_only=True)
class Meta:
model = MyModel
fields = (
'id',
'user_email',
'services',
)
In urls.py:
from django.urls import path
from core.views import GetItemsByEmail
urlpatterns = [
path('users/', GetItemsByEmail.as_view(), name='users'), # Ignore!
path('users/account=<str:user_email_pk>/shipments/', GetItemsByEmail.as_view(), name='user_email'),
]
In the test that I made localy I created two 'user_email' and each one have diferent 'services' so you are able to get all the data by the id, images of the result:
You obviously only need to get attention in 'views.py' and 'serializers.py', I just created all this code to get in the expected result!
If you want your query to be case insensitive, you can try the following:
myModel.objects.filter(user_email__iexact=email_items)

How to display only specific data from the entire list storage on python django server (rest framework)

I have to display (as in topic title) only specific data from the list which is storage on server (PYTHON/DJANGO/REST_FRAMEWORK).
F.e. I want to choose data which has planted on the server with 'id=1', but I always get back all items. Can you explain how to correct this?
'urls' file (project level) :
# URL routes - known as endpoints API
urlpatterns = [
path('admin/', admin.site.urls),
path('devices/', include('efota.api.urls')),
]
'urls' file (subordinate folder) :
urlpatterns = [
url('', views.DeviceList.as_view()),
url('<int:pk>/', views.DeviceDetail.as_view()),
]
urlpatterns = format_suffix_patterns(urlpatterns)
'views' file :
class DeviceList(generics.ListAPIView):
queryset = Device.objects.all()
serializer_class = DeviceSerializer
class DeviceDetail(generics.RetrieveAPIView):
queryset = Device.objects.all()
serializer_class = DeviceSerializer
'serializers' file:
class DeviceSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
# the 'fields' controls which database attributes are available
class Meta:
model = Device
fields = (
'id',
'user',
'id_token',
'current_firmware',
'carrier_code',
'model_name',
'owner',
)
read_only_fields = ['id']
def get_url(self, obj):
request = self.context.get("request")
return obj.get_api_url(request=request)
'models' file:
class Device(models.Model):
created = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey('auth.User', related_name='owner',
on_delete=models.CASCADE)
user = models.CharField(max_length=50, verbose_name='user')
id_token = models.CharField(max_length=1000,
verbose_name='id_token')
current_firmware = models.CharField(max_length=41,
verbose_name='current_firmware')
carrier_code = models.CharField(max_length=5,
verbose_name='carrier_code')
model_name = models.CharField(max_length=10,
verbose_name='model_name')
class Meta:
ordering = ('created', )
def __str__(self):
return self.model_name
'admin' file:
from django.contrib import admin
from .models import Device
# Register your models here.
admin.site.register(Device)
You are confusing old-style URL and new-style path syntax in your urls.py. The url() function takes a regex, and r'' matches every URL, while <int:pk>/ would only match that literal string. Use path instead.
urlpatterns = [
path('', views.DeviceList.as_view()),
path('<int:pk>/', views.DeviceDetail.as_view()),
]
To filter result returned by ListAPIView you can modify its get_queryset method as follows.
class DeviceDetail(generics.ListAPIView):
serializer_class = DeviceSerializer
def get_queryset(self):
return Device.objects.filter(id=self.kwargs['pk'])

Django Rest Framework Filtering Not working

Using Django 1.11 & djangorestframework==3.7.7, I want to return Videos where is_thumbnail=True on a GET call. However, all of my testing with filters have been returning all Videos objects.
Model:
class Videos(models.Model):
"""This class represents the Videos model."""
uid = models.UUIDField(
primary_key=True, default=uuid.uuid4, editable=False)
is_thumbnail = models.BooleanField(default=False)
file_name = models.CharField(unique=True, max_length=64)
file_path = models.CharField(unique=True, max_length=256)
file_created_time = models.DateTimeField()
owner = models.ForeignKey('auth.User',
related_name='videos',
on_delete=models.CASCADE)
created_time = models.DateTimeField(auto_now_add=True)
def __str__(self):
"""Return a human readable representation of the model instance."""
return "{}".format(self.file_name)
view:
class DetailsView(generics.RetrieveUpdateDestroyAPIView):
"""This class handles the http GET, PUT and DELETE requests."""
serializer_class = VideosSerializer
permission_classes = (permissions.IsAuthenticated, IsOwner)
lookup_field = 'uid'
def get_queryset(self):
return Videos.objects.filter(is_thumbnail=True)
If I put a print statement inside of the get_queryset function, I don't see that statement in the log. So it seems like the function isn't being called.
api/urls.py
urlpatterns = {
url(r'^auth/', include('rest_framework.urls',
namespace='rest_framework')),
url(r'^api/videos/$', CreateView.as_view(), name="create"),
url(r'^api/videos/(?P<uid>[0-9a-f-]+)/$',
DetailsView.as_view(), name="details"),
url(r'^get-token/', obtain_auth_token),
}
securedash_project/urls.py
urlpatterns = format_suffix_patterns(urlpatterns)
urlpatterns = [
url(r'', include('secureDash.dash.urls')),
url(r'^dash/', include('secureDash.dash.urls')),
url(r'^admin/', admin.site.urls),
url(r'^', include('secureDash.api.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Ok, you want to replace the value of the "get_queryset" method of the generic view "generics.RetrieveUpdateDestroyAPIView", which accesses the objects using the "uid" field setting like lookup_field to make the modification later, so I recommend that when you overwrite it the "get_queryset" method replaces them with the following:
def get_queryset(self):
return self.get_queryset().filter(is_thumbnail=True)
The issue that I was having was that I had a CreateView class that implemented generics.ListCreateAPIView. This view has r/w endpoints so my GET calls were never getting to my DetailsView. I need to adjust my views, but for now this works to only show is_thumbnail=True Videos.
class CreateView(generics.ListCreateAPIView):
"""This class defines the (GET & POST) behavior of the rest api."""
serializer_class = VideosSerializer
permission_classes = (permissions.IsAuthenticated, )
def perform_create(self, serializer):
"""Save the post data when creating a new Videos object."""
serializer.save(owner=self.request.user)
def get_queryset(self):
queryset = Videos.objects.all()
return queryset.filter(is_thumbnail=True)
class DetailsView(generics.RetrieveUpdateDestroyAPIView):
"""This class handles the http GET, PUT and DELETE requests."""
queryset = Videos.objects.all()
serializer_class = VideosSerializer
permission_classes = (permissions.IsAuthenticated, IsOwner)
lookup_field = 'uid'

django-autocomplete-light error = 'list' object has no attribute 'queryset'

i am new on django and i need your help, trying since many days to understand django-autocomplete-light, after setup my test,
http://192.168.0.108:8000/country-autocomplete/ work, data is showed like explaned here http://django-autocomplete-light.readthedocs.io/en/master/tutorial.html#overview
But after following next step, i am getting error:
AttributeError at /auto
'list' object has no attribute 'queryset'
Request Method: GET
Request URL: http://192.168.0.108:8000/auto
Django Version: 1.10.3
Exception Type: AttributeError
Exception Value:'list' object has no attribute 'queryset'
Exception Location: /home/alcall/ENV/lib/python3.4/site-packages/dal/widgets.py in filter_choices_to_render, line 161
Below my setup:
urls:
from dal import autocomplete
from django.conf.urls import url
from django.contrib import admin
from rates.view.index import *
from rates.view.index import UpdateView
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(
r'^country-autocomplete/$',
CountryAutocomplete.as_view(),
name='country-autocomplete',
),
url(r'^auto$',
UpdateView.as_view(),
name='select',
),
]
models.py
from __future__ import unicode_literals
from django.db import models
class Country(models.Model):
enabled = models.IntegerField()
code3l = models.CharField(unique=True, max_length=3)
code2l = models.CharField(unique=True, max_length=2)
name = models.CharField(unique=True, max_length=64)
name_official = models.CharField(max_length=128, blank=True, null=True)
prix = models.FloatField()
flag_32 = models.CharField(max_length=255, blank=True, null=True)
flag_128 = models.CharField(max_length=255, blank=True, null=True)
latitude = models.DecimalField(max_digits=10, decimal_places=8, blank=True,$
longitude = models.DecimalField(max_digits=11, decimal_places=8, blank=True$
zoom = models.IntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'country'
def __str__(self):
return self.name
view (include form too)
from dal import autocomplete
from django.shortcuts import render
from rates.models import Country
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.http import HttpResponse
from django import forms
from django.core.urlresolvers import reverse_lazy
from django.views import generic
class CountryAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self):
# Don't forget to filter out results depending on the visitor !
# if not self.request.user.is_authenticated():
# return Country.objects.none()
qs = Country.objects.all()
if self.q:
qs = qs.filter(name__istartswith=self.q)
return qs
class Form_country(forms.ModelForm):
class Meta:
model = Country
fields = ('name', 'code2l')
widgets = {
'name': autocomplete.ModelSelect2Multiple(
'country-autocomplete'
)
}
class UpdateView(generic.UpdateView):
model = Country
form_class = Form_country
template_name = 'fr/public/monformulaire.html'
success_url = reverse_lazy('select')
def get_object(self):
return Country.objects.first()
I had the same issue. The problem here is with the widget. Tried to fix it for very long. The only way in worked for me was changing form's widget.
If it doesn't matter that much you can use autocomplete.ListSelect2 instead, it worked for me.
So try this:
class Form_country(forms.ModelForm):
class Meta:
model = Country
fields = ('name', 'code2l')
widgets = {
'name': autocomplete.ListSelect2(
'country-autocomplete'
)
}
Actually you can just try any other autocomplete widget and see weather it works
I you create the widget in __init__(), then this work-around of issue #790 helps:
form.fields['name'].widget.choices = form.fields['name'].choices
Here is my implementation, where I used it to suggest similar names that are already present in a model
IMPORTANT: After you must have done all these, don't forget to run python manage.py collectstatic.
Also note that you wish to include a placeholder in your form field you have to do it with data-placeholder in the widget autocomplete widget.
When you run it, you'll see this message
Found another file with the destination path
'admin/js/jquery.init.js'. It will be ignored since only the first
encountered file is collected. If this is not what you want, make sure
every static file has a unique path.
This is the reason the documentation states here that you must place dal and dal_select2 before django.contrib.admin in your INSTALLED_APPS
models.py
from django.db import models
class Patient(models.Model):
name = models.CharField(max_length=100)
stable = models.BooleanField(default=False)
views.py
from django.db.models import Q
from dal import autocomplete
class NewName(autocomplete.Select2QuerySetView):
"""Suggest similar names in form"""
def get_queryset(self):
qs = People.objects.filter(stable=True)
if self.q:
query = Q(name__contains=self.q.title()) | Q(name__contains=self.q.lower()) | Q(name__contains=self.q.upper())
qs = qs.filter(query)
return qs
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('new-name/', views.NewName.as_view(), name='new_name_autocomplete'),
]
forms.py
class PatientForm(forms.ModelForm):
class Meta:
model = Patient
fields = ["stable", "name"]
widgets = {
"name" : autocomplete.ModelSelect2(url=reverse_lazy('new_name_autocomplete'), attrs={'class' : 'form-control', 'data-placeholder' : "Name"}),
I had to modify dal/widgets.py and comment out the queryset filtering as shown below. It seems to be a bug or something. The issue has been raised here. But if you're using
autocomplete.ListSelect2() as your widget, then there's no need for that.
class QuerySetSelectMixin(WidgetMixin):
"""QuerySet support for choices."""
def filter_choices_to_render(self, selected_choices):
"""Filter out un-selected choices if choices is a QuerySet."""
# self.choices.queryset = self.choices.queryset.filter(
# pk__in=[c for c in selected_choices if c]
# )

Need help creating a model in a view

models.py
class Match(models.Model):
match_name = models.CharField(max_length=100)
player = models.CharField(max_length=100, choices=match_game, default=2)
time_start = models.DateTimeField(blank=True, default=None, null=True)
match_finished = models.BooleanField(default=False)
def get_absolute_url(self):
return reverse('match:details', kwargs={'pk': self.pk})
def __str__(self):
return self.match_name
class PlayerSignup(models.Model):
current_player = models.ForeignKey(User)
signup = models.ForeignKey(Match)
urls.py
url(r'^create/add/$', views.MatchCreate.as_view(), name='match-add'),
url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(template_name = 'match/bracket_detail.html'), name='details'),
url(r'^search/$', views.IndexView.as_view(template_name = 'match/bracket.html'), name='search'),
url(r'(?P<pk>[0-9]+)/$', views.PlayerSign, name='join')
views.py
def PlayerSign(request):
model = PlayerSignup.objects.all()
match = Match.objects.get(pk=Match.pk)
joinmatch = PlayerSignup(current_player=request.user, signup=match)
joinmatch.save()
return render(request, 'match/bracket_detail.html', {'model': model })
template
Join Match
when a person clicks on the 'Join Match' link i would like it to create a PlayerSignup model and link it to the current match that they are on.
when i click the Join Match link nothing happens, no new model, no error
First, try to edit this statement
def PlayerSign(request):
...
match = Match.objects.get(pk=Match.pk)
to
def PlayerSign(request, pk):
...
match = Match.objects.get(pk=pk)
Because there is an request parameter in URL named pk, you should pass this parameter to the query method.
Second, review your url define
url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(template_name = 'match/bracket_detail.html'), name='details'),
url(r'(?P<pk>[0-9]+)/$', views.PlayerSign, name='join')
Change to
url(r'^match_detail/(?P<pk>[0-9]+)/$', views.DetailView.as_view(template_name = 'match/bracket_detail.html'), name='details'),
url(r'^player_detail/(?P<pk>[0-9]+)/$', views.PlayerSign, name='join')

Categories