Django: Urls Optional Query Parameters - python

Urls.py:
app_name = 'main'
urlpatterns = [
path('',include(router.urls)),
path('player_id=<str:player>%season_id=<str:season>',views.MatchesList.as_view())
]
Views.py
class MatchesList(generics.ListAPIView):
serializer_class = MatchesSerializer
permissions = (IsAuthenticated)
def get_queryset(self):
player = self.kwargs['player']
season = self.kwargs['season']
if season is None:
queryset = Matches.objects.filter(player=player).all()
else:
queryset = Matches.objects.filter(player=player,season=season).all()
return queryset
Is there any way to request without the parameter 'season'? Something like that:
app_name = 'main'
urlpatterns = [
path('',include(router.urls)),
path('player_id=<str:player>',views.MatchesList.as_view())
]

Sure. In DRF you can/should use filtering for this.
In urls.py you'll have something like this:
path('matches/<str:player_id>/', views.MatchesList.as_view())
And your URL will look like:
https://yourhost.com/matches/42/?season=spring
For season you'll have to implement a filter (there is a bunch of ways to do it). Filters are optional — if you'll not pass the ?season=something part of the URL, it just will not be applied.

Related

Django detailview filter by other fields like isbn

If I have another field like ISBN in book so how do I filter with this field in from django.views.generic import DetailField
here is my book/urls.py file code
urlpatterns = [
path('',BookListView.as_view(), name="book_list"),
path('<isbn>/',BookDetailView.as_view(), name="book_detail")
]
book/views.py
class BookDetailView(DetailView):
template_name = "book/detail.html"
def get_queryset(self,*args, **kwargs):
print(self.kwargs['isbn'])
return BookModel.objects.filter(isbn=self.kwargs['isbn'])
and the Error is
Generic detail view BookDetailView must be called with either an object pk or a slug in the URLconf.
you can use isbn as slug
book/urls.py
urlpatterns = [
path('',BookListView.as_view(), name="book_list"),
path('<slug:isbn>/',BookDetailView.as_view(), name="book_detail")
]
book/views.py
class BookDetailView(DetailView):
model = BookModel
template_name = "book/detail.html"
slug_field = 'isbn'
slug_url_kwarg = 'isbn'

Getting a TypeError at / 'function' object is not iterable

I keep getting this error ('function' object is not iterable) after having added a new def function in my .views file, any thoughts on what the problem could be?
The goal with this is to filter querysets with checkboxes.
Here's my views.py function:
def FilterView(request):
qs = Product.objects.all()
ptag = request.GET.get('ptag')
if ptag == 'on':
qs = qs.filter(ptag='')
qs = filter(request)
context = {
'queryset': qs
}
return render(request, "partials/search_form.html", context)
And in my urls:
from search.views import HomeView, FilterView
urlpatterns = [
url(r'^$', HomeView.as_view(), FilterView),
]
Thanks so much!
Your code doesn't make sense. You are passing both your HomeView and your FilterView to a single url(), and you are running the builtin filter function on a request object? Here should be a working example, minus the unexplained filter():
urls.py
from search.views import HomeView, FilterView
urlpatterns = [
...
url(r'^$', FilterView, name='filter'),
...
]
views.py
def FilterView(request):
ptag = request.GET.get('ptag', '')
qs = Product.objects.all() if ptag != 'on' else Product.objects.filter(ptag='')
#qs = filter(request) # What is this even trying to do?
context = {
'queryset': qs
}
return render(request, "partials/search_form.html", context)
You are passing in both homeview and filterview. You need to choose one.
in urls.py
change
url(r'^$', HomeView.as_view(), FilterView)
to
url(r'^$', Filterview)

Django: create an admin section gathering info from multiple models

I've been asked to add in the admin site of a Django project a new section that will gather information from several models (as it were a Database view) but I'm not allowed to change or add tables/views in the db.
Checking similar questions custom page for Django admin in SO, I've ended up trying to create a "fake" model that won't be managed by Django and adding custom urls in get_urls method.
Let code explain itself:
core/admin.py
class ConfigurationOverview(Model):
aa = ForeignKey(ModelA, on_delete=DO_NOTHING)
bb = ForeignKey(ModelB, on_delete=DO_NOTHING)
cc = ForeignKey(ModelC, on_delete=DO_NOTHING)
class Meta:
# Django won't consider this model
managed = False
# link to the index page at /admin
verbose_name = 'Configuration overview'
app_label = 'core'
#staticmethod
def all():
# gather info from ModelA, ModelB, ModelC and create a collection of ConfigurationOverviews
return []
#register(ConfigurationOverview)
class ConfigurationOverviewAdmin(ModelAdmin):
def get_urls(self):
urls = super(ConfigurationOverviewAdmin, self).get_urls()
my_urls = [
url(
r'^$', # /admin/core/configurationoverview/
self.admin_site.admin_view(self.list_view),
name='core_configurationoverview_list'
)
]
return my_urls + urls
def list_view(self, request):
context = {
'configuration_overviews': ConfigurationOverview.all(),
}
return render(request,
"admin/core/configurationoverview/change_list.html",
context)
templates/admin/core/configurationoverview/change_list.html
{% extends "admin/change_list.html" %}
{% block content %}
AAAA
{% endblock %}
But when accesing /admin/core/configurationoverview/ I'm getting
NoReverseMatch at /admin/core/configurationoverview/
Reverse for 'app_list' with keyword arguments '{'app_label': ''}' not found. 1
but I've defined app_label: core! any hint?
* EDIT *
This is the empty migration I ran:
class Migration(migrations.Migration):
dependencies = [...]
operations = [
migrations.CreateModel(
name='ConfigurationOverview',
fields=[],
options={
'managed': False,
'verbose_name': 'Configuration overview'
},
),
]
You can try to add a regular view and require the user to be a staff member.
views.py
from django.contrib.admin.views.decorators import staff_member_required
#staff_member_required
def configuration_overview(request):
aa = ModelA.objects.all() # customize this queryset if neccesary, paginate ...
bb = ModelB.objects.all() # customize this queryset if neccesary, paginate ...
cc = ModelC.objects.all() # customize this queryset if neccesary, paginate ...
return render(request, 'admin/core/configurationoverview/change_list.html', context={'aa': aa, 'bb': bb, 'cc': cc})
urls.py
urlpatterns = [
###
path('admin/configuration', views.configuration_overview) # customize the path you want
###
]

How to reverse_lazy to a view/url with variable?

I've got a DeleteView I use for removing objects from a model. It is launched via a button in a table. It works fine.
class DeleteAssignment(DeleteView):
model = Assignment
success_url = reverse_lazy('company')
I just want to have it return to it's parent view on success. I currently have it redirecting to the parent's parent (company), as this view doesn't require a variable. This would be simple, but the parent view requires a variable farm_id to render, this is captured from the url like "/farm/18"
url(r'^farm/(?P<farm_id>.+)', views.farm, name='farm'),
I've solved this with forms on the page by having them redirect to the view farm with the variable farm_id.
return redirect(farm, farm_id=farm_id)
How could I do this with the success_url for my DeleteView?
Example for nickie:
views.py
#login_required
def farm(request, farm_id=None):
user = request.user
company_id = user.profile.company_id
farm_id = farm_id
farm_filter = Farm.objects.filter(farm=farm_id)
farm_current = farm_filter[0]
# farm_company =
serial_filter = Sensor.objects.filter(assignment__farm__company_id__isnull=True)
assignment_filter = Assignment.objects.filter(farm=farm_id)
farm_instance = Farm.objects.get(farm=farm_filter[0].farm)
update_farm_form = UpdateFarmForm(instance=farm_instance)
assign_sensor_form = AssignmentForm()
if request.method == 'POST' and 'updatefarm' in request.POST:
update_farm_form = UpdateFarmForm(request.POST, instance=farm_instance)
if update_farm_form.is_valid():
update_farm_form.save()
return redirect(farm, farm_id=farm_id)
else:
if request.method == "POST" and 'assignsensor' in request.POST:
assign_sensor_form = AssignmentForm(request.POST)
if assign_sensor_form.is_valid():
assignment = assign_sensor_form.save()
if user.is_staff is True:
assignment.company_id = farm_filter[0].company_id
else:
assignment.company_id = user.profile.company_id
assignment.save()
return redirect(farm, farm_id=farm_id)
else:
assign_sensor_form = AssignmentForm(request.POST)
return render(request, 'users/farm_template.html', {'company_id': company_id, 'farm_filter': farm_filter, 'farm_current': farm_current, 'serial_filter': serial_filter, 'assignment_filter': assignment_filter, 'update_farm_form': update_farm_form, 'assign_sensor_form': assign_sensor_form})
urls.py
from django.conf.urls import url, include
from django.contrib.auth import views as auth_views
from apps.dashboard import views
from apps.dashboard.views import DeleteAssignment, DeleteFarm
urlpatterns = [
url(r'^company/', views.company_view, name='company'),
# url(r'^test/', views.test),
# url(r'^test2/', views.test2, name='test2'),
# url(r'^farms/', views.add_farms),
url(r'^manual-signup/', views.signup_manual),
url(r'^signup/(?P<company_id>.+)', views.signup_company),
url(r'^settings/', views.update_profile),
url(r'^create-company/', views.create_company),
url(r'^create-sensor/', views.create_sensor),
url(r'^assign-sensor/', views.assign_sensor),
url(r'^login/$', auth_views.login, {'template_name': 'login.html'}, name='login'),
url(r'^logout/$', auth_views.logout, {'next_page': '/login'}, name='logout'),
url(r'^$', views.main),
# url(r'^company/(?P<company_id>.+)/farm/(?P<farm_id>.+)', views.farm),
url(r'^farm/(?P<farm_id>.+)', views.farm, name='farm'),
url(r'^unit/(?P<sensor_id>.+)', views.unit),
# url(r'^company/(?P<company_id>.+)', views.company),
url(r'^download/', views.download),
# url(r'^export/xls/$', views.export_users_xls),
url(r'^live/', views.live),
url(r'^data/', views.data),
url(r'^debug/', views.debug),
url(r'^delete-assignment/(?P<pk>\d+)/$', DeleteAssignment.as_view(), name='delete-assignment', ),
url(r'^delete-farm/(?P<pk>\d+)/$', DeleteFarm.as_view(), name='delete-farm', ),
url(r'^', include('django.contrib.auth.urls'))
]
This is view redirects to itself upon successful form submission. This reloads tables based on the user submission without having to deal with js for now.
The farm_id in return redirect(farm, farm_id=farm_id) is captured from the url, via the appropriate line in urls.py url(r'^farm/(?P<farm_id>.+)', views.farm, name='farm'),
This is all I want to do with the delete view, instead of the success url simply being a view, a view with a variable like I did above.
Yes, you can do this with success_url in this way:
class DeleteAssignment(DeleteView):
. . . . .
. . . . .
. . . . .
def get_success_url(self):
# if you are passing 'pk' from 'urls' to 'DeleteView' for company
# capture that 'pk' as companyid and pass it to 'reverse_lazy()' function
companyid=self.kwargs['pk']
return reverse_lazy('company', kwargs={'pk': companyid})
This should work perfectly.
As Nickie suggested in the comments: https://docs.djangoproject.com/en/1.11/ref/class-based-views/mixins-editing/#django.views.generic.edit.DeletionMixin.success_url
Solved this with success_url = "/farm/{farm_id}"
The following works:
reverse_lazy('name_of_your_view', kwargs={'key': value})
Not documented either in the man page or in docstring, was suggested by AI.

Django - No Reverse Match at /

I'm trying to get the absolute url for particular items in my model.
models.py
class BannerAds(models.Model):
name = models.CharField(max_length=256)
phone = models.CharField(max_length=20)
def __unicode__(self):
return self.name
#permalink
def get_absolute_url(self):
from django.core.urlresolvers import reverse
return reverse('index', args=[str(self.name)])
views.py
def banners(request):
context = RequestContext(request)
all_banners = BannerAds.objects.all()
content_dict = {'banners': all_banners,}
return render_to_response('templates/banner.html', content_dict, context)
def index(request):
context = RequestContext(request)
banner_list = BannerAds.objects.all()
city_list = Cities.objects.order_by('name')
offer_list = NewOffers.objects.order_by('offer_add_date')[:5]
context_dic = {'banner_list': banner_list,
'cities': city_list,
'offers': offer_list,
}
return render_to_response('templates/index.html', context_dic, context)
urls.py
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^$', views.index, name='index'),
url(r'^advertise/', views.advertise, name='advertise'),
url(r'^about/', views.about, name='about'),
url(r'^listing/', views.listing, name='listing'),
url(r'^search/', views.search, name='search'),
url(r'^add/', views.add_listing, name='add'),
url(r'^offers/', views.offers, name='offer'),
url(r'^add_listing/$', views.add_listing, name='add_listing'),
url(r'^listing/(?P<listing_url>\w+)/$', views.listing, name='category'),
url(r'^testimonial/', views.testimonials, name='testimonial'),
url(r'^add_testimonial', views.add_testimonial, name='add_testimonial'),
url(r'^banner', views.banners, name='banners'),
)
I've entered test data as name=test, phone = testing.
When I try to open the page, it gives me a No Reverse Match at / error along with a
Reverse for '' with arguments '('Testing',)' and keyword arguments '{}' not found. 0 pattern(s) tried: []
Any idea what I'm missing? I'm pretty new to Django development so solutions with code examples would help me a lot.
Change the view banners to as you are passing args.
def banners(request, name):
context = RequestContext(request)
all_banners = BannerAds.objects.all()
content_dict = {'banners': all_banners,}
return render_to_response('templates/banner.html', content_dict, context)
Also, make sure you have made an entry in urls.py with name="banners"
Don't use both #permalink and reverse(). They do the same thing. Either drop the decorator, or just return the tuple of (view_name, args).
In fact, the documentation says that permalink is deprecated, so the best thing is just to remove it.
The url url(r'^$', views.index, name='index') does not accept any parameter so why are you passing args here reverse('index', args=[str(self.name)])?
If you want a detail view and wants the name to be optional parameter for index then you can do:
url(r'^(?:(?P<name>.+?)/)?$', views.index, name='index')
Also change the index view to this:
def index(request, name=None):
context = RequestContext(request)
banner_list = BannerAds.objects.all()
# now if name parameter is not None you may want to just pick single object
banner_obj = None
if name:
banner_obj = BannerAds.objects.get(name__exact=name)
city_list = Cities.objects.order_by('name')
offer_list = NewOffers.objects.order_by('offer_add_date')[:5]
context_dic = {'banner_list': banner_list,
'cities': city_list,
'offers': offer_list,
'banner_obj': banner_obj,
}
return render_to_response('templates/index.html', context_dic, context)
Or have a separate view which will serve for the detail of BannerAds.

Categories