Display icons in Django admin for each item - python

I want to add a specified icon for each model on admin index page. I added an attribute named "picture" on each model then I modified /contrib/admin/sites.py to pass that picture name to template and checked and use it on index.html template of admin to get the result.
I wonder to know if there is a better way
class Product(models.Model):
abbr = models.CharField(max_length=20,unique=True)
title = models.CharField(max_length=200,unique=True)
owner = models.ForeignKey(UserProxy)
des = models.TextField(blank=True,null=True)
picture = 'product.png'
def __unicode__(self):
return self.abbr
class Meta:
none

What You did seems OK, only small tips that can make Your code a little better:
Instead of modifying django/contrib/admin/sites.py You can subclass the AdminSite class (if You didn't do that already).
Modify the AdminSite.index() method to pass not picture, but whole admin class (there is a model_admin variable available in the index() method).
Assign picture in the ModelAdmin classes, not models, to separate admin stuff from models.

The answer from 'Python Fanboy' was so brief but useful to me, I could avoid modifying django base classes
picture field were moved to admin class
I subclass AdminSite as CustomAdminSite and copied index and app_index and made modification
(I don't know if there is a better way than copying whole of index and app_index like overriding)
In urls.py, 'admin.sites.url' replaced by 'custom_site.url'
(custom_site is instance of CustomAdminSite)
I did not want another url instead of '/admin' like '/my_admin' so I have to use instance of CustomAdminSite for all my models even User, Group & Site
I'm using admin_tools, now I've lose my application menu
Any better Idea or solution for my new encountered problems?

Related

Using Django ModelForm with non-persistent model.Field

Is there a way to add a field to a Django model class such that:
It doesn't get persisted to the database (i.e. no column in the DB)
It does get rendered by a ModelForm
The widget for that field can be customised
I believe 3. can be done with a custom widget, and 2. will happen if the field inherits from models.Field. However, I haven't found a way to achieve 1. without breaking 2. and 3. I was hoping for a persist=False or db_column=None type of solution.
Scenario:
I'm using this to quickly produce data capture forms by only adding a class to the model, but in order to insert headers for sub sections I still having to edit the template. Was hoping to do the following:
models.py
from django.db import models
class Applicant(models.Model):
sectionA = models.SectionField(help_text="Personal details")
title = models.CharField(max_length=100)
name = models.CharField(max_length=100)
sectionB = models.SectionField(help_text="Banking details")
account = models.CharField(max_length=100)
pin = models.CharField(max_length=100)
In the above example, sectionA and sectionB are instances of a custom model.Field that doesn't actually get persisted but cause a heading to be rendered by the ModelForm and a custom widget
Finally:
I realise this probably violates separation of View and Model.
Other questions have been asked about non-persisting fields but their solutions don't render in a ModelForm
Sort of, Just don't make them a model field, theres no need for them to be.
sectionA = "Personal details"
sectionB = "Banking details"
You can access them via form.instance where you need them, you could even make them a form field instead of a string as I've shown here.

Django Grappelli_Nested Inlines cannot create new nested lines after initial load

I am looking for a way to create a new nested row, before saving the "owner"-row.
By way of django ticket 9025 I found Grappelli-Nested-Inlines which I have been using.
I have a test project set up based on the instructions found at that link:
from django.contrib import admin
from grappelli_nested.admin import NestedModelAdmin, NestedStackedInline, NestedTabularInline
from .models import *
class MyNestedInline(NestedTabularInline):
model = C
extra = 0
class MyInline(NestedStackedInline):
model = B
extra = 0
inlines = [MyNestedInline,]
class MyAdmin(NestedModelAdmin):
inlines = [MyInline,]
admin.site.register(A, MyAdmin)
My issue is based in the fact that I cannot create a child object before saving the parent. That is to say, the "add another c"-button has no functionality before saving B
Is there a way to achieve this?
I have read through all the posts regarding this that I could find, but I have to say that if the answer is included anywhere, then I didnĀ“t understand it, so please be patient with me.
I should also note, that because of the production code, grappelli is a requirement, so anything that clashes with that will not work.
What i did was to take the templates that django-grappelli-inline provides and use them for use as a template in django-nested-inlines.
class NestedStackedInline(NestedInline):
template = 'admin/edit_inline/stacked.html'
class NestedTabularInline(NestedInline):
template = 'admin/edit_inline/tabular.html'
Where the templates are the ones from django-grappelli-inline

Using a FormSet in a ClassBasedView in django

I'm trying to set up a django form consisting solely of a formset. In forms.py I have:
class StudentEnrolmentForm(forms.ModelForm):
school_class = forms.ModelChoiceField(SchoolClass.objects.currently_enrolling())
class Meta:
model = StudentApplication
fields = []
StudentEnrolmentFormSet = modelformset_factory(StudentApplication, StudentEnrolmentForm, extra=0)
but I'm unclear how to incorporate the FormSet into a CBV (In this case I've chosen a FormView). In this case I'm basically displaying a table of students, and allowing the operator to assign each student to a class. I only want a single 'submit' button at the end of the page.
If you will take a look on sources of Django views and check how FormView is working, you find that it just overrides default get and post methods of base View class and adds some additional methods for the form handling.
So you can:
try to assign your formset to the form_class field of your view and
play around. Probably you will have to override some additional
methods;
take a look on https://github.com/AndrewIngram/django-extra-views;
if options #1 and #2 causes too much pain - use default View

Django Admin: when displaying an object, display a URL that contains one of the fields

Here is an abstract base class for many of my "Treatment" models (TreatmentA, TreatmentB, etc):
class TreatmentBase(models.Model):
URL_PREFIX = '' # child classes define this string
code = shared.models.common.RandomCharField(length=6)
class Meta:
abstract = True
Each Treatment instance has a URL, that when visited by a user, takes them to a page specific to that treatment. I want to be able to create a Treatment in Django Admin, and immediately get this URL so I can send it to users. This URL can be created with the following method on TreatmentBase:
def get_url(self):
return '{}/{}/'.format(self.URL_PREFIX, self.code)
However, I am stuck with how to get this URL to display in Django Admin. I can think of the following solutions:
(1) Customize the display of the code field so that it becomes a clickable URL. Problem: I don't know how to do this.
(2) Add the get_url method to ModelAdmin.list_display. Problem: This means I would have to define a separate list_display for each of the child models of BaseTreatment, and I would have to explicitly list all the fields of the model, meaning I have to update it every time I modify a model, violating DRY.
(3) Add an extra field like this:
url = models.URLField(default = get_url)
Problem: get_url is an instance method (since it needs to refer to the self.code field), and from my reading of the docs about the default argument, it just has to be a simple callable without arguments.
Any way to do this seemingly simple task?
You could go with option 2 (adding to the admin display) but add it to the
readonly_fields which may alleviate your DRY concerns when models changes.
Option 3 (the extra field) could also work if you override the save method setting the URL property. You'd either want to set the field as readonly in the admin or only set the value in the save method if it's currently None.

Overriding class member variables in Python (Django/Satchmo)

I'm using Satchmo and Django and am trying to extend Satchmo's Product model. I'd like to make one of the fields in Satchmo's Product model have a default value in the admin without changing Satchmo's source code. Here is an abbreviated version of Satchmo's Product model:
class Product(models.Model):
site = models.ForeignKey(Site, verbose_name='Site')
This is what I attempted to do to extend it...
class MyProduct(Product):
Product.site = models.ForeignKey(Site, verbose_name='Site', editable=False, default=1)
This does not work, any ideas on why?
For two reasons, firstly the way you are trying to override a class variable just isn't how it works in Python. You just define it in the class as normal, the same way that def __init__(self): is overriding the super-class initializer. But, Django model inheritance simply doesn't support this. If you want to add constraints, you could do so in the save() method.
You could probably monkeypatch it if you really wanted to:
site_field = Product._meta.get_field('site')
site_field.editable = False
site_field.default = 1
But this is a nasty habit and could cause problems; arguably less maintainable than just patching Satchmo's source directly.
You can't change the superclass from a subclass.
You have the source. Use subversion. Make the change. When Satchmo is updated merge the updates around your change.

Categories

Resources