I am trying to redo my app views with a Class Based Views(CBV) and stumbled across this function get_absolute_url() being defined in the models.py, generic editing views
I have created models and have never used this function before. Is this specific to CBVs?
It's not specific to CBV, you can use it anywhere in your application. It makes it much easier to get the url for a model instance without having to mess around with url resolving. Also it is much easier to get the definitive url for your object in a template when you can call get_absolute_url on the object itself. For example, if you are looping through a list of objects:
{% for post in blog_posts %}
read post
{% endfor %}
That said, there's nothing stopping you using the method in your view either:
post = BlogPost.objects.get(...)
url = post.get_absolute_url()
There's also is nothing at all special about the method though. You can write your own get_foo_url() if you like instead. For example, I wrote a blog post about a get_admin_url, a method to allow you to get the Django admin url to an object:
class Book(models.Model):
...
def get_admin_url(self):
content_type = ContentType \
.objects \
.get_for_model(self.__class__)
return reverse("admin:%s_%s_change" % (
content_type.app_label,
content_type.model),
args=(self.id,))
# {{ book.get_admin_url }}
Related
Using Django I want to implement some middleware that will calculate some context that is to be used by the view itself.
For example, I have a middleware that looks at the request, and adds the user's permissions to the request, or some user configuration. The view looks at these permissions and decides how to handle the request using it.
This saves the need for multiple views (and multiple parts within the view) to query for this information.
I'm wondering what is the correct way to do that. One option is to just add request.user_permissions=... directly on the request. But is there some documented and expected way to do that?
There's no real documented way to do that, but Middleware is the correct place to do it and just adding properties to the request object is also the correct way.
You can confirm this, because Django is already doing it:
LocaleMiddelware
AuthenticationMiddleware
RemoteUserMiddleware
CurrentSiteMiddleware
SessionMiddleware
So just pick whatever is the most convenient data structure for your use case and tack that on to the request object.
This is not a perfect answer but at my experience I use this code. Every permission is saved in a boolean value which is true or false. You can access it in a html template like.
{% if request.user.is_admin %}
"Your code here"
{% else %}
"Your code here"
{% endif %}
and to send extra context you should create and pass an dicionary and pass it as as an argument to the render method from the view.
For eg:
def view(request, slug):
context = {'administrator':True}
blog_post = get_object_or_404(BlogPost, slug=slug)
context['blog_post'] = blog_post
return render(request, 'blog/detail_blog.html', context)
and access it like
{% if context.administrator %}
"Your code here"
{% else %}
"Your code here"
{% endif %}
I believe, since your middleware will calculate context, it should be implemented as context processor.
https://docs.djangoproject.com/en/3.1/ref/templates/api/#using-requestcontext
https://docs.djangoproject.com/en/3.1/ref/templates/api/#writing-your-own-context-processors
Need to access URL by name at model, can't just hardcode it. Need it for error message for a new object creating. Any suggestions?
Update: Just need to put url to error message, not reverse
Your question is not totally clear, but I think you are asking about the reverse function.
You can define get_absolute_url method in your model and than access it in other model's methods. Check https://docs.djangoproject.com/en/2.1/ref/models/instances/#get-absolute-url
I suggest you use a template tag. You can build one for your model and avoid polluting the model about stuff not related to the domain level and keep the presentation level to the template.
Check the docs here on how add a templatetags your app.: https://docs.djangoproject.com/en/2.1/howto/custom-template-tags/
Here a snippet of code to use as starting point for your url generation
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def url_for_object(context, object):
# you have both the context and the object available to
# generate your url here
url = ....
return url
In your template use
{% url_for_object my_object %}
Is there anyway I can take advantage of Django's default CBV's without resulting to super calls on the get_context_data to send extra pieces of info.
For instance, I have a site where the CBV's handle 99% of the work on their own, but I'd like to send minor bits of static info such as page titles and it seems unnecessary to use get_context_data just to accomplish this.
I'm aware that I can do the following:
class Page(DetailView):
model: MyModel
template_name: 'something.html'
title: 'Some Page Title'
And reference title in my template as view.title. However I'd like the page title to be an attribute of my model. Which I'm able to do through the following:
get_context_data(self, **kwargs):
context = super(Page, self).get_context_data(**kwargs)
context['title'] = 'Page Title | %s' % (self.get_object().title)
return context
Is it possible for me to reference the individual model being called in the detail view without running a query or using get_context_data so I can get the model's title attribute and use access it as view.title in my template?
I can't see any reason to define this method just to get the title. The whole point of a DetailView is that you have access to the object in the template, via {{ object }}. So why not just do {{ object.title }}?
I would like to understand what is the benefit to use the get_absolute_url call instead of the url template tag.
get_absolute_url:
class Project(models.Model):
#permalink
def get_absolute_url(self):
return ('view_project', (), {'project_id': self.pk})
{{ project.name }}
url template tag:
{{ project.name }}
Thank you for your help,
Julio
The only clear advantage is that you can change the name of the url for that model without having to rewrite all your templates. Also, if you define a get_absolute_url function (you don't have to use it in your templates, though), that provides some additional benefits like adding a View on site button in Django's admin or providing a fallback success url for class-based modelform views.
However, get_absolute_url and in general urls for models is an ongoing point of discussion.
I find it easier to manage all my url in template if there are "located" only into one place, ie in the model. So everytime I need an url related to an object I use get_absolute_url.
But since Django 1.5 #permalink is deprecated, you must use reverse() instead. Please check documentation
i'm looking for a way to extend a django template/view.
my first implementation consists of two models (clients/models.py):
class Client(models.Model):
...
class Address(models.Model):
client = models.ForeignKey(Client)
...
and its fairly simple template (clients/detail.html) :
{{client.name}}
Address: {{client.address.street}}, {{client.address.zipcode}} {{client.address.city}}
as my application grows, a new app was born: 'invoices'.
it is again very simple (invoices/models.py):
class Invoice(models.Model):
client = models.ForeignKey(clients.models.Client)
...
now my clients details-view needs to display invoices, so i create and override clients/detail.html in my 'invoices' app.
good for now.
later on i created a third app 'quotes'.
again my clients details-view needs to display quotes.
if i create clients/detail.html in my 'clients' i will loose the ability to display invoices.
because the 'invoices' and 'quotes' app are indipendent.
my first idea was to create something like a SubView-class
which 'invoices' and 'quotes' can extend and then register their implementation somewhere.
a template should look like this:
{{client.name}}
Address: {{client.address.street}}, {{client.address.zipcode}} {{client.address.city}}
{% for view in views %}
<h1>{{view.title}}</h1>
{{view.get_html}}
{% endfor %}
is this a good way to go and should i use a admin.site-like implementation for registering my sub-views?
In Django one url in urls.py should ideally use one view, just to keep things simple.
I would therefore adopt the approach of putting all the required context in your one view for this screen (I think you already have this via foreign keys in your model). Then, rather than doing what you call "SubView-class" I would go for the Django template include tag.
Example:
{% for invoice in client.invoices %}
{% include "invoice-detail.html" with invoice=invoice %}
{% endfor %}
This renders each invoice's detail for all the invoices of the client. Notice how this is in line with the DRY principle.