Properly storing values passed in URL in Django - django

I have the following URL:
http://localhost:8000/store/add/?points=5
I want to extract the number of points from my URL.
In my views.py, I have:
points = request.GET.get('points',0)
The problem is that it never finds points, so it uses the default of 0.
Any insight into what I'm doing wrong?
My urls.py
from django.conf.urls.defaults import *
from store.models import Part, Category, UniPart, LibraryRequest
from django.views.generic.list_detail import object_list
from voting.views import vote_on_object
urlpatterns=patterns('',
#/store/
url(r'^$','store.views.all_models',name="all_models"),
#/integer/view_part
url(r'^(\d+)/view_part/$','store.views.view_part',name="view_part"),
url(r'^your_models/$','store.views.your_models',name="your_models"),#/your_model
url(r'^user_models/(?P<username>\w+)/$','store.views.user_models',name="user_models"),
url(r'^add/(?P<points>\d+)/','store.views.add_model'),
Snipped from views.py:
def add_model(request, points=None):
print points

Well, your urls.py says that you should use following url /store/add/5, and in your views.py you need to have view
def add_model(request, points=None):
print points
If you want points as a GET parameter change your urls.py as following:
url(r'^add$','store.views.add_model', name='add_model'),
And then you can pass points as /store/add?points=5 and extract it from the URL as
points = request.GET.get('points')
UPDATE
Also in a future to avoid such problems I suggest you to add name parameter to your routes in urls.py (see above) and use reverse in your views (ex. reverse('add_model', kwargs={'points': 5}) and url in your templates (ex. {% url 'add_model' 5 %})
In that case all urls in your application will be generated automatically based on routes in your urls.py files.

Use the following code:
points = request.GET.get('points')
If you are passing more than one variable it can be done in two ways:
METHOD 1:
In your urls.py.
(r'^store/add1/?integer=(?P<category>\d+)/?string=(?P<keyword>\w+)$', 'view_function_name'),
You can get the above values in your views using the following:
def function_name(request):
int_value = request.GET.get('integer')
str_value = reuest.GET.get('string')
And you can also use the pattern given below:
METHOD 2:
In your urls.py.
urlpatterns = patterns('model_name.views',
(r'^store/add1/(?P<integer>\d+)/(?P<string>\w+)/', 'function_name')
)
In your views.py:
def function_name(request, integer= None, string = None):
print integer
print string
#Do whatever you wish with this value
The second method will be more easy for you.

Related

How to perform a query by using URL with question mark in Django?

It seems like the original URL querying function has been removed from Django 3.1. Does anyone know how to do it with a new package?
The url.py:
urlpatterns = [
re_path(r'^portfolio/(?P<title>[\w-]+)/$' , BlogApp_View.displayPortfolio, name='displayPortfolio'),
path('portfolio/', BlogApp_View.selectPortfolio, name='selectPortfolio'),]
The view.py
def displayPortfolio(request):
title = request.GET.get('title')
portfolio = Article.objects.filter(articleType__name__contains = "Portfolio", title=title)
print(title)
DICT = {}
return render(request, 'Article/', DICT)
The problem is now if I visit http://127.0.0.1:8000/Blog/portfolio/?title=A_UAV_Positioning_Approach_Using_LoRa/, it will skip the re_path shows in url.py.
Instead, it goes to the path one.
I have tried str:title method but that is actually not what I want. I prefer using the question mark pattern to finish the query.
The part after the questionmark is the querystring [wiki] and is not part of the path. This thus means that regardless what patterns you write, you can not distinguish on this, since the path patterns, regardless whether it is a path or re_path, are never matched against a URL with a query string.
You thus should write a single view, and inspect the request.GET query dict (which is a dictionary-like representation of the query string and see if it contains a value for title.
Your urlpatterns thus look like:
urlpatterns = [
path('portfolio/', BlogApp_View.selectPortfolio, name='selectPortfolio'),
]
and in the view, you can see if it contains a title:
def selectPortfolio(request):
if 'title' in request.GET:
# contains a ?title=…
title = request.GET.get('title')
portfolio = Article.objects.filter(
articleType__name__contains='Portfolio',
title=title
)
data = {'portfolio': portfolio}
return render(request, 'some_template.html', data)
else:
# contains no ?title=…
# …
return …

Wagtail: Add method to PageModel to get an inspect url

I am trying to add a dynamic instead of a hard coded get_inspect_url method to a PageModel:
class MyModel(Page):
# ...
# this is what I have now, which breaks in prod due to a different admin url
def get_inspect_url(self):
inspect_url = f"/admin/myapp/mymodel/inspect/{self.id}/"
return inspect_url
I know that you can use the ModelAdmin.url_helper_class in wagtail_hooks.py to get admin urls for an object, but I can't figure a way to do the same on the model level as a class method. Is there a way?
thanks to #Andrey Maslov tip I found a way:
from django.urls import reverse
def get_inspect_url(self):
return reverse(
f"{self._meta.app_label}_{self._meta.model_name}_modeladmin_inspect",
args=[self.id],
)
The basic form of a Wagtail admin url is:
[app_label]_[model_name]_modeladmin_[action]
Just change the [action] to one of the following to generated other instance level admin urls:
edit
delete
if you have in you urls.py line like this
path(MyModel/view/<id:int>/', YourViewName, name='mymodel-info'),
then you can add to your models.py this lines
from django.urls import reverse
...
class MyModel(Page):
def get_inspect_url(self):
inspect_url = reverse('mymodel-info', kwargs={'id': self.id})
return inspect_url

how to get a list of all views in a django application?

Is there any way to get a list of all views in an django app? I have googled for answer. All answers shows a way to get list of urls.
Getting list of all the views of a Django project:
To get all the views present in a Django project, we create a function get_all_view_names() which takes urlpatterns as input and returns the complete list of views being used in the project as the output.
First, we import the root_urlconf module using settings.ROOT_URLCONF. Then root_urlconf.urls.urlpatterns will give us the list of project's urlpatterns.
The above urlpatterns list contains RegexURLPattern and RegexURLResolver objects. Accessing .urlpatterns on a RegexURLResolver will further give us a list of RegexURLPattern and RegexURLResolver objects.
A RegexURLPattern object will give us the view name which we are interested in. The callback attribute on it contains the callable view. When we pass either a string in our urls like 'foo_app.views.view_name' representing the path to a module and a view function name, or a callable view, then callback attribute is set to this. Further accessing .func_name will give us the view name.
We call the function get_all_view_names() recursively and add the view names obtained from a RegexURLPattern object to a global list VIEW_NAMES.
from django.conf import settings
from django.core.urlresolvers import RegexURLResolver, RegexURLPattern
root_urlconf = __import__(settings.ROOT_URLCONF) # import root_urlconf module
all_urlpatterns = root_urlconf.urls.urlpatterns # project's urlpatterns
VIEW_NAMES = [] # maintain a global list
def get_all_view_names(urlpatterns):
global VIEW_NAMES
for pattern in urlpatterns:
if isinstance(pattern, RegexURLResolver):
get_all_view_names(pattern.url_patterns) # call this function recursively
elif isinstance(pattern, RegexURLPattern):
view_name = pattern.callback.func_name # get the view name
VIEW_NAMES.append(view_name) # add the view to the global list
return VIEW_NAMES
get_all_view_names(all_urlpatterns)
Getting list of all the views in a Django application:
To get the list of all the views present in a Django application, we will use the get_all_view_names() function defined above.
We will first import all the urlpatterns of the application and pass this list to the get_all_view_names() function.
from my_app.urls import urlpatterns as my_app_urlpatterns # import urlpatterns of the app
my_app_views = get_all_view_names(my_app_urlpatterns) # call the function with app's urlpatterns as the argument
my_app_views gives us the list of all the views present in my_app Django app.
Adding on to above fix by Rahul, if anyone is using Python3, you will need to use __name__ instead of func_name:
...
view_name = pattern.callback.__name__
...
otherwise you will get the following:
AttributeError: 'function' object has no attribute 'get_all_view_names'
(Thanks to scipy-gitbot at https://github.com/scipy/scipy/issues/2101#issuecomment-17027406
As an alternative, if you are disinclined to using global variables, here is what I ended up using :
all_urlpatterns = __import__(settings.ROOT_URLCONF).urls.urlpatterns
detail_views_list = []
def get_all_view_names(urlpatterns):
for pattern in urlpatterns:
if isinstance(pattern, RegexURLResolver):
get_all_view_names(pattern.url_patterns)
elif isinstance(pattern, RegexURLPattern):
detail_views_list.append(pattern.callback.__name__)
get_all_view_names(all_urlpatterns)
all_views_list = []
# remove redundant entries and specific ones we don't care about
for each in detail_views_list:
if each not in "serve add_view change_view changelist_view history_view delete_view RedirectView":
if each not in all_views_list:
all_views_list.append(each)
Then you can just iterate through all_views_list to get the list of filtered views.
update: Mar 1 2018
In Django 2.0, django.core.urlresolvers is moved to django.urls. RegexURLPattern and RegexURLResolver are renamed to URLPattern and URLResolver. So you should use
from django.urls import URLResolver, URLPattern
instead of
from django.core.urlresolvers import RegexURLResolver, RegexURLPattern
if you are using Django 2.
Get all Django and DRF views w/o using global vars
def get_all_views(urlpatterns, views=None):
views = views or {}
for pattern in urlpatterns:
if hasattr(pattern, 'url_patterns'):
get_all_views(pattern.url_patterns, views=views)
else:
if hasattr(pattern.callback, 'cls'):
view = pattern.callback.cls
elif hasattr(pattern.callback, 'view_class'):
view = pattern.callback.view_class
else:
view = pattern.callback
views[pattern.name] = view
return views

Django: Get relative uri from views.py

Here is what I have currently:
urls.py:
...
url(r'this/is/relative', 'myapp.views.callview', name='myapp_callview'),
...
views.py:
def callview(request, **kwargs):
# I can get the complete url by doing this
print request.build.absolute_uri() # Prints: https://domain:8080/myapp/this/is/relative
# How do I just get: /myapp/this/is/relative or even /this/is/relative
I would like to extract the relative uri from the view. I could just use regex, but I think there is already something out there that would let me do this.
This will give you "/myapp/this/is/relative":
from django.core import urlresolvers
relative_uri = urlresolvers.reverse("myapp_callview")
Link to Django docs page: https://docs.djangoproject.com/en/dev/ref/urlresolvers/

How do I change the view a URL resolves to after a certain date?

I'm writing a contest app. The contest closes at midnight on a particular date. I want to have the app automatically switch from: using a CookieWizardView, from formtools; to a normal TemplateView, from the generic view library.
Currently the relevant part of my urlpatterns looks like this:
urlpatterns += patterns('',
url(r'^$', 'appname.views.contest'), # the CookieWizardView
)
and I'd like it, after a certain date, to act as though it looks like this:
urlpatterns += patterns('',
url(r'^$', 'appname.views.contestclosed'), # a TemplateView
)
I am totally, totally fine with having a hard-coded magic number, I just don't want to be up at midnight that day!
~~
I solved this but can't answer my own question because I'm too new.
I made a function in my views.py:
def contest_switcher(request):
if datetime.datetime.now() < datetime.datetime(YEAR_OVER, MONTH_OVER, DAY_OVER):
return contest(request)
else:
return contestclosed(request)
This does the trick, now my urlpattern is:
urlpatterns += patterns('',
url(r'^$', 'appname.views.contest_switcher'),
)
I did have to add a function to my contest closed view, though, because it wasn't expecting a POST, which could happen if someone is trying to fill out the contest form at midnight:
class ContestClosedView(TemplateView):
template_name = "appname/closed.html"
def post(self, *args, **kwargs):
return self.get(*args, **kwargs)
contestclosed = ContestClosedView.as_view()
You don't have to try to hack your urls.py to pull this off. Set one URL pattern that points to a view that looks like this:
def contest_page(request, contest_id):
try:
contest = Contest.objects.get(pk=contest_id)
except Contest.DoesNotExist:
raise Http404 # minimum necessary - you can do better
if datetime.datetime.now() < contest.end_date: # model field rather than module constants
return contest(request, contest_id) # CookieWizardView
else:
return contestclosed(request, contest_id) # TemplateView
This is basically your contest_switcher with improvements:
Applies to multiple contests
Contests know their own end date so you don't clutter your module scope with constants
Simple urls.py and the view does the work of delegating what is shown (you know, the view)
(Note that this example implies that you would change your models correspondingly and import all the correct libraries and such.)