Modify Django admin app index - python

I want to change the app index page so I add help text to the models themselves, e.g. under each model I want to add help text. I know that I should override AdminSite.app_index. What is the best way to do this?

I can create a new AdminSite subclass, and override app_index method to send the help text to the template. In urls.py I can use an instance of MyAdminSite instead of django's vanilla AdminSite.
# urls.py
from mysite.admin import MyAdminSite
site = MyAdminSite()
urlpatterns = patterns('',
(r'^admin/', include(site.urls)),
)
# app/admin.py
site.register(MyModel)

Related

Django: adding simple button to admin generic view

Django newbie here working on a pre-existing app I've inherited. I need to add a cancel/back button to the show (DetailView in Django terms, I think?) page. I know how to do this with anchor tags in HTML. However, I can't figure out where the HTML template is for this view! I believe it's being procedurally generated as a "generic view" or "admin" from this code in urls.py:
from django.conf.urls import url
from . import views
app_name = 'reports'
urlpatterns = [
# ex: /reports/
url(r'^$', views.IndexView.as_view(), name='index'),
# ex: /reports/5/
url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
# ex: /reports/5/results/
url(r'^(?P<pk>[0-9]+)/results$', views.ResultsView.as_view(), name='results'),
# ex: /reports/5/vote/
url(r'^(?P<question_id>[0-9]+)/vote$', views.vote, name='vote'),
]
The bottom bar of the reports show / DetailView page contains the following values when accessed via browser:
I'd like to add a "Cancel" button to this bar, but I can't find where I could add such a button -- I can't even find these existing buttons in the codebase.
An admin/reports_admin.py exists with some configuration that may be relevant, but I don't see an obvious place in that file where I could add this "Cancel" button.
Please help!
I think this is what you want
Overriding admin templates | Django docs
as well you can override admin views, which is also described here, to add additinal functionality.

Serializing with django rest framework

I have the model named Artist and I want expose this model with Django Rest Framework to create an API and this data can be consumed.
I've created a class based view in artists/views.py named ArtistViewSet
#CBV for rest frameworks
from rest_framework import viewsets
class ArtistViewSet(viewsets.ModelViewSet):
model = Artist
I also have an url named api/ in the urls.py file (view third url named api/) which the user could access to the view above mentioned.
# coding=utf-8
from django.conf.urls import patterns, include, url
from django.conf import settings
from django.contrib import admin
admin.autodiscover()
from rest_framework import routers
from artists.views import ArtistViewSet
#I create a router by default
router = routers.DefaultRouter()
#Register the model 'artists' in ArtistViewSet
router.register(r'artists', ArtistViewSet)
urlpatterns = patterns('',
(r'^grappelli/', include('grappelli.urls')), # grappelli URLS
url(r'^admin/', include(admin.site.urls)),
#Include url api/ with all urls of router
url(r'^api/', include(routers.urls)),
)
When I go to my browser and type http://localhost:8000/api/ I get this message error:
What did can be happened me?
In Django REST framework 2.4+ (including 3.0+), the model attribute for views has been deprecated and removed. This means that you should be defining your view as
from rest_framework import viewsets
class ArtistViewSet(viewsets.ModelViewSet):
queryset = Artist.objects.all()
Which should give you the result you are expecting. Now, you asked in the comments
I cannot understand the role of base_name. I mean, this base name is the url that I've created? My viewset ArtistViewSet does not have a queryset attribute, due to this, according to documentation, it's necessary put the base_name argument, but i don't know how to do it.
The base_name that can be optionally defined when registering a ViewSet is used when naming the automatically generated routes. By default, the format is [base]-list and [base]-detail, where [base] is the base_name that can be defined. When you do not specify your own base_name, it is automatically generated based on the model name. As the queryset method must be defined for ViewSet instances, this is where the model (and later model name) is retrieved. As you did not provide the queryset argument, Django REST framework triggers an error because it cannot generate a base_name.
To quote from the documentation on routers
Note: The base_name argument is used to specify the initial part of the view name pattern.
The documentation goes on to further explain exactly why you are getting the issue, even including an example, and how to fix it.

Modifying and creating sites in djangos admin app

I have to include multiple changes to djangos admin panel, so I decided to fork the django admin app into my own django project.
As I was working with this admin app I recognized, that the site registration and template handling differs from the apps, that are normally created in django.
For instance, I want to keep the old admin index.html template and view, for backup and safety reasons but the landing page should be replaced by a custom page.
For that of course I need to change admin/templates/index.html and /admin/sites.py respectively.
I copied the old index function in admin/sites.py to old_index.py and created a old_index.html in the template folder.
But if I try to reference to old_index.html in my new index.html with
old index
I got an NoReverseMatch-Exception thrown. Unfortunately I did not found more information about how the django admin app itself register new views and sites, so an example or description would be helpful.
Creating separate views for the admin app in the distinct other apps in my project is no real option, due the high amount of changes, that need to be done.
The main urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'django_project.views.home', name='home'),
url(r'^polls/', include('other_app.urls', namespace="other_app")),
url(r'^admin/', include(admin.site.urls)),
)
The admin app itself does not provide a urls.py file and the views.py is exactely the same as in django.contrib.admin I just copied the function index to a new function called old_index, referencing to a template old_index.html.
Maybe the point did not get so clear, as I expected. I copied the whole admin app in my project and want to add a custom defined site to it, regardless where. But I failed to understand how sites and views are registered in the admin app itself, because the way is different from the custom apps you create normally in django.
So, is it possible (and how) to add a custom site in the django.contrib.admin app?
I think you need to create your own AdminSite for custom purposes and keep default as it is. More about this you can find here: https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#adminsite-objects and here https://docs.djangoproject.com/en/dev/ref/contrib/admin/#multiple-admin-sites-in-the-same-urlconf
Update:
You need to edit get_urls method of AdminSite class - add:
url(r'^$', wrap(self.old_index), name='old_index')
to urlpatterns variable. And rename old index method to old_index.

Django, name parameter in urlpatterns

I'm following a tutorial where my urlpatterns are:
urlpatterns = patterns('',
url(r'^passwords/$', PasswordListView.as_view(), name='passwords_api_root'),
url(r'^passwords/(?P<id>[0-9]+)$', PasswordInstanceView.as_view(), name='passwords_api_instance'),
...other urls here...,
)
The PasswordListView and PasswordInstanceView are supposed to be class based views.
I could not figure out the meaning of the name parameter. Is it a default parameter passed to the view?
No. It is just that django gives you the option to name your views in case you need to refer to them from your code, or your templates. This is useful and good practice because you avoid hardcoding urls on your code or inside your templates. Even if you change the actual url, you don't have to change anything else, since you will refer to them by name.
e.x with views:
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse #this is deprecated in django 2.0+
from django.urls import reverse #use this for django 2.0+
def myview(request):
passwords_url = reverse('passwords_api_root') # this returns the string `/passwords/`
return HttpResponseRedirect(passwords_url)
More here.
e.x. in templates
<p>Please go here</p>
More here.

Customized views with django-registration

I need to make a very simple modification -- require that certain views only show up when a user is not authenticated -- to django-registration default views. For example, if I am logged in, I don't want users to be able to visit the /register page again.
So, I think the idea here is that I want to subclass the register view from django-registration. This is just where I'm not sure how to proceed. Is this the right direction? Should I test the user's authentication status here? Tips and advice welcomed!
Edit
I think this is the right track here: Django: Redirect logged in users from login page
Edit 2
Solution:
Create another app, for example, custom_registration, and write a view like this (mine uses a custom form as well):
from registration.views import register
from custom_registration.forms import EduRegistrationForm
def register_test(request, success_url=None,
form_class=EduRegistrationForm, profile_callback=None,
template_name='registration/registration_form.html',
extra_context=None):
if request.user.is_authenticated():
return HttpResponseRedirect('/')
else:
return register(request, success_url, form_class, profile_callback, template_name, extra_context)
I had to use the same function parameters, but otherwise just include the test, and if we pass it, continue to the main function.
Don't forget to put this in your URLConf either (again, this includes some stuff about my custom form as well):
top-level URLConf
(r'^accounts/', include('custom_registration.urls')),
(r'^accounts/', include('registration.urls')),
custom_registration.views
from django.conf.urls.defaults import *
from custom_registration.views import register_test
from custom_registration.forms import EduRegistrationForm
urlpatterns = patterns('',
url(r'^register/$', register_test, {'form_class': EduRegistrationForm}, name='registration.views.register'),
)
As far as I remember django-registration is using function-based views, so you can not really subclass them. The approach I usually follow is "overwriting" the original views (without modifying the django-registration app of course). This works like this:
Create another app (you could call it custom_registration or whatever you want)
This app need to contain another urls.py and in your case another views.py
Copy the original register view code to your new views.py and modify it, add a pattern to your urls.py to point to this view (use the same url pattern as in django-registration for this view)
Put an include to your projects urls.py of your new app urls.py before your are including the original django-registration app. This could look like this for example:
urlpatterns = patterns('',
...
url(r'^accounts/', include('custom_registration.urls')),
url(r'^accounts/', include('registration.backends.default.urls')),
...
)
This simply works since the first matching url pattern for /accounts/register will point to your new app, so it will never try to call the one from the original app.

Categories

Resources