django: access url name pattern in cbv - django

I would like to map several urls to the same view.
url(r'^foo/', BaseView.as_view(), name='foo'),
url(r'^bar/', BaseView.as_view(), name='bar'),
url(r'^buzz/', BaseView.as_view(), name='buzz'),
Is there anyway in my class based view I can access the name parameters? I know it's possible to specify it in as_view(). But is there a way around that extra boilerplate code?

What about:
url(r'^/(?P<name>[-\w]+)/$', BaseView.as_view())
Then you can just grab the name from BaseView:
name = self.kwargs['name']

Related

how to create params in django url?

I have a django project where url is like this
url(r'^invoice/(?P<invoice_id>[A-Za-z0-9]+)/(?P<order_id>[A-Za-z0-9]+)$',GenerateInvoicePdf,name='invoice'),
which generates url localhost:8000/invoice/2341wq23fewfe1231/3242
but i want url to be like localhost:8000/invoice?invoice_id=2341wq23fewfe1231&order_id=3242
i tried documentation and used syntax like this re_path(r'^comments/(?:page-(?P<page_number>\d+)/)?$', comments), But did not get desired result.
how can i do so?
The parts which you are trying to write after ? is called url query string. You don't need to define them in the urls.py. You can just use:
re_path(r'^comments/$', comments),
And inside comments views, you can access the query string like this:
def comments(request):
invoice_id = request.GET.get('invoice_id')
order_id = request.GET.get('order_id')
# rest of the code

Django context processors and URL arguments

I have some code that is repeated at the start of my Django views. It basically just adds some variables to the context, but based on the URL argument, e.g.
def someView(request, id):
target = Target.objects.get(id=id)
# name will be added to ctx
name = target.name
(there are more attributes added and other attributes from related models, but this gives the general idea --- There are quite a few lines of repeat code at the start of each view)
I thought I could make my code more DRY by taking advantage of Django's context processors, but it would seem these don't access to the URL arguments?
Is there another way to avoid these repeat lines? Maybe middleware or something else?
You can access the URL parameters via request through the resolver_match attribute. So for instance you can do request.resolver_match.kwargs['id'] to get the ID kwarg.

Filter all queries based on url parameters

I have in a Django project all my urls based on the following syntax:
/ID_PROGRAM/ID_PROJECT/blablabla
I would like by default that all my queries have the following filters:
.filter(program=ID_PROGRAM).filter(project=ID_PROJECT)
How can I apply these filters automatically to all my queries? My idea was to define a new manager. But is the manager able to access to the url parameters? I this the best way to do?
To complet the question, I want to enrich all my queries without having to pass explicitly the view parameters to the manager.
You could have just tried it to see if it works.
Yes, managers do accept parameters
class MyModelManager(models.Manager):
def my_filters(self, id_prog, id_proj):
return super(MyModelManager, self).get_query_set().filter(program=id_prog, project=id_proj)
and in the views:
MyModelManager.objects.my_filters(id_prog, id_proj)
Documentation on custom managers
Python promotes "Explicit is better than implicit"
karthikr is almost right, but you can also use:
1 - decorator above your function. Decorator will get args from url and put objects to any variable
2 - write mixin and aply it to view. Mixin will get args from url at overriden dispatch and save filter result to self.custom_context. Override get_context_data to merge contexts.

Django: Passing data to view from url dispatcher without including the data in the url?

I've got my mind set on dynamically creating URLs in Django, based on names stored in database objects. All of these pages should be handled by the same view, but I would like the database object to be passed to the view as a parameter when it is called. Is that possible?
Here is the code I currently have:
places = models.Place.objects.all()
for place in places:
name = place.name.lower()
urlpatterns += patterns('',
url(r'^'+name +'/$', 'misc.views.home', name='places.'+name)
)
Is it possible to pass extra information to the view, without adding more parameters to the URL? Since the URLs are for the root directory, and I still need 404 pages to show on other values, I can't just use a string parameter. Is the solution to give up on trying to add the URLs to root, or is there another solution?
I suppose I could do a lookup on the name itself, since all URLs have to be unique anyway. Is that the only other option?
I think you can pass a dictionary to the view with additional attributes, like this:
url(r'^'+name +'/$', 'misc.views.home', {'place' : place}, name='places.'+name)
And you can change the view to expect this parameter.
That's generally a bad idea since it will query the database for every request, not only requests relevant to that model. A better idea is to come up with the general url composition and use the same view for all of them. You can then retrieve the relevant place inside the view, which will only hit the database when you reach that specific view.
For example:
urlpatterns += patterns('',
url(r'^places/(?P<name>\w+)/$', 'misc.views.home', name='places.view_place')
)
# views.py
def home(request, name):
place = models.Place.objects.get(name__iexact=name)
# Do more stuff here
I realize this is not what you truly asked for, but should provide you with much less headaches.

How can I get access to a Django Model field verbose name dynamically?

I'd like to have access to one my model field verbose_name.
I can get it by the field indice like this
model._meta._fields()[2].verbose_name
but I need to get it dynamically. Ideally it would be something like this
model._meta._fields()['location_x'].verbose_name
I've looked at a few things but I just can't find it.
For Django < 1.10:
model._meta.get_field_by_name('location_x')[0].verbose_name
model._meta.get_field('location_x').verbose_name
For Django 1.11 and 2.0:
MyModel._meta.get_field('my_field_name').verbose_name
More info in the Django doc
The selected answer gives a proxy object which might look as below.
<django.utils.functional.__proxy__ object at 0x{SomeMemoryLocation}>
If anyone is seeing the same, you can find the string for the verbose name in the title() member function of the proxy object.
model._meta.get_field_by_name(header)[0].verbose_name.title()
A better way to write this would be:
model._meta.get_field(header).verbose_name.title()
where header will be the name of the field you are interested in. i.e., 'location-x' in OPs context.
NOTE: Developers of Django also feel that using get_field is better and thus have depreciated get_field_by_name in Django 1.10. Thus I would suggest using get_field no matter what version of Django you use.
model._meta.get_field_by_name('location_x')[0].verbose_name
You can also use:
Model.location_x.field.verbose_name
Model being the class name. I tested this on my Animal model:
Animal.sale_price.field.verbose_name
Animal.sale_price returns a DeferredAttribute, which has several meta data, like the verbose_name
Note: I'm using Django 3.1.5
If you want to iterate on all the fields you need to get the field:
for f in BotUser._meta.get_fields():
if hasattr(f, 'verbose_name'):
print(f.verbose_name)
# select fields for bulk_update : exclude primary key and relational
fieldsfields_to_update = []
for field_to_update in Model._meta.get_fields():
if not field_to_update.many_to_many and not field_to_update.many_to_one and not field_to_update.one_to_many and not field_to_update.one_to_one and not field_to_update.primary_key and not field_to_update.is_relation :
fields_to_update = fields_to_update + [field_to_update.name]
Model.objects.bulk_update(models_to_update , fields_to_update)